Add support for PSKc TLV and Security Policy TLV (#558)

* Add support for PSKc TLV and Security Policy TLV
diff --git a/include/openthread-types.h b/include/openthread-types.h
index ca0e257..b3f507a 100644
--- a/include/openthread-types.h
+++ b/include/openthread-types.h
@@ -175,6 +175,40 @@
     uint8_t m8[OT_MESH_LOCAL_PREFIX_SIZE];
 } otMeshLocalPrefix;
 
+#define OT_PSKC_MAX_SIZE           16  ///< Maximum size of the PSKc (bytes)
+
+/**
+  * This structure represents PSKc.
+  *
+  */
+typedef struct otPSKc
+{
+    uint8_t m8[OT_PSKC_MAX_SIZE];
+} otPSKc;
+
+/**
+  * This structure represent Security Policy.
+  *
+  */
+typedef struct otSecurityPolicy
+{
+    uint16_t mRotationTime;
+    uint8_t mFlags;
+} otSecurityPolicy;
+
+/**
+ * This enumeration represents flags that indicate security related behaviours within OpenThread.
+ *
+ */
+enum
+{
+    OT_SECURITY_POLICY_OBTAIN_MASTER_KEY      = 1 << 7,  ///< Obtaining the Master Key
+    OT_SECURITY_POLICY_NATIVE_COMMISSIONING   = 1 << 6,  ///< Native Commissioning
+    OT_SECURITY_POLICY_ROUTERS                = 1 << 5,  ///< Routers enabled
+    OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER  = 1 << 4,  ///< External Commissioner allowed
+    OT_SECURITY_POLICY_BEACONS                = 1 << 3,  ///< Beacons enabled
+};
+
 /**
  * This type represents the IEEE 802.15.4 PAN ID.
  *
@@ -309,6 +343,8 @@
     uint32_t          mDelay;                      ///< Delay Timer
     otPanId           mPanId;                      ///< PAN ID
     uint16_t          mChannel;                    ///< Channel
+    otPSKc            mPSKc;                       ///< PSKc
+    otSecurityPolicy  mSecurityPolicy;             ///< Security Policy
 
     bool              mIsActiveTimestampSet : 1;   ///< TRUE if Active Timestamp is set, FALSE otherwise.
     bool              mIsPendingTimestampSet : 1;  ///< TRUE if Pending Timestamp is set, FALSE otherwise.
@@ -319,6 +355,8 @@
     bool              mIsDelaySet : 1;             ///< TRUE if Delay Timer is set, FALSE otherwise.
     bool              mIsPanIdSet : 1;             ///< TRUE if PAN ID is set, FALSE otherwise.
     bool              mIsChannelSet : 1;           ///< TRUE if Channel is set, FALSE otherwise.
+    bool              mIsPSKcSet : 1;              ///< TRUE if PSKc is set, FALSE otherwise.
+    bool              mIsSecurityPolicySet : 1;    ///< TRUE if Security Policy is set, FALSE otherwise.
 } otOperationalDataset;
 
 /**
diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp
index 8b7df4f..ba51fbf 100644
--- a/src/cli/cli_dataset.cpp
+++ b/src/cli/cli_dataset.cpp
@@ -62,6 +62,8 @@
     { "panid", &ProcessPanId },
     { "pending", &ProcessPending },
     { "pendingtimestamp", &ProcessPendingTimestamp },
+    { "pskc", &ProcessPSKc },
+    { "securitypolicy", &ProcessSecurityPolicy },
 };
 
 Server *Dataset::sServer;
@@ -132,6 +134,45 @@
         sServer->OutputFormat("PAN ID: 0x%04x\r\n", aDataset.mPanId);
     }
 
+    if (aDataset.mIsPSKcSet)
+    {
+        sServer->OutputFormat("PSKc: ");
+        OutputBytes(aDataset.mPSKc.m8, sizeof(aDataset.mPSKc.m8));
+        sServer->OutputFormat("\r\n");
+    }
+
+    if (aDataset.mIsSecurityPolicySet)
+    {
+        sServer->OutputFormat("Security Policy: %d, ", aDataset.mSecurityPolicy.mRotationTime);
+
+        if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_OBTAIN_MASTER_KEY)
+        {
+            sServer->OutputFormat("o");
+        }
+
+        if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_NATIVE_COMMISSIONING)
+        {
+            sServer->OutputFormat("n");
+        }
+
+        if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_ROUTERS)
+        {
+            sServer->OutputFormat("r");
+        }
+
+        if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER)
+        {
+            sServer->OutputFormat("c");
+        }
+
+        if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_BEACONS)
+        {
+            sServer->OutputFormat("b");
+        }
+
+        sServer->OutputFormat("\r\n");
+    }
+
     return kThreadError_None;
 }
 
@@ -553,5 +594,72 @@
     return error;
 }
 
+ThreadError Dataset::ProcessPSKc(int argc, char *argv[])
+{
+    ThreadError error = kThreadError_None;
+    uint16_t length;
+
+    VerifyOrExit(argc > 0, error = kThreadError_Parse);
+
+    length = static_cast<uint16_t>((strlen(argv[0]) + 1) / 2);
+    VerifyOrExit(length <= OT_PSKC_MAX_SIZE, error = kThreadError_NoBufs);
+    VerifyOrExit(Interpreter::Hex2Bin(argv[0], sDataset.mPSKc.m8 + OT_PSKC_MAX_SIZE - length, length)
+                 == length, error = kThreadError_Parse);
+
+    sDataset.mIsPSKcSet = true;
+
+exit:
+    return error;
+}
+
+ThreadError Dataset::ProcessSecurityPolicy(int argc, char *argv[])
+{
+    ThreadError error = kThreadError_None;
+    long value;
+
+    VerifyOrExit(argc > 0, error = kThreadError_Parse);
+
+    SuccessOrExit(error = Interpreter::ParseLong(argv[0], value));
+    sDataset.mSecurityPolicy.mRotationTime = static_cast<uint16_t>(value);
+    sDataset.mSecurityPolicy.mFlags = 0;
+
+    if (argc > 1)
+    {
+        for (char *arg = argv[1]; *arg != '\0'; arg++)
+        {
+            switch (*arg)
+            {
+            case 'o':
+                sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_OBTAIN_MASTER_KEY;
+                break;
+
+            case 'n':
+                sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_NATIVE_COMMISSIONING;
+                break;
+
+            case 'r':
+                sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_ROUTERS;
+                break;
+
+            case 'c':
+                sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER;
+                break;
+
+            case 'b':
+                sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_BEACONS;
+                break;
+
+            default:
+                ExitNow(error = kThreadError_Parse);
+            }
+        }
+    }
+
+    sDataset.mIsSecurityPolicySet = true;
+
+exit:
+    return error;
+}
+
 }  // namespace Cli
 }  // namespace Thread
diff --git a/src/cli/cli_dataset.hpp b/src/cli/cli_dataset.hpp
index 1c35188..b8ae957 100644
--- a/src/cli/cli_dataset.hpp
+++ b/src/cli/cli_dataset.hpp
@@ -88,6 +88,8 @@
     static ThreadError ProcessPendingTimestamp(int argc, char *argv[]);
     static ThreadError ProcessMgmtSetCommand(int argc, char *argv[]);
     static ThreadError ProcessMgmtGetCommand(int argc, char *argv[]);
+    static ThreadError ProcessPSKc(int argc, char *argv[]);
+    static ThreadError ProcessSecurityPolicy(int argc, char *argv[]);
 
     static const DatasetCommand sCommands[];
     static otOperationalDataset sDataset;
diff --git a/src/core/thread/meshcop_dataset.cpp b/src/core/thread/meshcop_dataset.cpp
index 077b75d..4f39418 100644
--- a/src/core/thread/meshcop_dataset.cpp
+++ b/src/core/thread/meshcop_dataset.cpp
@@ -177,6 +177,23 @@
             break;
         }
 
+        case Tlv::kPSKc:
+        {
+            const PSKcTlv *tlv = static_cast<const PSKcTlv *>(cur);
+            memcpy(aDataset.mPSKc.m8, tlv->GetPSKc(), tlv->GetLength());
+            aDataset.mIsPSKcSet = true;
+            break;
+        }
+
+        case Tlv::kSecurityPolicy:
+        {
+            const SecurityPolicyTlv *tlv = static_cast<const SecurityPolicyTlv *>(cur);
+            aDataset.mSecurityPolicy.mRotationTime = tlv->GetRotationTime();
+            aDataset.mSecurityPolicy.mFlags = tlv->GetFlags();
+            aDataset.mIsSecurityPolicySet = true;
+            break;
+        }
+
         default:
         {
             break;
@@ -270,6 +287,23 @@
         Set(tlv);
     }
 
+    if (aDataset.mIsPSKcSet)
+    {
+        MeshCoP::PSKcTlv tlv;
+        tlv.Init();
+        tlv.SetPSKc(aDataset.mPSKc.m8);
+        Set(tlv);
+    }
+
+    if (aDataset.mIsSecurityPolicySet)
+    {
+        MeshCoP::SecurityPolicyTlv tlv;
+        tlv.Init();
+        tlv.SetRotationTime(aDataset.mSecurityPolicy.mRotationTime);
+        tlv.SetFlags(aDataset.mSecurityPolicy.mFlags);
+        Set(tlv);
+    }
+
 exit:
     return error;
 }
diff --git a/src/core/thread/meshcop_tlvs.hpp b/src/core/thread/meshcop_tlvs.hpp
index dcfb421..8cabd27 100644
--- a/src/core/thread/meshcop_tlvs.hpp
+++ b/src/core/thread/meshcop_tlvs.hpp
@@ -774,11 +774,11 @@
 
     enum
     {
-        kObtainMasterKeyFlag      = 1 << 7,  ///< Obtaining the Master Key
-        kNativeCommissioningFlag  = 1 << 6,  ///< Native Commissioning
-        kRoutersFlag              = 1 << 5,  ///< Routers enabled
-        kExternalCommissionerFlag = 1 << 4,  ///< External Commissioner allowed
-        kBeaconsFlag              = 1 << 3,  ///< Beacons enabled
+        kObtainMasterKeyFlag      = OT_SECURITY_POLICY_OBTAIN_MASTER_KEY,      ///< Obtaining the Master Key
+        kNativeCommissioningFlag  = OT_SECURITY_POLICY_NATIVE_COMMISSIONING,   ///< Native Commissioning
+        kRoutersFlag              = OT_SECURITY_POLICY_ROUTERS,                ///< Routers enabled
+        kExternalCommissionerFlag = OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER,  ///< External Commissioner allowed
+        kBeaconsFlag              = OT_SECURITY_POLICY_BEACONS,                ///< Beacons enabled
     };
 
     /**