[IOT-2617] Enable Anon Ciphersuite after RESET
[platform/upstream/iotivity.git] / resource / csdk / security / src / deviceonboardingstate.c
1 //******************************************************************
2 //
3 // Copyright 2017 Intel OpenSource Technology Center All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "deviceonboardingstate.h"
22 #include "srmutility.h"
23 #include "octypes.h"
24 #include "logger.h"
25 #include "srmresourcestrings.h"
26 #include "aclresource.h"
27 #include "amaclresource.h"
28 #include "credresource.h"
29 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
30 #include "crlresource.h"
31 #endif /* (__WITH_DTLS__) || (__WITH_TLS__) */
32 #include "doxmresource.h"
33 #include "pstatresource.h"
34 #include "resourcemanager.h"
35
36 #define TAG "OIC_SRM_DOS"
37
38 /**
39  * @return true if changing from oldState to newState is valid transition.
40  */
41 static bool IsValidStateTransition(OicSecDeviceOnboardingState_t oldState,
42     OicSecDeviceOnboardingState_t newState)
43 {
44     bool ret = false;
45
46     switch (newState)
47     {
48         case DOS_RESET:
49         ret = true;
50         break;
51
52         case DOS_RFNOP:
53         if (DOS_RFPRO == oldState)
54         {
55             ret = true;
56         }
57         break;
58
59         case DOS_RFOTM:
60         if (DOS_RESET == oldState)
61         {
62             ret = true;
63         }
64         break;
65
66         case DOS_RFPRO:
67         if (DOS_RFNOP == oldState
68             || DOS_RFOTM == oldState
69             || DOS_SRESET == oldState)
70         {
71             ret = true;
72         }
73         break;
74
75         case DOS_SRESET:
76         if (DOS_RFNOP == oldState
77             || DOS_RFPRO == oldState)
78         {
79             ret = true;
80         }
81         break;
82     }
83
84     OIC_LOG_V(INFO, TAG, "%s: returning %s.", __func__, ret?"true":"false");
85     return ret;
86 }
87
88 /**
89  * @return true if Device meets requirements to enter RFNOP DOS.
90  */
91 static bool IsReadyToEnterRFNOP()
92 {
93     bool ret = false;
94     bool tempBool = false;
95     OicUuid_t tempUuid = {.id={0}};
96
97     // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
98
99     // Verify doxm.owned == TRUE.
100     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
101     VERIFY_TRUE_OR_EXIT(TAG, tempBool, WARNING);
102
103     // Verify doxm.devowneruuid != nil UUID.
104     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
105     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
106
107     // Verify doxm.deviceuuid != nil UUID.
108     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
109     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
110
111     // Verify oxmsel was the actual OTM used (no-op: CTT will verify this during
112     // certification testing, as it requires OBT cooperation to verify).
113
114     // Verify pstat.isop == false (Server sets isop on entry)
115     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatIsop(&tempBool), ERROR);
116     VERIFY_TRUE_OR_EXIT(TAG, !tempBool, WARNING);
117
118     // Verify implemented SVRs with rowneruuid Property have non-Nil rowneruuid
119     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetAclRownerId(&tempUuid), ERROR);
120     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
121
122     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCredRownerId(&tempUuid), ERROR);
123     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
124
125     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmRownerId(&tempUuid), ERROR);
126     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
127
128     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatRownerId(&tempUuid), ERROR);
129     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
130
131     // Verify each rowneruuid, devowneruuid has a corresponding /cred entry
132     // TODO [IOT-2023]
133
134     ret = true;
135
136 exit:
137     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
138     return ret;
139 }
140
141 /**
142  * @return true if Device meets requirements to enter RFOTM DOS.
143  */
144 static bool IsReadyToEnterRFOTM()
145 {
146     bool ret = false;
147     bool tempBool = false;
148     OicUuid_t tempUuid = {.id={0}};
149
150     // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
151
152     // Verify doxm.owned == FALSE.
153     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
154     VERIFY_TRUE_OR_EXIT(TAG, !tempBool, WARNING);
155
156     // Verify doxm.devowneruuid == nil UUID.
157     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
158     VERIFY_TRUE_OR_EXIT(TAG, IsNilUuid(&tempUuid), WARNING);
159
160     // Check and log whether doxm.deviceuuid == nil UUID ("may" reqt not "shall")
161     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
162     if (!IsNilUuid(&tempUuid))
163     {
164         OIC_LOG_V(INFO, TAG, "%s: doxm.deviceuuid != Nil UUID... allowed but noted.",
165             __func__);
166     }
167
168     ret = true;
169
170 exit:
171     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
172     return ret;
173 }
174
175 /**
176  * @return true if Device meets requirements to enter RFPRO DOS.
177  */
178 static bool IsReadyToEnterRFPRO()
179 {
180     bool ret = false;
181     bool tempBool = false;
182     OicUuid_t tempUuid = {.id={0}};
183
184     // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
185
186     // Verify doxm.owned == TRUE.
187     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
188     VERIFY_TRUE_OR_EXIT(TAG, tempBool, WARNING);
189
190     // Verify doxm.devowneruuid != nil UUID.
191     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
192     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
193
194     // Verify doxm.deviceuuid != nil UUID.
195     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
196     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
197
198     // doxm.sct and doxm.oxmsel retain previous values (checked by CTT)
199
200     // Verify implemented SVRs with rowneruuid Property have non-Nil rowneruuid
201     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetAclRownerId(&tempUuid), ERROR);
202     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
203
204     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCredRownerId(&tempUuid), ERROR);
205     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
206
207     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmRownerId(&tempUuid), ERROR);
208     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
209
210     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatRownerId(&tempUuid), ERROR);
211     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
212
213     // Verify each rowneruuid, devowneruuid has a corresponding /cred entry
214     // TODO [IOT-2023]
215
216     ret = true;
217
218 exit:
219     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
220     return ret;
221 }
222
223 /**
224  * @return true if Device meets requirements to set pstat.dos.s = SRESET.
225  */
226 static bool IsReadyToEnterSRESET()
227 {
228     bool ret = false;
229     bool tempBool = false;
230     OicUuid_t tempUuid = {.id={0}};
231
232     // Note: pstat.dos.p set by DoStateChange(), so not checked here.
233
234     // TODO [IOT-2023]: sanity check SVRs (optional)
235
236     // Verify doxm.owned == TRUE.
237     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
238     VERIFY_TRUE_OR_EXIT(TAG, tempBool, WARNING);
239
240     // Verify doxm.devowneruuid != nil UUID.
241     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
242     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
243
244     // Verify doxm.deviceuuid != nil UUID.
245     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
246     VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
247
248     // doxm.sct and doxm.oxmsel retain previous values (checked by CTT)
249
250     ret = true;
251
252 exit:
253     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
254     return ret;
255 }
256
257 /**
258  * Generic ops performed on entering most states, coalesced to avoid repeat code.
259  */
260 static bool EnterStateGeneric(bool isop,
261                               bool cmReset,
262                               bool cmTakeOwner,
263                               bool tmReset,
264                               bool tmTakeOwner,
265                               OicSecDeviceOnboardingState_t state)
266 {
267     bool ret = false;
268     OicSecDpm_t cm = 0;
269     OicSecDpm_t tm = 0;
270
271     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatCm(&cm), ERROR);
272     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatTm(&tm), ERROR);
273
274     // Set pstat.isop
275     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatIsop(isop), ERROR);
276
277     // Set pstat.cm
278     if (cmReset)
279     {
280         cm |= RESET; // set RESET bit
281     }
282     else
283     {
284         cm &= ~RESET; // clear RESET bit
285     }
286     if (cmTakeOwner)
287     {
288         cm |= TAKE_OWNER; // set TAKE_OWNER bit
289     }
290     else
291     {
292         cm &= ~TAKE_OWNER; // clear TAKE_OWNER bit
293     }
294     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatCm(cm), ERROR);
295
296     // Set pstat.tm
297     if (tmReset)
298     {
299         tm |= RESET; // set RESET bit
300     }
301     else
302     {
303         tm &= ~RESET; // clear RESET bit
304     }
305     if (tmTakeOwner)
306     {
307         tm |= TAKE_OWNER; // set TAKE_OWNER bit
308     }
309     else
310     {
311         tm &= ~TAKE_OWNER; // clear TAKE_OWNER bit
312     }
313     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatTm(tm), ERROR);
314
315     // Set pstat.dos.s
316     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosS(state), ERROR);
317
318     ret = true;
319
320 exit:
321     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
322     return ret;
323 }
324
325 /**
326  * Enter RFNOP state and set all Server-controlled SVR Property values.
327  */
328 static bool EnterRFNOP()
329 {
330     bool ret = false;
331
332     // Set pstat.isop = TRUE
333     // Unset pstat.cm RESET and TAKE_OWNER bits
334     // Unset pstat.tm RESET and TAKE_OWNER bits
335     // Set pstat.dos to RFNOP
336     ret = EnterStateGeneric(true, false, false, false, false, DOS_RFNOP);
337
338     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
339     return ret;
340 }
341
342 /**
343  * Enter RFOTM state and set all Server-controlled SVR Property values.
344  */
345 static bool EnterRFOTM()
346 {
347     bool ret = false;
348
349     // Set pstat.isop = FALSE
350     // Unset pstat.cm RESET bit, and set TAKE_OWNER bit
351     // Unset pstat.tm RESET and TAKE_OWNER bits
352     // Set pstat.dos to RFOTM
353     ret = EnterStateGeneric(false, false, true, false, false, DOS_RFOTM);
354
355     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
356     return ret;
357 }
358
359 /**
360  * Enter RFPRO state and set all Server-controlled SVR Property values.
361  */
362 static bool EnterRFPRO()
363 {
364     bool ret = false;
365
366     // Set pstat.isop = FALSE
367     // Unset pstat.cm RESET and TAKE_OWNER bits
368     // Unset pstat.tm RESET and TAKE_OWNER bits
369     // Set pstat.dos to RFPRO
370     ret = EnterStateGeneric(false, false, false, false, false, DOS_RFPRO);
371
372     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
373     return ret;
374 }
375
376 /**
377  * Enter RESET state and set all Server-controlled SVR Property values.
378  */
379 static bool EnterRESET()
380 {
381     bool ret = false;
382
383     // Restore Mfr Defaults
384     // "Mfr Defaults" is defined by manufacturer.  It could be "failsafe"
385     // SVRs (e.g. the hard-coded SVRs in IoTivity) or it could be a backup
386     // copy of the initally-provisioned SVRs (e.g. the ResetSecureResourceInPS
387     // function in IoTivity).
388     // TODO [IOT-2633]: VERIFY_SUCCESS(TAG, OC_STACK_OK == ResetSecureResources(), ERROR);
389
390     // Set doxm.deviceuuid = Mfr Default (handled above)
391     // Set doxm.sct = Mfr Default ("")
392     // Set doxm.oxmsel = Mfr Default ("")
393     // Set pstat.om = Mfr Default ("")
394     // Set pstat.sm = Mfr Default ("")
395     // Assert acl2, amacl, sacl, cred arrays = mfr defaults ("")
396
397     // Set doxm.owned = FALSE
398     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmIsOwned(false), ERROR);
399
400     // Set doxm.devowneruuid = Nil UUID
401     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmDevOwnerId(&THE_NIL_UUID), ERROR);
402
403     // Set acl, doxm, cred and pstat rowneruuids = Nil UUID
404     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetAclRownerId(&THE_NIL_UUID), ERROR);
405     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmRownerId(&THE_NIL_UUID), ERROR);
406     VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatRownerId(&THE_NIL_UUID), ERROR);
407
408     // Set pstat.isop = FALSE
409     // Set pstat.cm RESET and unset TAKE_OWNER
410     // Unset pstat.tm and set TAKE_OWNER
411     // Set pstat.dos.s to RESET
412     VERIFY_SUCCESS(TAG,
413         EnterStateGeneric(false, true, false, false, true, DOS_RESET),
414         ERROR);
415
416 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
417     // Enable Anon DH cipher suite if appropriate
418     bool isAnonEnabled = false;
419     VERIFY_SUCCESS(TAG,
420         OC_STACK_OK == EnableAnonCipherSuiteIfUnOwnedAndJustWorksSelected(&isAnonEnabled),
421         ERROR);
422     OIC_LOG_V(INFO, TAG, "%s: Anon Ciphersuite %sENABLED.", __func__,
423         isAnonEnabled ? "" : "NOT ");
424 #endif // __WITH_DTLS__ or __WITH_TLS__
425
426     ret = true;
427
428 exit:
429     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
430     return ret;
431 }
432
433 /**
434  * Enter SRESET state and set all Server-controlled SVR Property values.
435  */
436 static bool EnterSRESET()
437 {
438     bool ret = false;
439
440     // Set pstat.isop = FALSE
441     // Set pstat.cm RESET and unset TAKE_OWNER
442     // Unset pstat.tm and unset TAKE_OWNER
443     // Set pstat.dos.s to RESET
444     VERIFY_SUCCESS(TAG,
445         EnterStateGeneric(false, true, false, false, false, DOS_SRESET),
446         ERROR);
447
448     ret = true;
449
450 exit:
451     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
452     return ret;
453 }
454
455 /**
456  * Set pstat.dos.p (pending) to true, then verify device is ready to perform
457  * the state change.  If so, perform the state change.  Finally, set
458  * pstat.dos.p (pending) to false.
459  * @return  OC_STACK_OK if successful change to newState
460  *          OC_STACK_FORBIDDEN_REQ if state change preconditions not met
461  *          OC_STACK_INTERNAL_SERVER_ERROR if SVRs left in potentially unstable state
462  */
463 static OCStackResult DoStateChange(OicSecDeviceOnboardingState_t newState)
464 {
465     OCStackResult ret = OC_STACK_INTERNAL_SERVER_ERROR;
466
467     switch (newState)
468     {
469         case DOS_RESET:
470         // No preconditions other than setting dos.p = true, which is done above
471         if (EnterRESET())
472         {
473             // if RESET succeeds, immediately enter RFOTM
474             if (IsReadyToEnterRFOTM())
475             {
476                 if (EnterRFOTM())
477                 {
478                     ret = OC_STACK_OK;
479                 }
480                 else
481                 {
482                     ret = OC_STACK_INTERNAL_SERVER_ERROR;
483                 }
484             }
485             else
486             {
487                 ret = OC_STACK_FORBIDDEN_REQ;
488             }
489         }
490         else
491         {
492             ret = OC_STACK_INTERNAL_SERVER_ERROR;
493         }
494         break;
495
496         case DOS_RFNOP:
497         if (IsReadyToEnterRFNOP())
498         {
499             if (EnterRFNOP())
500             {
501                 ret = OC_STACK_OK;
502             }
503             else
504             {
505                 ret = OC_STACK_INTERNAL_SERVER_ERROR;
506             }
507         }
508         else
509         {
510             ret = OC_STACK_FORBIDDEN_REQ;
511         }
512         break;
513
514         case DOS_RFOTM:
515         if (IsReadyToEnterRFOTM())
516         {
517             if (EnterRFOTM())
518             {
519                 ret = OC_STACK_OK;
520             }
521             else
522             {
523                 ret = OC_STACK_INTERNAL_SERVER_ERROR;
524             }
525         }
526         else
527         {
528             ret = OC_STACK_FORBIDDEN_REQ;
529         }
530         break;
531
532         case DOS_RFPRO:
533         if (IsReadyToEnterRFPRO())
534         {
535             if (EnterRFPRO())
536             {
537                 ret = OC_STACK_OK;
538             }
539             else
540             {
541                 ret = OC_STACK_INTERNAL_SERVER_ERROR;
542             }
543         }
544         else
545         {
546             ret = OC_STACK_FORBIDDEN_REQ;
547         }
548         break;
549
550         case DOS_SRESET:
551         if (IsReadyToEnterSRESET())
552         {
553             if (EnterSRESET())
554             {
555                 ret = OC_STACK_OK;
556             }
557             else
558             {
559                 ret = OC_STACK_INTERNAL_SERVER_ERROR;
560             }
561         }
562         else
563         {
564             ret = OC_STACK_FORBIDDEN_REQ;
565         }
566         break;
567     }
568
569     OIC_LOG_V(DEBUG, TAG, "%s: returning %d.", __func__, ret);
570     return ret;
571 }
572
573 OCStackResult GetDos(OicSecDostype_t *dos)
574 {
575     if (dos)
576     {
577         VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosS(&(dos->state)), ERROR);
578         VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosP(&(dos->pending)), ERROR);
579         return OC_STACK_OK;
580     }
581 exit:
582     return OC_STACK_ERROR;
583 }
584
585 OCStackResult SetDosState(const OicSecDeviceOnboardingState_t desiredState)
586 {
587     OIC_LOG_V(INFO, TAG, "%s called for state %d.", __func__, desiredState);
588
589     OCStackResult ret = OC_STACK_ERROR;
590     bool pending = false;
591
592     VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosP(&pending), ERROR);
593
594     if (!pending)
595     {
596
597         VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosP(true), ERROR);
598
599         OicSecDeviceOnboardingState_t oldState = DOS_RESET;
600         VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosS(&oldState), ERROR);
601         if (IsValidStateTransition(oldState, desiredState))
602         {
603             OCStackResult stateChangeResult = DoStateChange(desiredState);
604             switch (stateChangeResult)
605             {
606                 case OC_STACK_OK:
607                 OIC_LOG_V(INFO, TAG, "%s: DOS state changed SUCCESSFULLY from %d to %d.",
608                     __func__, oldState, desiredState);
609                 ret = OC_STACK_OK;
610                 break;
611
612                 case OC_STACK_FORBIDDEN_REQ:
613                 OIC_LOG_V(WARNING, TAG, "%s: DOS state change change from %d to %d NOT ALLOWED.",
614                     __func__, oldState, desiredState);
615                 ret = OC_STACK_FORBIDDEN_REQ;
616                 break;
617
618                 case OC_STACK_INTERNAL_SERVER_ERROR:
619                 default:
620                 OIC_LOG_V(ERROR, TAG, "%s: DOS state change change from %d to %d FAILED."
621                     " Internal error - SVRs may be in bad state.",
622                     __func__, oldState, desiredState);
623                 ret = OC_STACK_INTERNAL_SERVER_ERROR;
624                 break;
625             }
626         }
627         else
628         {
629             OIC_LOG_V(INFO, TAG, "%s: Invalid transition; cannot go from %d to %d.", \
630                 __func__, oldState, desiredState);
631             ret = OC_STACK_FORBIDDEN_REQ;
632         }
633
634         VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosP(false), ERROR);
635
636     }
637     else
638     {
639         OIC_LOG_V(WARNING, TAG, "%s: cannot set pstat->dos.s, change \
640             already pending.", __func__);
641         ret = OC_STACK_FORBIDDEN_REQ;
642     }
643
644     // TODO [IOT-2023] if OC_STACK_OK, update all SVRs in Persistent Storage?
645
646     return ret;
647
648 exit:
649     return OC_STACK_INTERNAL_SERVER_ERROR;
650 }