OSDN Git Service

ee9bd568bf766df510fc40a4a971ce10183b3b0b
[openpts/openpts.git] / src / fsm.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/fsm.c
26  * \brief Finite State Machine
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-04-01
29  * cleanup 2011-01-21 SM
30  * refactoring 2011-07-20 SM
31  * 
32  * Input
33  *   FSM Model
34  *   IML
35  *   PROPERTY
36  * Output
37  *   SNAPSHOT
38  *   PROPERTY
39  *
40  */
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45
46 #include <libxml/encoding.h>
47 #include <libxml/xmlwriter.h>
48 #include <libxml/parser.h>
49
50 #include <openpts.h>
51
52 /**
53  * create new FSM context
54  */
55 OPENPTS_FSM_CONTEXT *newFsmContext() {
56     OPENPTS_FSM_CONTEXT *ctx = NULL;
57
58     /* malloc */
59     ctx = (OPENPTS_FSM_CONTEXT *) xmalloc(sizeof(OPENPTS_FSM_CONTEXT));
60     if (ctx == NULL) {
61         LOG(LOG_ERR, "no memory");
62         return NULL;
63     }
64     /* init */
65     memset(ctx, 0 , sizeof(OPENPTS_FSM_CONTEXT));
66     ctx->fsm_sub = NULL;
67     ctx->fsm_trans = NULL;
68     ctx->uml_file = NULL;
69     ctx->state = 0;
70     ctx->subvertex_num = 0;
71     ctx->transition_num = 0;
72     return ctx;
73 }
74
75 /**
76  * Free OPENPTS_FSM_Transition chain
77  */
78 void freeFsmTransitionChain(OPENPTS_FSM_Transition *fsm_trans) {
79     /* check */
80     if (fsm_trans == NULL) {
81         LOG(LOG_ERR, "null input");
82         return;
83     }
84
85     /* free */
86     if (fsm_trans->next != NULL) {
87         freeFsmTransitionChain(fsm_trans->next);
88     }
89
90     /* free */
91     if (fsm_trans->digest != NULL) {
92         xfree(fsm_trans->digest);
93     }
94
95     xfree(fsm_trans);
96 }
97
98 /**
99  * Free OPENPTS_FSM_Subvertex chain
100  */
101 void freeFsmSubvertexChain(OPENPTS_FSM_Subvertex *fsm_sub) {
102
103     /* check */
104     if (fsm_sub == NULL) {
105         LOG(LOG_ERR, "null input");
106         return;
107     }
108
109     /* chain */
110     if (fsm_sub->next != NULL) {
111         freeFsmSubvertexChain(fsm_sub->next);
112     }
113
114     /* free */
115     xfree(fsm_sub);
116 }
117
118 /**
119  * free FSM context
120  */
121 int freeFsmContext(OPENPTS_FSM_CONTEXT *ctx) {
122
123     /* check */
124     if (ctx == NULL) {
125         LOG(LOG_ERR, "null input");
126         return PTS_FATAL;
127     }
128
129     /* Transition */
130     if (ctx->fsm_trans != NULL) {
131         freeFsmTransitionChain(ctx->fsm_trans);
132         ctx->fsm_trans = NULL;
133     }
134
135     /* Subvertex */
136     if (ctx->fsm_sub != NULL) {
137         freeFsmSubvertexChain(ctx->fsm_sub);
138         ctx->fsm_sub = NULL;
139     }
140
141     /* UML filename */
142     if (ctx->uml_file != NULL) {
143         xfree(ctx->uml_file);
144         ctx->uml_file = NULL;
145     }
146
147     xfree(ctx);
148     return 0;
149 }
150
151
152 //// SUBVERTEX ////
153
154 /**
155  * reset FSM subvertex
156  */
157 void resetFsmSubvertex(OPENPTS_FSM_CONTEXT *ctx) {
158     /* check */
159     if (ctx == NULL) {
160         LOG(LOG_ERR, "null input");
161         return;
162     }
163
164     // fsm_sub=NULL;
165     ctx->subvertex_num = 0;
166 }
167
168 /**
169  * reset FSM transition
170  */
171 void resetFsmTransition(OPENPTS_FSM_CONTEXT *ctx) {
172     /* check */
173     if (ctx == NULL) {
174         LOG(LOG_ERR, "null input");
175         return;
176     }
177
178     // fsm_trans=NULL;
179     ctx->transition_num = 0;
180 }
181
182
183 /**
184  * add FMS subvertex to context
185  */ 
186 void addFsmSubvertex(
187         OPENPTS_FSM_CONTEXT *ctx,
188         char *type,
189         char *id,
190         char *name,
191         char *action) {
192     int i;
193     OPENPTS_FSM_Subvertex *ptr = NULL;
194     OPENPTS_FSM_Subvertex *ptr_pre = NULL;
195
196     DEBUG_CAL("addFsmSubvertex - %d \n", ctx->subvertex_num);
197
198     /* check */
199     if (ctx == NULL) {
200         LOG(LOG_ERR, "null input");
201         return;
202     }
203     if (type == NULL) {
204         LOG(LOG_ERR, "null input");
205         return;
206     }
207     if (id == NULL) {
208         LOG(LOG_ERR, "null input");
209         return;
210     }
211     if (name == NULL) {
212         LOG(LOG_ERR, "null input");
213         return;
214     }
215     if (action == NULL) {
216         LOG(LOG_ERR, "null input");
217         return;
218     }
219
220     /* add */
221     ptr = ctx->fsm_sub;
222     for (i = 0; i <= ctx->subvertex_num; i++) {
223         if (ptr == NULL) {
224             /* add new PENPTS_FSM_Subvertex */
225             DEBUG_FSM(" id=%s name=%s size=%d\n",
226                       id, name,
227                       (int)sizeof(OPENPTS_FSM_Subvertex));
228
229             /* malloc OPENPTS_FSM_Subvertex */
230             ptr = (OPENPTS_FSM_Subvertex *)
231                     xmalloc(sizeof(OPENPTS_FSM_Subvertex));
232             if (ptr == NULL) {
233                 return;
234             }
235
236             /* init */
237             memset(ptr, 0, sizeof(OPENPTS_FSM_Subvertex));
238             /* setup new FSM_Subvertex */
239             memcpy(ptr->type, type, FSM_BUF_SIZE);
240             memcpy(ptr->id, id, FSM_BUF_SIZE);
241             memcpy(ptr->name, name, FSM_BUF_SIZE);
242             memcpy(ptr->action, action, FSM_BUF_SIZE);
243
244             ptr->next = NULL;
245             ptr->num = ctx->subvertex_num;
246             ptr->incomming_num = 0;
247
248             if (ctx->subvertex_num == 0) {  // first event
249                 ctx->fsm_sub = ptr;
250                 ptr->prev = NULL;
251                 // NG must be Start event ctx->curr_state = ptr;
252             } else if (ptr_pre != NULL) {
253                 ptr_pre->next = ptr;  // else
254                 ptr->prev = ptr_pre;
255             } else {
256                 LOG(LOG_ERR, "BAD, free last one");
257                 xfree(ptr);  // free last one
258                 return;
259             }
260
261             ctx->subvertex_num++;
262             return;
263         }
264         ptr_pre = ptr;
265         ptr = ptr->next;
266     }
267 }
268
269 /**
270  * get Subvertex ptr by ID
271  */
272 OPENPTS_FSM_Subvertex * getSubvertex(OPENPTS_FSM_CONTEXT *ctx, char * id) {
273     OPENPTS_FSM_Subvertex *ptr;
274
275     /* check */
276     if (ctx == NULL) {
277         LOG(LOG_ERR, "null input");
278         return NULL;
279     }
280     if (id == NULL) {
281         LOG(LOG_ERR, "null input");
282         return NULL;
283     }
284
285     /* Final? */
286     if (!strcmp(id, "Final")) return NULL;  // final state
287
288     ptr = ctx->fsm_sub;
289
290     while (ptr != NULL) {
291         if (!strcmp(id, ptr->id)) return ptr;
292         ptr = (OPENPTS_FSM_Subvertex *) ptr->next;
293     }
294
295     return NULL;
296 }
297
298 /**
299  * get Subvertex Name by ID
300  */
301 char * getSubvertexName(OPENPTS_FSM_CONTEXT *ctx, char * id) {
302     int i;
303     OPENPTS_FSM_Subvertex *ptr;
304
305     /* check */
306     if (ctx == NULL) {
307         LOG(LOG_ERR, "null input");
308         return NULL;
309     }
310     if (id == NULL) {
311         LOG(LOG_ERR, "null input");
312         return NULL;
313     }
314
315     /* Final? */
316     if (!strcmp(id, "Final")) return id;
317
318     ptr = ctx->fsm_sub;
319     for (i = 0;i <= ctx->subvertex_num; i++) {
320         if (!strcmp(id, ptr->id)) return ptr->name;
321         ptr = (OPENPTS_FSM_Subvertex *) ptr->next;
322     }
323
324     return NULL;
325 }
326
327 /**
328  * get Subvertex ID by Name
329  */
330 char * getSubvertexId(OPENPTS_FSM_CONTEXT *ctx, char * name) {
331     int i;
332     OPENPTS_FSM_Subvertex *ptr;
333
334     /* check */
335     if (ctx == NULL) {
336         LOG(LOG_ERR, "null input");
337         return NULL;
338     }
339     if (name == NULL) {
340         LOG(LOG_ERR, "null input");
341         return NULL;
342     }
343
344     ptr = ctx->fsm_sub;
345     for (i = 0;i <= ctx->subvertex_num; i++) {
346         if (!strcmp(name, ptr->name)) return ptr->id;
347         ptr = (OPENPTS_FSM_Subvertex *) ptr->next;
348     }
349
350     return NULL;
351 }
352
353
354 /// TRANSITION ///
355
356 static char *skipWhiteSpace(char *str, int *len /* out */) {
357     char *cur = str, *end = str + *len;
358
359     /* check */
360     if (str == NULL) {
361         LOG(LOG_ERR, "null input");
362         return NULL;
363     }
364
365     /* skip space */
366     while (cur < end &&
367            '\0' != *cur &&
368            ' '  == *cur) {
369         cur++;
370     }
371     *len -= cur - str;
372     return cur;
373 }
374
375 static int isEndOfString(char *str) {
376     /* check */
377     if (str == NULL) {
378         LOG(LOG_ERR, "null input");
379         return 0;  // TODO
380     }
381
382     return '\0' == *str;
383 }
384
385 static char *skipParameter(char *str, int *len /* out */) {
386     char *cur = str, *end = str + *len;
387
388     /* check */
389     if (str == NULL) {
390         LOG(LOG_ERR, "null input");
391         return NULL;
392     }
393
394     /* skip space */
395     while (cur < end &&
396            '\0' != *cur &&
397            ' '  != *cur &&
398            ','  != *cur) {
399         cur++;
400     }
401     *len -= cur - str;
402     return cur;
403 }
404
405 /**
406  *   <body>eventtype == 0x01, digest == base64</body>
407  * -1: error
408  *  0: don't care
409  *   1: ==, eq
410  *   2: !=, ne
411  *
412  * Unit Test : check_fsm.c / test_getTypeFlag
413  *
414  */
415 int getTypeFlag(char * cond, UINT32 *eventtype /* out */) {
416     char * loc;
417     int len;
418     int rc = 0;
419     long int val;  // TODO uint64_t? but build fail on i386 platform
420
421     /* check */
422     if (cond == NULL) {
423         LOG(LOG_ERR, "null input");
424         return -1;
425     }
426
427     len = strlen(cond);
428     loc = strstr(cond, "eventtype");
429
430     if (loc == NULL) {  // miss
431         *eventtype = 0;
432         return 0;
433     } else {  // hit
434         /* skip eventtype*/
435         loc += 9;
436         len -= (loc - cond);
437
438         loc = skipWhiteSpace(loc, &len);
439         if (isEndOfString(loc)) {
440             return -1;
441         }
442
443         /* operation */
444         if (len < 2) {
445             LOG(LOG_ERR, "ERROR 001\n");
446             return -1;  // end
447         }
448         if ((loc[0] == '=') && (loc[1] == '=')) {  // ==
449             rc = 1;
450         } else if ((loc[0] == 'e') && (loc[1] == 'q')) {  // ==
451             rc = 1;
452         } else if ((loc[0] == '!') && (loc[1] == '=')) {  // !=
453             rc = 2;
454         } else if ((loc[0] == 'n') && (loc[1] == 'e')) {  // !=
455             rc = 2;
456         } else {
457             LOG(LOG_ERR, "ERROR 002 %c %c \n", loc[0], loc[1]);
458             return -1;  // unknown operand
459         }
460         loc += 2;
461         len -= 2;
462
463         loc = skipWhiteSpace(loc, &len);
464         if (isEndOfString(loc)) {
465             return -1;
466         }
467
468         /* value */
469         // 20110117 Ubuntu i386, 0x80000002 => 7FFFFFFF, => use strtoll
470         if (len > 2) {
471             if  ((loc[0] == '0') && (loc[1] == 'x')) {  // 0x HEX
472                 val = strtoll(loc, NULL, 16);
473                 *eventtype = (UINT32)val;
474                 // DEBUG("strtol [%s] => %X => %X\n", loc,val,*eventtype);
475                 return rc;
476             }
477         }
478         val = strtoll(loc, NULL, 10);
479         *eventtype = (UINT32)val;
480         // DEBUG("strtol [%s] => %X => %X\n", loc,val, *eventtype);
481
482         return rc;
483     }
484 }
485
486 /**
487  * Parse condition string and setup an internal digest condition structure
488  *
489  * Return
490  *   0: don't care
491  *   1: valid (=binary model),  return the digest => freed at freeFsmTransitionChain()
492  *   2: ignore now (=behavior model or ignored digests in binary model)
493  *  -1: Error?
494  *
495  * Unit Test : check_fsm.c / test_getDigestFlag
496  *
497  * TODO STA may complain the memory leak againt *digest.
498  */
499 int getDigestFlag(char * cond, BYTE **digest, int *digest_size) {
500     char * loc;   // loc at value
501     int len;
502     BYTE *buf;
503     int buf_len;
504
505     DEBUG_CAL("getDigestFlag -");
506
507     /* check */
508     if (cond == NULL) {
509         LOG(LOG_ERR, "null input");
510         return -1;
511     }
512
513     len = strlen(cond);
514
515     loc = strstr(cond, "digest");
516     if (loc == NULL) {  // miss
517         *digest_size = 0;
518         return DIGEST_FLAG_SKIP;
519     } else {  // hit
520         /* skip  digest */
521         loc += 6;
522         len -= (loc - cond);
523
524         loc = skipWhiteSpace(loc, &len);
525         if (isEndOfString(loc)) {
526             return -1;
527         }
528
529         /* operation, "==" only */
530         if (len < 2) {
531             LOG(LOG_ERR, "ERROR 001\n");
532             return -1;  // end
533         }
534         if ((loc[0] == '=') && (loc[1] == '=')) {  // ==
535             // operand is ==
536         } else {
537             LOG(LOG_ERR, "ERROR 002 [%c%c]  not  ==, (cond = %s)\n", loc[0], loc[1], cond);
538             return -1;  // unknown operand
539         }
540         loc +=2;
541         len -=2;
542
543         /* skip space */
544         loc = skipWhiteSpace(loc, &len);
545         if (isEndOfString(loc)) {
546             return -1;
547         }
548
549         if (NULL != strstr(loc, "base64!")) {  // HIT, temp
550             /* Behavior Model */
551             return DIGEST_FLAG_IGNORE;
552         } else if (NULL != strstr(loc, "base64")) {  // HIT, temp
553             /* Behavior Model */
554             return DIGEST_FLAG_IGNORE;
555         } else if (NULL != strstr(loc, "transparent!")) {
556             /* we have been told to ignore this digest from the binary model */
557             /* and use the behaviour version instead */
558             return DIGEST_FLAG_TRANSPARENT;
559         } else {
560             /* Binary Model */
561             /* Base64 str -> BYTE[] */
562             buf = decodeBase64(
563                 (char *)loc,
564                 SHA1_BASE64_DIGEST_SIZE,
565                 &buf_len);
566             if (buf == NULL) {
567                 LOG(LOG_ERR, "decodeBase64 fail");
568                 *digest = NULL;
569                 *digest_size = 0;
570                 return -1;
571             } else if (buf_len == SHA1_DIGEST_SIZE) {
572                 *digest = buf;
573                 *digest_size = SHA1_DIGEST_SIZE;
574                 return DIGEST_FLAG_EQUAL;  // 1
575             } else {
576                 LOG(LOG_ERR, "getDigestFlag() - decodeBase64() was failed \n");
577                 xfree(buf);
578                 *digest = NULL;
579                 *digest_size = 0;
580                 return -1;
581             }
582         }
583     }
584 }
585
586 /**
587  * Parse condition string and setup an internal couter condition structure
588  *
589  *
590  * 
591  * Return
592  *   COUNTER_FLAG_SKIP 0: don't care
593  *   COUNTER_FLAG_LT   1:  < name
594  *   COUNTER_FLAG_GTE  2:  >= name 
595  *
596  * Unit Test : check_fsm.c / test_getCounterFlag
597  */
598 int getCounterFlag(char *cond, char *name, char **flag /* out */) {
599     char * loc;   // loc at value
600     char * loc2;  // loc at flag
601     int len;
602     int rc = COUNTER_FLAG_SKIP;
603
604     /* check */
605     if (cond == NULL) {
606         LOG(LOG_ERR, "Null condition found");
607         return 0;
608     }
609     if (name == NULL) {
610         LOG(LOG_ERR, "Null condition found");
611         return 0;
612     }
613
614     /* parse the flag */
615     len = strlen(cond);
616     loc = strstr(cond, name);
617
618     if (loc == NULL) {
619         /* miss */
620         return 0;
621     } else {
622         int param_len = 0;
623         /* hit */
624
625         /* skip  count */
626         loc += strlen(name);
627         len -= (loc - cond);
628
629         loc = skipWhiteSpace(loc, &len);
630         if (isEndOfString(loc)) {
631             goto error;  //return -1;
632         }
633
634         /* operation, "&lt;" ">=" only */
635         if ((len >= 2) && (loc[0] == 'l') && (loc[1] == 't')) {  // <, lt
636             rc = COUNTER_FLAG_LT;
637             loc +=2;
638             len -=2;
639         } else if ((len >= 2) && (loc[0] == 'l') && (loc[1] == 'e')) {  // <=, le
640             rc = COUNTER_FLAG_LE;
641             loc +=2;
642             len -=2;
643         } else if ((len >= 2) && (loc[0] == 'g') && (loc[1] == 't')) {  // >, gt
644             rc = COUNTER_FLAG_GT;
645             loc +=2;
646             len -=2;
647         } else if ((len >= 2) && (loc[0] == 'g') && (loc[1] == 'e')) {  // >, gt
648             rc = COUNTER_FLAG_GE;
649             loc +=2;
650             len -=2;
651         } else if ((len >= 2) && (loc[0] == '<') && (loc[1] == ' ')) {  // <, lt
652             rc = COUNTER_FLAG_LT;
653             loc +=2;
654             len -=2;
655         } else if ((len >= 2) && (loc[0] == '<') && (loc[1] == '=')) {  // <=, le
656             rc = COUNTER_FLAG_LE;
657             loc +=2;
658             len -=2;
659         } else if ((len >= 2) && (loc[0] == '>') && (loc[1] == ' ')) {  // >, gt
660             rc = COUNTER_FLAG_GT;
661             loc +=2;
662             len -=2;
663         } else if ((len >= 2) && (loc[0] == '>') && (loc[1] == '=')) {  // >=
664             rc = COUNTER_FLAG_GE;
665             loc +=2;
666             len -=2;
667         } else {
668             LOG(LOG_ERR, "unknown operand [%s]", &loc[0]);
669             goto error;  //return -1;
670         }
671
672         loc = skipWhiteSpace(loc, &len);
673         if (isEndOfString(loc)) {
674             goto error;  //return -1;
675         }
676
677         // TODO check the end, this code only support if counter is the last
678
679         loc2 = skipParameter(loc, &len);
680         param_len = loc2 - loc;
681         if (0 == param_len) {
682             /* we haven't moved along the string - no valid parameter found */
683             goto error;  //return -1;
684         }
685
686         /* DEBUG_FSM("[%d][%s][%s]\n",len, loc, loc2); */
687
688         *flag = xmalloc(param_len + 1);
689         if (*flag == NULL) {
690             goto error;  //return -1;
691         }
692         memset(*flag, 0, param_len + 1);
693         memcpy(*flag, loc, param_len);
694     }
695
696     DEBUG_FSM("getCounterFlag  %s #=> %d %s\n", cond, rc, *flag);
697
698     return rc;
699
700   error:
701     LOG(LOG_ERR, "getCounterFlag(\"%s\",\"%s\") fail", cond, name);
702     return -1;
703 }
704
705
706
707 /**
708  * Parse condition string and setup an internal couter condition structure
709  *
710  *
711  * 
712  * Return
713  *                    -1: error
714  *   LAST_FLAG_SKIP 0: don't care
715  *   LAST_FLAG_EQ   1:  == last
716  *   LAST_FLAG_NEQ  2:  != last 
717  *
718  * Unit Test : check_fsm.c / test_getCounterFlag
719  */
720 int getLastFlag(char * cond) {
721     char * loc;   // loc at value
722     char * loc2;  // loc at name
723     int len;
724     int rc = LAST_FLAG_SKIP;
725
726     /* check */
727     if (cond == NULL) {
728         LOG(LOG_ERR, "null input");
729         return -1;
730     }
731
732     len = strlen(cond);
733     loc = strstr(cond, "last");
734
735     if (loc == NULL) {
736         /* miss */
737         return LAST_FLAG_SKIP;
738     } else {
739         /* hit */
740         /* skip  count */
741         loc += 4;  // 2011-12-30 5 => 4
742         len -= (loc - cond);
743
744         loc = skipWhiteSpace(loc, &len);
745         if (isEndOfString(loc)) {
746             return -1;
747         }
748
749         /* operation, "&lt;" ">=" only */
750         if ((len >= 2) && (loc[0] == '=') && (loc[1] == '=')) {
751             /* >= */
752             rc = LAST_FLAG_EQ;
753             loc +=2;
754             len -=2;
755         } else if ((len >= 2) && (loc[0] == '!') && (loc[1] == '=')) {
756             /* >= */
757             rc = LAST_FLAG_NEQ;
758             loc +=2;
759             len -=2;
760         } else {
761             LOG(LOG_ERR, "Unknown operation [%s], cond=[%s], BAD Validation Model\n", &loc[0], cond);
762             return -1;
763         }
764
765         loc = skipWhiteSpace(loc, &len);
766         if (isEndOfString(loc)) {
767             LOG(LOG_ERR, "Unknown operation [%s]\n", &loc[0]);
768             return -1;
769         }
770
771         /* value */
772         loc2 = loc;
773         len = strlen(loc2);
774
775         if (!strncmp(loc2, "true", 4)) {
776             // DEBUG("true\n");
777             /* == true */
778             /* != true => false */
779         } else if (!strncmp(loc2, "false", 5)) {
780             // DEBUG("false %d\n",rc);
781             if (rc == LAST_FLAG_EQ) {
782                 rc = LAST_FLAG_NEQ;
783             } else {
784                 rc = LAST_FLAG_EQ;
785             }
786         } else {
787             LOG(LOG_ERR, "unknown value, %s\n", loc2);
788         }
789     }
790
791     // DEBUG("getLastFlag  %s #=> %d\n",cond, rc);
792
793     return rc;
794 }
795
796
797
798
799 /**
800  * add FSM transition
801  *
802  * Return
803  *   PTS_SUCCESS
804  *   PTS_INTERNAL_ERROR
805  */
806 int addFsmTransition(
807         OPENPTS_FSM_CONTEXT *ctx,
808         char *source,
809         char *target,
810         char *cond) {
811     int i;
812     OPENPTS_FSM_Transition *ptr = NULL;
813     OPENPTS_FSM_Transition *ptr_pre = NULL;
814
815     DEBUG_CAL("addFsmTransition - start\n");
816
817     /* check */
818     if (ctx == NULL) {
819         LOG(LOG_ERR, "null input");
820         return PTS_FATAL;
821     }
822     if (source == NULL) {
823         LOG(LOG_ERR, "null input");
824         return PTS_FATAL;
825     }
826     if (target == NULL) {
827         LOG(LOG_ERR, "null input");
828         return PTS_FATAL;
829     }
830     if (cond == NULL) {
831         LOG(LOG_ERR, "null input");
832         return PTS_FATAL;
833     }
834
835     /* trans */
836     ptr = ctx->fsm_trans;
837     for (i = 0; i <= ctx->transition_num; i++) {
838         if (ptr == NULL) {  // new
839             DEBUG_FSM(" src=%s -> dst=%s  cond[%s] %d\n",
840                       source, target, cond,
841                       (int)sizeof(OPENPTS_FSM_Transition));
842
843             /* malloc OPENPTS_FSM_Transition */
844             ptr = (OPENPTS_FSM_Transition *)
845                     xmalloc(sizeof(OPENPTS_FSM_Transition));
846             if (ptr == NULL) {
847                 LOG(LOG_ERR, "no memory");
848                 return PTS_INTERNAL_ERROR;
849             }
850             /* init */
851             memset(ptr, 0, sizeof(OPENPTS_FSM_Transition));
852             memcpy(ptr->source, source, FSM_BUF_SIZE);
853             memcpy(ptr->target, target, FSM_BUF_SIZE);
854             ptr->num = ctx->transition_num;
855             if (cond == NULL) {
856                 ptr->eventTypeFlag = 0;
857                 ptr->digestFlag = DIGEST_FLAG_SKIP;
858             } else if  (cond[0] == 0) {
859                 ptr->eventTypeFlag = 0;
860                 ptr->digestFlag = DIGEST_FLAG_SKIP;
861                 memcpy(ptr->cond, cond, FSM_BUF_SIZE);
862             } else {
863                 // 0:don't care, 1:care
864                 ptr->eventTypeFlag = getTypeFlag(cond, &ptr->eventType);
865                 // 0:don't care, 1:care, 2:temp, 3:transparent
866                 ptr->digestFlag = getDigestFlag(cond, &ptr->digest, &ptr->digestSize);
867                 // 0:don't care, 1:<, 2:>=
868                 ptr->counter_flag = getCounterFlag(cond, "digest_count", &ptr->counter_name);
869                 if (ptr->counter_flag < 0) {
870                     LOG(LOG_ERR, "getCounterFlag() fail (%s => %s [%s])", source, target, cond);
871                 }
872                 // 0:don't care, 1:<, 2:>=
873                 ptr->fatal_counter_flag = getCounterFlag(cond, "fatal_count", &ptr->fatal_counter_name);
874                 if (ptr->fatal_counter_flag < 0) {
875                     LOG(LOG_ERR, "getCounterFlag() fail (%s => %s [%s])", source, target, cond);
876                 }
877                 // 0:don't care 1: ==last 2: != last
878                 ptr->last_flag = getLastFlag(cond);
879                 memcpy(ptr->cond, cond, FSM_BUF_SIZE);
880             }
881             /* subvertex link (ptr) */
882             ptr->source_subvertex = getSubvertex(ctx, ptr->source);
883             ptr->target_subvertex = getSubvertex(ctx, ptr->target);
884
885             if (DIGEST_FLAG_TRANSPARENT == ptr->digestFlag) {
886                 DEBUG_FSM("Found transparent digest\n");
887                 ctx->numTransparencies++;
888             }
889
890             /* ptr */
891             ptr->next = NULL;
892             if (ctx->transition_num == 0) {
893                 ctx->fsm_trans = ptr;
894                 ptr->prev = NULL;  // first trans
895             } else if (ptr_pre != NULL) {
896                 ptr_pre->next = ptr;
897                 ptr->prev = ptr_pre;
898                 ptr->next = NULL;  // last trans
899             } else {
900                 LOG(LOG_ERR, "BAD, free last one");
901                 xfree(ptr);  // free last one
902                 return PTS_INTERNAL_ERROR;
903             }
904             ctx->transition_num++;
905             /* added */
906             return PTS_SUCCESS;
907         }
908         /* next */
909         ptr_pre = ptr;
910         ptr = (OPENPTS_FSM_Transition *)ptr->next;
911     }
912
913     LOG(LOG_ERR, "missing?\n");
914     return PTS_INTERNAL_ERROR;
915 }
916
917 #if 0
918 /**
919  * get Event String (malloc) - obsolete function
920  */
921 char *getEventString(OPENPTS_PCR_EVENT_WRAPPER *eventWrapper) {
922     // int len;
923     int size = FSM_BUF_SIZE;  // TODO fixed size
924     TSS_PCR_EVENT *event;
925     char *buf;
926
927     /* malloc */
928     buf = xmalloc(size);
929     if (buf == NULL) {
930         return NULL;
931     }
932
933     /* event */
934     event = eventWrapper->event;
935     if (event != NULL) {
936         // len = snprintf(buf, size, "PCR[%d],TYPE=%d", (int)event->ulPcrIndex, event->eventType);
937     } else {
938         LOG(LOG_ERR, "NULL event\n");  // TODO(munetoh)
939         xfree(buf);
940         return NULL;
941     }
942
943     return buf;
944 }
945 #endif
946
947 /**
948  * get counter(int) value from property
949  * property
950  *    name=num
951  *
952  * return
953  *   -1   : ERROR
954  *    1   : missing, invalid (e.g. minus)
955  *    num 
956  */
957 int getCountFromProperty(OPENPTS_CONTEXT *ctx, char * name) {
958     int count = 0;  // TODO get from prop
959     OPENPTS_PROPERTY *prop;
960
961     /* check */
962     if (ctx == NULL) {
963         LOG(LOG_ERR, "null input");
964         return -1;
965     }
966     if (name == NULL) {
967         LOG(LOG_ERR, "null input");
968         return -1;
969     }
970
971     /* lookup */
972     prop = getProperty(ctx, name);
973     if (prop != NULL) {
974         /* Hit use this properties */
975         count = atoi(prop->value);
976         DEBUG_FSM("getCountFromProperty - prop %s = %d\n", name, count);
977         if (count < 0) {
978             DEBUG("getCountFromProperty - prop %s is %d < 0. set count to 1\n", count, name);
979             count = 1;
980         }
981     } else {
982         /* Miss -> 1 */
983         // TODO
984         DEBUG("getCountFromProperty - prop %s is missing. add property with count=1\n", name);
985         addProperty(ctx, name, "1");
986         count = 1;  // TODO
987     }
988     return count;
989 }
990
991 /**
992  * Drive FSM Transition by Event
993  *
994  * @parm eventWrapper  NULL, push the FSM until Final state
995  *
996  * Return
997  *
998  *  OPENPTS_FSM_ERROR
999  *
1000  *  OPENPTS_FSM_SUCCESS
1001  *  OPENPTS_FSM_FLASH
1002  *  OPENPTS_FSM_FINISH     reach Final State, move to the next snapshot(=model)
1003  *  OPENPTS_FSM_TRANSIT    transit to next FSM
1004  *  OPENPTS_FSM_ERROR_LOOP
1005  *
1006  * if eventWrapper is NULL, create and use dummy event 
1007  */
1008 int updateFsm(
1009         OPENPTS_CONTEXT *ctx,
1010         OPENPTS_FSM_CONTEXT *fsm,
1011         OPENPTS_PCR_EVENT_WRAPPER *eventWrapper
1012     ) {
1013     int rc = OPENPTS_FSM_SUCCESS;
1014     OPENPTS_FSM_Subvertex  *curr_state;
1015     OPENPTS_FSM_Transition *trans;
1016     TSS_PCR_EVENT *event;
1017     int type_check;
1018     int digest_check;
1019     int fatal_counter_check;
1020     int last_check;
1021     int dont_care;
1022     int hit = 0;
1023     char *hex;
1024     OPENPTS_FSM_Transition *hit_trans = NULL;
1025
1026     DEBUG_CAL("updateFsm - start\n");
1027
1028     /* check */
1029     if (ctx == NULL) {
1030         LOG(LOG_ERR, "null input");
1031         return PTS_FATAL;
1032     }
1033     if (fsm == NULL) {
1034         LOG(LOG_ERR, "null input");
1035         return PTS_FATAL;
1036     }
1037
1038     curr_state = fsm->curr_state;
1039     if (curr_state == NULL) {
1040         DEBUG_FSM("[RM%02d-PCR%02d] updateFsm() - curr_state == NULL => set the FSM state to 'Start'\n",
1041             fsm->level, fsm->pcr_index);
1042         curr_state = getSubvertex(fsm, "Start");
1043     }
1044     trans = fsm->fsm_trans;
1045
1046     /* Null event ->  push FSM until Final state */
1047     // TODO(munetoh) dummy event does not need event. just add flag to the wrapper
1048     if (eventWrapper == NULL) {
1049         DEBUG_FSM("[RM%02d-PCR%02d] create dummy event to flash the FSM\n",
1050             fsm->level, fsm->pcr_index);
1051
1052         /* dummy wrapper */
1053         eventWrapper = (OPENPTS_PCR_EVENT_WRAPPER *)
1054             xmalloc_assert(sizeof(OPENPTS_PCR_EVENT_WRAPPER));
1055         memset(eventWrapper, 0, sizeof(OPENPTS_PCR_EVENT_WRAPPER));
1056         eventWrapper->event_type = OPENPTS_DUMMY_EVENT;
1057         eventWrapper->push_count = 0;
1058         eventWrapper->last = 1;
1059
1060         /*  push */
1061         rc = updateFsm(ctx, fsm, eventWrapper);
1062         if (rc == OPENPTS_FSM_ERROR) {
1063             LOG(LOG_ERR, "updateFsm() - updateFsm push was fail\n");
1064         }
1065         if (rc == OPENPTS_FSM_ERROR_LOOP) {
1066             // DEBUG("updateFsm -- updateFsm push - loop \n");
1067         }
1068
1069         /* free dummy wrapper */
1070         xfree(eventWrapper);
1071         eventWrapper = NULL;
1072         return rc;
1073     } else if (eventWrapper->event == NULL) {
1074         if (eventWrapper->event_type == OPENPTS_DUMMY_EVENT) {
1075             // DUMMY
1076             eventWrapper->push_count++;
1077             event = NULL;
1078
1079             if (eventWrapper->push_count > 10) {
1080                 /* LOOP */
1081                 // TODO detect LOOP
1082                 // DEBUG("LOOP?\n");
1083                 return OPENPTS_FSM_ERROR_LOOP;
1084             }
1085         } else {
1086            LOG(LOG_ERR, "missing event body\n");
1087            return OPENPTS_FSM_ERROR;
1088         }
1089     } else {
1090         /* FSM update by event */
1091         event = eventWrapper->event;
1092     }
1093
1094     DEBUG_FSM("[RM%02d-PCR%02d] updateFsm() - State='%s', action='%s'\n",
1095         fsm->level, fsm->pcr_index,
1096         curr_state->name, curr_state->action);
1097
1098     if ((event != NULL) && isDebugFlagSet(DEBUG_FSM_FLAG)) {
1099         hex = getHexString(event->rgbPcrValue, event->ulPcrValueLength);
1100         DEBUG_FSM("[RM%02d-PCR%02d] eventtype=0x%x, digest=0x%s\n",
1101             fsm->level, fsm->pcr_index,
1102             event->eventType, hex);
1103         xfree(hex);
1104     }
1105
1106     if (eventWrapper->event_type == OPENPTS_DUMMY_EVENT) {
1107         // DEBUG("flash FSM\n");
1108         /* Flash the trans chain */
1109         hit_trans = NULL;
1110         while (trans != NULL) {
1111             if (!strcmp(trans->source, curr_state->id)) {
1112                 /* ID HIT, this is the trans from current state */
1113
1114                 /* Is this Final (last)? */
1115                 if (!strcmp(trans->target, UML2_SD_FINAL_STATE_STRING)) {
1116                     /* Final state => PENPTS_FSM_FINISH_WO_HIT */
1117                     DEBUG_FSM("[RM%02d-PCR%02d] Final state! move to the next snapshot\n",
1118                         fsm->level, fsm->pcr_index);
1119                     fsm->status = OPENPTS_FSM_FINISH;
1120                     return OPENPTS_FSM_FINISH_WO_HIT;
1121                 }
1122
1123                 /* More stats */
1124                 hit_trans = trans;
1125
1126                 if (trans->last_flag == LAST_FLAG_EQ) {
1127                     DEBUG_FSM("check last == true\n");
1128                     if (eventWrapper->last == 1) {
1129                         /* Hit */
1130                         break;
1131                     }
1132                 } else if (trans->last_flag == LAST_FLAG_NEQ) {
1133                     DEBUG_FSM("check last != true\n");
1134                     if (eventWrapper->last == 0) {
1135                         /* Hit */
1136                         break;
1137                     }
1138                 } else {
1139                     // DEBUG_FSM("last - don't care\n");
1140                 }
1141             }  // hit
1142             trans = trans->next;
1143         }  // while
1144
1145
1146         if (hit_trans != NULL) {
1147             // DEBUG("hit_trans\n");
1148             hit = 1;  // SKIP with this trans
1149             DEBUG_FSM("[RM%02d-PCR%02d] '%s' -> '%s'\n",
1150                     fsm->level, fsm->pcr_index,
1151                     hit_trans->source, hit_trans->target);
1152             fsm->curr_state = getSubvertex(fsm, hit_trans->target);
1153
1154             if (fsm->curr_state != NULL) {
1155                 /* doActivity, update properties */
1156                 rc = doActivity(ctx, (char *)fsm->curr_state->action, NULL);  // action.c
1157                 if (rc == OPENPTS_FSM_FLASH) {
1158                     /* last event, Flash FSM */
1159                     DEBUG_FSM("\t\tFlash FSM (don't care trans)\n");
1160
1161                     rc = updateFsm(ctx, fsm, NULL);
1162
1163                     if (rc == OPENPTS_FSM_FINISH_WO_HIT) {
1164                         rc = OPENPTS_FSM_FINISH;
1165                     } else {
1166                         LOG(LOG_ERR, "updateFsm - flash FSM was failed\n");
1167                         rc = OPENPTS_FSM_ERROR;
1168                     }
1169                 } else if (rc == OPENPTS_FSM_TRANSIT) {
1170                     /* transit FSM */
1171                     DEBUG_FSM("\t\tFlash FSM before transit \n");
1172
1173                     rc = updateFsm(ctx, fsm, NULL);  // flash FSM
1174
1175                     if  (rc == OPENPTS_FSM_FINISH_WO_HIT) {
1176                         rc = OPENPTS_FSM_TRANSIT;
1177                     } else {
1178                         LOG(LOG_ERR, "updateFsm - FSM did not finish\n");
1179                         rc = OPENPTS_FSM_ERROR;
1180                     }
1181                 } else if (rc == OPENPTS_FSM_ERROR) {
1182                     LOG(LOG_ERR, "updateFsm - FSM doActivity False\n");
1183                     return rc;
1184                 } else if (rc == OPENPTS_FSM_MIGRATE_EVENT) {
1185                     LOG(LOG_TODO, "updateFsm - OPENPTS_FSM_MIGRATE_EVENT \n");
1186                     return rc;
1187                 } else if (rc == OPENPTS_FSM_SUCCESS) {
1188                     rc = updateFsm(ctx, fsm, eventWrapper);
1189                 } else if (rc == PTS_INTERNAL_ERROR) {
1190                     // TODO  << INFO:(TODO) action.c:97 addBIOSAction() - eventWrapper is NULL
1191                     rc = updateFsm(ctx, fsm, eventWrapper);
1192                 } else {
1193                     LOG(LOG_TODO, "updateFsm() - rc = %d, call updateFsm() again\n", rc);
1194                     rc = updateFsm(ctx, fsm, eventWrapper);
1195                 }
1196             }  // curr state
1197         } else {  // hit
1198             LOG(LOG_TODO, "no trans\n");
1199         }
1200     } else {
1201         /* check trans chain */
1202         // DEBUG("updateFsm - check trans\n");
1203         while (trans != NULL) {
1204             type_check = 0;
1205             digest_check = 0;
1206             dont_care = 0;
1207
1208             if (!strcmp(trans->source, curr_state->id)) {
1209                 /*  ID HIT, this is the trans from current state */
1210
1211                 /* check the last flag */
1212                 hit_trans = trans;
1213                 last_check = 3;
1214
1215                 if (trans->last_flag == LAST_FLAG_EQ) {
1216                     DEBUG_FSM("check last == true\n");
1217                     if (eventWrapper->last == 1) {
1218                         /* Hit */
1219                         last_check = 1;
1220                     } else {
1221                         last_check = -1;
1222                     }
1223                 } else if (trans->last_flag == LAST_FLAG_NEQ) {
1224                     DEBUG_FSM("check last != true\n");
1225                     if (eventWrapper->last == 0) {
1226                         /* Hit */
1227                         last_check = 1;
1228                     } else {
1229                         last_check = -1;
1230                     }
1231                 } else {
1232                     // DEBUG_FSM("last - don't care\n");
1233                 }
1234
1235                 if (last_check == 1) {
1236                     DEBUG_FSM("last event push the FSM\n");
1237                 } else {
1238                     // DEBUG("NOT last event??? last_check = %d\n", last_check);
1239                     // DEBUG("NOT last event??? eventWrapper->last = %d\n", eventWrapper->last);
1240                     // DEBUG("NOT last event??? trans->last_flag = %d\n", trans->last_flag);
1241                 }
1242
1243
1244                 /* check the event type */
1245
1246                 if (trans->eventTypeFlag == EVENTTYPE_FLAG_EQUAL) {
1247                     // DEBUG_FSM("eventtype == %d - ", trans->eventType);
1248                     if (trans->eventType == event->eventType) {
1249                         /* TYPE MATCH */
1250                         // DEBUG_FSM("- valid\n");
1251                         type_check = 1;
1252                     } else {
1253                         // DEBUG_FSM("- invalid type %d(model) != %d(iml)\n", trans->eventType, event->eventType);
1254                         type_check = -1;
1255                     }
1256                 } else if (trans->eventTypeFlag == EVENTTYPE_FLAG_NOT_EQUAL) {
1257                     // DEBUG_FSM("eventtype != %d - ", trans->eventType);
1258                     if (trans->eventType != event->eventType) {
1259                         /* TYPE MATCH */
1260                         DEBUG_FSM("\t\t type %x(trans) != %x(event) \n", trans->eventType, event->eventType);
1261                         type_check = 2;
1262                     } else {
1263                         // DEBUG_FSM("- invalid type %d(model) == %d(iml)\n", trans->eventType, event->eventType);
1264                         type_check = -1;
1265                     }
1266                 } else {
1267                     // DEBUG_FSM("eventtype == %d - don't care\n", trans->eventType);
1268                     type_check = 3;
1269                     dont_care++;
1270                 }
1271
1272                 /* check the digest */
1273                 if (trans->digestFlag == DIGEST_FLAG_EQUAL) {
1274                     // DEBUG_FSM("digest -");
1275                     if (!memcmp(trans->digest,
1276                                 event->rgbPcrValue,
1277                                 event->ulPcrValueLength)) {
1278                         /* DIGEST MATCH */
1279                         digest_check = 1;
1280                         // DEBUG_FSM("- valid\n");
1281                     } else {
1282                         digest_check = -1;
1283                         // DEBUG_FSM("- invalid\n");
1284                     }
1285                 } else if (trans->digestFlag == DIGEST_FLAG_IGNORE ||
1286                            trans->digestFlag == DIGEST_FLAG_TRANSPARENT) {
1287                     /* Behavior Model */
1288                     // DEBUG_FSM("digest - ignore\n");
1289                     digest_check = 2;
1290                 } else {
1291                     // DEBUG_FSM("digest - don't care\n");
1292                     digest_check = 3;
1293                     dont_care++;
1294                 }
1295
1296                 /* check the counter */
1297                 fatal_counter_check = 3;
1298                 if (trans->fatal_counter_flag == COUNTER_FLAG_LT) {
1299                     /* count < name */
1300                     int fatal_count = getCountFromProperty(ctx, trans->fatal_counter_name);
1301
1302                     if (fatal_count < 0) {
1303                         LOG(LOG_ERR, "getCountFromProperty() fail");
1304                     } else if (ctx->count < fatal_count) {
1305                         DEBUG_FSM("FATAL COUNTER %d < %d - HIT\n", ctx->count, fatal_count);
1306                         fatal_counter_check = 1;  // HIT
1307                     } else {
1308                         DEBUG_FSM("FATAL COUNTER %d < %d - MISS\n", ctx->count, fatal_count);
1309                         fatal_counter_check = -1;  // MISS
1310                     }
1311                 } else if (trans->fatal_counter_flag == COUNTER_FLAG_GE) {
1312                     /* count >= name */
1313                     int fatal_count = getCountFromProperty(ctx, trans->fatal_counter_name);
1314
1315                     // TODO at this moment we ignore >= condition,
1316                     if (fatal_count < 0) {
1317                         LOG(LOG_ERR, "getCountFromProperty() fail");
1318                     } else if (ctx->count >= fatal_count) {
1319                         DEBUG_FSM("FATAL COUNTER %d >= %d - HIT\n", ctx->count, fatal_count);
1320                         fatal_counter_check = 1;  // HIT
1321                     } else {
1322                         DEBUG_FSM("FATAL COUNTER %d >= %d - MISS\n", ctx->count, fatal_count);
1323                         fatal_counter_check = -1;  // MISS
1324                     }
1325                 } else {
1326                     // DEBUG_FSM("counter - don't care\n");
1327                 }
1328
1329                 if (trans->counter_flag != COUNTER_FLAG_SKIP) {
1330                     int thisCount = 1 + trans->event_num;
1331                     int maxCount = getCountFromProperty(ctx, trans->counter_name);
1332                     if (maxCount < 0) {
1333                         LOG(LOG_ERR, "getCountFromProperty() fail, trans->counter_flag=%d", trans->counter_flag);
1334                     } else if (trans->counter_flag == COUNTER_FLAG_GE &&
1335                         thisCount >= maxCount) {
1336                         DEBUG_FSM("DIGEST COUNTER %d >= %d ('%s') - digest is transparent\n",
1337                             thisCount, maxCount, trans->counter_name);
1338                         eventWrapper->transparent = 1;
1339                     } else if (trans->counter_flag == COUNTER_FLAG_LT &&
1340                                thisCount < maxCount) {
1341                         DEBUG_FSM("DIGEST COUNTER %d < %d ('%s') - digest is transparent\n",
1342                             thisCount, maxCount, trans->counter_name);
1343                         eventWrapper->transparent = 1;
1344                     }
1345                 }
1346
1347                 /* Judge */
1348                 // if ((type_check == 1) && (digest_check == 1)) {
1349                 if ((type_check > 0) &&
1350                     (digest_check > 0) &&
1351                     (fatal_counter_check > 0) &&
1352                     (last_check > 0)) {
1353                     /* Hit this Trans */
1354                     /* If Final state, switch to next snapshot */
1355                     if (!strcmp(trans->target, UML2_SD_FINAL_STATE_STRING)) {
1356                         /* Final state */
1357                         DEBUG_FSM("\tPCR[%d] level %d, Final state!! move to the next snapshot\n",
1358                             fsm->pcr_index, fsm->level);
1359                         // LOG(LOG_ERR, "PCR[%d] level %d, Final\n", fsm->pcr_index, fsm->level);
1360                         fsm->status = OPENPTS_FSM_FINISH;
1361                         return OPENPTS_FSM_FINISH_WO_HIT;  // FINAL
1362                     }
1363
1364                     /* create FSM-IML link */
1365                     eventWrapper->fsm_trans = trans;
1366                     trans->event = (void *) event;   // note) hold the last link of looped trans
1367                     trans->event_num++;  // # of shared trans > 1
1368                     DEBUG_FSM("[RM%02d-PCR%02d] trans->event_num = %d\n",
1369                         fsm->level, fsm->pcr_index, (int)trans->event_num);
1370                     hit = 1;
1371
1372                     /* next trans */
1373                     if (dont_care == 2) {
1374                         // this transfer does not feed event,
1375                         // just move to next state and check again
1376                         DEBUG_FSM("[RM%02d-PCR%02d] '%s' -> '%s'\n",
1377                             fsm->level, fsm->pcr_index,
1378                             trans->source, trans->target);
1379                         fsm->curr_state = getSubvertex(fsm, trans->target);
1380
1381                         if (fsm->curr_state != NULL) {
1382                             /* doActivity, update properties */
1383                             rc = doActivity(ctx, (char *)fsm->curr_state->action, NULL);  // action.c
1384                             if (rc == OPENPTS_FSM_FLASH) {
1385                                 /* last event, Flash FSM */
1386                                 DEBUG_FSM("\t\tFlash FSM (don't care trans)\n");
1387
1388                                 rc = updateFsm(ctx, fsm, NULL);
1389
1390                                 if (rc == OPENPTS_FSM_FINISH_WO_HIT) {
1391                                     rc = OPENPTS_FSM_FINISH;
1392                                 } else {
1393                                     LOG(LOG_ERR, "flash FSM was failed\n");
1394                                     rc = OPENPTS_FSM_ERROR;
1395                                 }
1396                             } else if (rc == OPENPTS_FSM_TRANSIT) {
1397                                 /* transit FSM */
1398                                 DEBUG_FSM("\t\tFlash FSM before transit \n");
1399
1400                                 rc = updateFsm(ctx, fsm, NULL);  // flash FSM
1401
1402                                 if (rc == OPENPTS_FSM_FINISH_WO_HIT) {
1403                                     rc = OPENPTS_FSM_TRANSIT;
1404                                 } else {
1405                                     LOG(LOG_ERR, "updateFsm - FSM did not finish\n");
1406                                     rc = OPENPTS_FSM_ERROR;
1407                                 }
1408                             } else if (rc == OPENPTS_FSM_ERROR) {
1409                                 DEBUG("updateFsm - doActivity error\n");
1410                                 // INFO("FSM validation of doActivity() was failed.
1411                                 // (FSM state = %s)\n",fsm->curr_state->name);
1412                                 addReason(ctx, fsm->pcr_index, NLS(MS_OPENPTS, OPENPTS_FSM_ACTION_FAILED,
1413                                                "[PCR%02d-FSM] The action '%s' failed at state '%s'"),
1414                                     fsm->pcr_index, (char *)fsm->curr_state->action, fsm->curr_state->name);
1415                                 return rc;
1416                             } else if (rc == OPENPTS_FSM_MIGRATE_EVENT) {
1417                                 LOG(LOG_TODO, "updateFsm - OPENPTS_FSM_MIGRATE_EVENT \n");
1418                                 return rc;
1419                             } else if (rc == OPENPTS_FSM_SUCCESS) {
1420                                 rc = updateFsm(ctx, fsm, eventWrapper);
1421                             } else {
1422                                 LOG(LOG_TODO, "rc = %d\n", rc);
1423                                 rc = updateFsm(ctx, fsm, eventWrapper);
1424                             }
1425                         }
1426                         break;
1427                     } else {
1428                         /* Trans */
1429                         DEBUG_FSM("[RM%02d-PCR%02d] %s -> %s - HIT (type=%d, digest=%d)\n",
1430                             fsm->level, fsm->pcr_index,
1431                             trans->source,
1432                             trans->target,
1433                             type_check, digest_check);
1434                         fsm->curr_state = getSubvertex(fsm, trans->target);
1435
1436                         if (fsm->curr_state != NULL) {
1437                             /* doActivity, update properties */
1438                             rc = doActivity(ctx, (char *)fsm->curr_state->action, eventWrapper);  // action.c
1439                             if (rc == OPENPTS_FSM_FLASH) {
1440                                 /* last event, Flash FSM */
1441                                 DEBUG_FSM("[RM%02d-PCR%02d] Flash this FSM\n",
1442                                     fsm->level, fsm->pcr_index);
1443
1444                                 rc = updateFsm(ctx, fsm, NULL);
1445
1446                                 if (rc == OPENPTS_FSM_FINISH_WO_HIT) {
1447                                     rc = OPENPTS_FSM_FINISH;
1448                                 } else {
1449                                     LOG(LOG_ERR, "updateFsm - flash FSM was failed, rc = %d\n", rc);
1450                                     rc = OPENPTS_FSM_ERROR;
1451                                 }
1452                             } else if (rc == OPENPTS_FSM_TRANSIT) {
1453                                 /* transit FSM */
1454                                 DEBUG_FSM("\t\tFlash FSM before transit \n");
1455
1456                                 rc = updateFsm(ctx, fsm, NULL);
1457
1458                                 if (rc == OPENPTS_FSM_FINISH_WO_HIT) {
1459                                     rc = OPENPTS_FSM_TRANSIT;
1460                                 } else {
1461                                     LOG(LOG_ERR, "updateFsm - FSM did not finish\n");
1462                                     rc = OPENPTS_FSM_ERROR;
1463                                 }
1464                             } else if (rc == OPENPTS_FSM_ERROR) {
1465                                 LOG(LOG_ERR, "updateFsm - FSM doActivity False, rc = %d\n", rc);
1466                                 return rc;
1467                             } else if (rc == OPENPTS_FSM_MIGRATE_EVENT) {
1468                                 // DEBUG("updateFsm - OPENPTS_FSM_MIGRATE_EVENT \n");
1469                                 return rc;
1470                             } else if (rc == OPENPTS_FSM_SUCCESS) {
1471                                 rc = OPENPTS_FSM_SUCCESS;
1472                             } else {
1473                                 /* */
1474                                 // DEBUG("rc = %d -> 0\n");  // fsm.c:1070 rc = 6 -> 0
1475                                 rc = OPENPTS_FSM_SUCCESS;
1476                             }
1477                         } else {
1478                             LOG(LOG_ERR, "curr_state is NULL, missing %s\n", trans->target);
1479                             rc = OPENPTS_FSM_ERROR;
1480                             return rc;
1481                         }
1482                         break;
1483                     }
1484                 } else {
1485                     // judge
1486                 }
1487             }  // if trans hit
1488             trans = trans->next;
1489         }  // while
1490     }  // DUMMY
1491
1492     /* MISS ALL? */
1493     if (hit == 0) {
1494         // 20101118 SM Reason generated at iml.c
1495         DEBUG_FSM("[RM%02d-PCR%02d] No transition => rc = OPENPTS_FSM_ERROR\n",
1496             fsm->level, fsm->pcr_index);
1497
1498         rc = OPENPTS_FSM_ERROR;
1499     }
1500
1501     /* success ? */
1502     return rc;
1503 }
1504
1505
1506 /**
1507  * Copy FSM
1508  *
1509  *   BHV->BIN
1510  *
1511  *   called from rm.c
1512  */
1513 OPENPTS_FSM_CONTEXT *copyFsm(OPENPTS_FSM_CONTEXT *src_fsm) {
1514     OPENPTS_FSM_CONTEXT * dst_fsm = NULL;
1515
1516     OPENPTS_FSM_Subvertex  *src_fsm_sub;
1517     OPENPTS_FSM_Subvertex  *dst_fsm_sub = NULL;
1518     OPENPTS_FSM_Subvertex  *dst_fsm_sub_prev = NULL;
1519
1520     OPENPTS_FSM_Transition *src_fsm_trans;
1521     OPENPTS_FSM_Transition *dst_fsm_trans = NULL;
1522     OPENPTS_FSM_Transition *dst_fsm_trans_prev = NULL;
1523
1524     int count;
1525
1526     DEBUG_FSM("copyFsm - start, PCR[%d]\n", src_fsm->pcrIndex);
1527
1528     /* check */
1529     if (src_fsm == NULL) {
1530         DEBUG("src_fsm == NULL, SKIP COPY\n");
1531         return NULL;
1532     }
1533
1534     /* New FSM */
1535     dst_fsm = (OPENPTS_FSM_CONTEXT *) xmalloc(sizeof(OPENPTS_FSM_CONTEXT));
1536     if (dst_fsm  == NULL) {
1537         return NULL;
1538     }
1539     memcpy((void *)dst_fsm, (void *)src_fsm, sizeof(OPENPTS_FSM_CONTEXT));
1540
1541     /* delete BHV-FSM smalloc link */
1542     dst_fsm->uml_file = NULL;
1543
1544     /* Copy Subvertexs */
1545     count = 0;
1546     src_fsm_sub = src_fsm->fsm_sub;
1547     if (src_fsm_sub == NULL) {
1548         LOG(LOG_ERR, "ERROR No FSM SUB\n");
1549         goto error;
1550     }
1551
1552     while (src_fsm_sub != NULL) {
1553         /* malloc new sub */
1554         dst_fsm_sub = (OPENPTS_FSM_Subvertex *)
1555             xmalloc_assert(sizeof(OPENPTS_FSM_Subvertex));
1556         /* copy */
1557         memcpy((void *)dst_fsm_sub,
1558                (void *)src_fsm_sub,
1559                sizeof(OPENPTS_FSM_Subvertex));
1560
1561         /* next ptr */
1562         if (dst_fsm_sub_prev != NULL) {  // 2nd-
1563             dst_fsm_sub_prev->next = dst_fsm_sub;
1564             dst_fsm_sub->prev = dst_fsm_sub_prev;
1565         } else {  // 1st
1566             dst_fsm->fsm_sub = dst_fsm_sub;
1567         }
1568         dst_fsm_sub_prev = dst_fsm_sub;
1569
1570         /* BHV-BIN link */
1571         dst_fsm_sub->link = src_fsm_sub;
1572         src_fsm_sub->link = dst_fsm_sub;
1573
1574         /* go next */
1575         src_fsm_sub = src_fsm_sub->next;
1576         count++;
1577     }
1578
1579     DEBUG_FSM("%d Subvertex was copied\n", count);
1580
1581     /* Copy Transitions */
1582     count = 0;
1583     src_fsm_trans = src_fsm->fsm_trans;
1584
1585     if (src_fsm_trans == NULL) {
1586         LOG(LOG_ERR, "ERROR No FSM TRANS\n");
1587         goto error;
1588     }
1589
1590     while (src_fsm_trans != NULL) {
1591         /* malloc new sub */
1592         dst_fsm_trans = (OPENPTS_FSM_Transition *)
1593             xmalloc_assert(sizeof(OPENPTS_FSM_Transition));
1594         /* copy */
1595         memcpy((void *)dst_fsm_trans,
1596                (void *)src_fsm_trans,
1597                sizeof(OPENPTS_FSM_Transition));
1598
1599         /* ptr */
1600         if (dst_fsm_trans_prev != NULL) {  // 2nd-
1601             dst_fsm_trans_prev->next = dst_fsm_trans;
1602             dst_fsm_trans->prev = dst_fsm_trans_prev;
1603         } else {  // 1st
1604             dst_fsm->fsm_trans = dst_fsm_trans;
1605         }
1606         dst_fsm_trans_prev = dst_fsm_trans;
1607
1608         /* links to sub, Start and Final */
1609         // TODO(munetoh) does NULL check need?
1610         src_fsm_sub = src_fsm_trans->source_subvertex;
1611         if (src_fsm_sub != NULL) {
1612             dst_fsm_trans->source_subvertex = src_fsm_sub->link;
1613         } else {
1614             LOG(LOG_ERR, "ERROR BHV trans %s source_subvertex is NULL\n",
1615                 src_fsm_trans->source);
1616         }
1617
1618         src_fsm_sub = src_fsm_trans->target_subvertex;
1619
1620         if (src_fsm_sub != NULL)
1621             dst_fsm_trans->target_subvertex = src_fsm_sub->link;
1622
1623         /* link between BIN and BHV FSM */
1624         dst_fsm_trans->link = src_fsm_trans;
1625         src_fsm_trans->link = dst_fsm_trans;
1626
1627         /* go next */
1628         src_fsm_trans = src_fsm_trans->next;
1629         count++;
1630     }
1631
1632     DEBUG_FSM("%d Transition was copied\n", count);
1633     DEBUG_FSM("copyFsm - done\n");
1634
1635     return dst_fsm;
1636
1637   error:
1638     if (dst_fsm != NULL) {
1639         xfree(dst_fsm);
1640     }
1641     return NULL;
1642 }
1643
1644 /**
1645
1646   S ----T--->Old_Sub
1647
1648   S ----T--->New_Sub(--->Old_Sub)
1649
1650           T(loop)
1651           |
1652   A---T---B---C
1653      
1654
1655           T(loop)
1656            |   A
1657            V   |
1658   A---T---BN   B--C    << NG
1659
1660
1661 */
1662 int changeTargetSubvertex(
1663         OPENPTS_FSM_CONTEXT *fsm_ctx,
1664         OPENPTS_FSM_Subvertex *old_sub,    // B
1665         OPENPTS_FSM_Subvertex *new_sub) {  // BN
1666     int rc = 0;
1667     OPENPTS_FSM_Transition *fsm_trans;
1668     int count = 0;
1669
1670     /* check */
1671     if (fsm_ctx == NULL) {
1672         LOG(LOG_ERR, "null input");
1673         return PTS_FATAL;
1674     }
1675     if (old_sub == NULL) {
1676         LOG(LOG_ERR, "null input");
1677         return PTS_FATAL;
1678     }
1679     if (new_sub == NULL) {
1680         LOG(LOG_ERR, "null input");
1681         return PTS_FATAL;
1682     }
1683
1684     /* */
1685     fsm_trans = fsm_ctx->fsm_trans;
1686
1687     /* check all trans to B */
1688     while (fsm_trans != NULL) {
1689         if (fsm_trans->target_subvertex == old_sub) {
1690             fsm_trans->target_subvertex = new_sub;
1691             snprintf(fsm_trans->target,
1692                      sizeof(fsm_trans->target),
1693                     "%s", new_sub->id);
1694         }
1695         fsm_trans = fsm_trans->next;
1696         count++;
1697     }
1698
1699     return rc;
1700 }
1701
1702 /**
1703
1704   S ----T--->Old_Sub
1705
1706   S ----T--->New_Sub(--->Old_Sub)
1707
1708           T(loop)
1709           |
1710   A---T---B---C
1711      
1712
1713                T(loop)
1714                |
1715   A---T---BN   B--C    << OK
1716
1717
1718 */
1719 int changeTransTargetSubvertex(
1720         OPENPTS_FSM_CONTEXT *fsm_ctx,
1721         OPENPTS_FSM_Subvertex *old_sub,    // B
1722         OPENPTS_FSM_Subvertex *new_sub) {  // BN
1723     int rc = 0;
1724     OPENPTS_FSM_Transition *fsm_trans;
1725     int count = 0;
1726
1727     /* check */
1728     if (fsm_ctx == NULL) {
1729         LOG(LOG_ERR, "null input");
1730         return PTS_FATAL;
1731     }
1732     if (old_sub == NULL) {
1733         LOG(LOG_ERR, "null input");
1734         return PTS_FATAL;
1735     }
1736     if (new_sub == NULL) {
1737         LOG(LOG_ERR, "null input");
1738         return PTS_FATAL;
1739     }
1740
1741     /* */
1742     fsm_trans = fsm_ctx->fsm_trans;
1743
1744     /* check all trans to B */
1745     while (fsm_trans != NULL) {
1746         if (fsm_trans->target_subvertex == old_sub) {
1747             /* HIT */
1748             if (fsm_trans->target_subvertex == fsm_trans->source_subvertex) {
1749                 // LOOP, belong to old sub
1750                 DEBUG_FSM("changeTransTargetSubvertex - keep loop '%s) \n",
1751                     fsm_trans->source);
1752             } else {
1753                 // move to new sub
1754                 fsm_trans->target_subvertex = new_sub;
1755                 snprintf(fsm_trans->target,
1756                          sizeof(fsm_trans->target),
1757                         "%s", new_sub->id);
1758                 DEBUG_FSM("changeTransTargetSubvertex - trans move to new sub (%s -> %s)\n",
1759                     fsm_trans->source, fsm_trans->target);
1760             }
1761         }
1762         fsm_trans = fsm_trans->next;
1763         count++;
1764     }
1765
1766     return rc;
1767 }
1768
1769
1770 /**
1771
1772 20100617 new alg
1773
1774 Behavior FSM
1775
1776                
1777 FSM   [A]---Ta---[B]---Tc---[C]
1778                   |
1779                  Tb(loop)
1780
1781
1782                   |<--loop-->|
1783 FSM   [A]---Ta---[B]---Tb---[B]---Tc---[C]
1784             |          |          |
1785 EW          e0       e1-e3        e4
1786                       (3)
1787
1788 Transfer Behavior to Binary FSM
1789
1790
1791                               |<--loop-->|
1792 FSM   [A]---Ta---[B0]---Tb0--[B]---Tb---[B]---Tc---[C]
1793             |           |           |         |
1794 EW          e0          e1         e2-e3      e4
1795                                    (2)
1796
1797                                           |<--loop-->|
1798 FSM   [A]---Ta---[B0]---Tb0--[B1]---tb1--[B]---Tb---[B]---Tc---[C]
1799             |           |           |          |          |
1800 EW          e0          e1          e2         e3         e4
1801                                                (1)
1802
1803
1804 FSM   [A]---Ta---[B0]---Tb0--[B1]---tb1--[B2]---Tb---[B]---Tc---[C]
1805             |           |           |           |          |
1806 EW          e0          e1          e2          e3         e4
1807                                                 (0)
1808
1809 */
1810
1811 int insertFsmNew(
1812         OPENPTS_FSM_CONTEXT *fsm_ctx,       // BIN-FSM
1813         OPENPTS_FSM_Transition *fsm_trans,  // target Trans
1814         OPENPTS_PCR_EVENT_WRAPPER *eventWrapper) {
1815     int rc =0;
1816     OPENPTS_FSM_Subvertex *prev_sub;  // STRUCT LINK
1817     OPENPTS_FSM_Subvertex *new_sub;
1818     OPENPTS_FSM_Subvertex *dst_sub;
1819     OPENPTS_FSM_Transition *prev_trans;  // STRUCT LINK
1820     OPENPTS_FSM_Transition *new_trans;
1821     TSS_PCR_EVENT *event;
1822
1823     DEBUG_FSM("insertFsm - start\n");
1824
1825     /* check input */
1826     if (fsm_ctx == NULL) {
1827         LOG(LOG_ERR, "null input");
1828         return -1;
1829     }
1830     if (fsm_trans == NULL) {
1831         LOG(LOG_ERR, "null input");
1832         return -1;
1833     }
1834     if (eventWrapper == NULL) {
1835         LOG(LOG_ERR, "null input");
1836         return -1;
1837     }
1838     event = eventWrapper->event;
1839     if (event == NULL) {
1840         LOG(LOG_ERR, "null input");
1841         return -1;
1842     }
1843
1844     if (fsm_trans->source_subvertex == NULL) {
1845         LOG(LOG_ERR, "ERROR fsm_trans->source_subvertex == NULL, %s -> %s\n",
1846             fsm_trans->source, fsm_trans->target);
1847         return -1;
1848     }
1849     if (fsm_trans->target_subvertex == NULL) {
1850         LOG(LOG_ERR, "ERROR fsm_trans->target_subvertex == NULL\n");
1851         return -1;
1852     }
1853
1854
1855     /* start */
1856     if (fsm_trans->source_subvertex == fsm_trans->target_subvertex) {
1857         /* OK, this is LOOP,  */
1858         DEBUG_FSM("Loop (%s->%s) has %d events\n",
1859             fsm_trans->source, fsm_trans->target, fsm_trans->event_num);
1860
1861         /* Base subvertex, B */
1862         dst_sub = fsm_trans->target_subvertex;
1863
1864         /* Add new subvertex, BN (->B) */
1865
1866         new_sub = (OPENPTS_FSM_Subvertex *)
1867             xmalloc(sizeof(OPENPTS_FSM_Subvertex));
1868         if (new_sub == NULL) {
1869             return -1;
1870         }
1871         /* copy */
1872         memcpy(new_sub,
1873                fsm_trans->source_subvertex,
1874                sizeof(OPENPTS_FSM_Subvertex));
1875
1876         snprintf(new_sub->id,  sizeof(new_sub->id),
1877                  "%s_LOOP_%d",
1878                  dst_sub->id, fsm_trans->copy_num);
1879         snprintf(new_sub->name, sizeof(new_sub->name),
1880                  "%s_LOOP_%d",
1881                  dst_sub->name, fsm_trans->copy_num);
1882         fsm_ctx->subvertex_num++;
1883
1884         /* Update the subvetex chain, A-B => A-BN-B  */
1885
1886         /* A <-> BN */
1887         prev_sub       = dst_sub->prev;
1888         prev_sub->next  = new_sub;
1889         new_sub->prev  = prev_sub;
1890
1891         /* BN <-> B */
1892         new_sub->next  = dst_sub;
1893         dst_sub->prev  = new_sub;
1894
1895         /* Any trans to B move to BN */
1896         // BN->B trans is open
1897         rc = changeTransTargetSubvertex(
1898                 fsm_ctx,
1899                 dst_sub,   // B
1900                 new_sub);  // BN
1901
1902         DEBUG_FSM("\tnew sub id = %s, name = %s added\n",
1903             new_sub->id, new_sub->name);
1904
1905         /*Next Updatre the Transition */
1906
1907         if (fsm_trans->event_num > 1) {
1908             /* Many loops, B-B -> BN-B-B, add new Trans between BN and B */
1909
1910             /* malloc */
1911             new_trans = (OPENPTS_FSM_Transition*)
1912                 xmalloc(sizeof(OPENPTS_FSM_Transition));
1913             if (new_trans == NULL) {
1914                 return -1;
1915             }
1916             /* copy */
1917             memcpy(new_trans,
1918                    fsm_trans,
1919                    sizeof(OPENPTS_FSM_Transition));
1920
1921             /* update the transition struct chain */
1922
1923             prev_trans = fsm_trans->prev;
1924             prev_trans->next = new_trans;
1925             new_trans->prev  = prev_trans;
1926
1927             new_trans->next = fsm_trans;
1928             fsm_trans->prev = new_trans;
1929
1930             fsm_ctx->transition_num++;
1931
1932             /* Update new Trans  */
1933             new_trans->source_subvertex = new_sub;
1934             snprintf(new_trans->source, sizeof(new_trans->source),
1935                      "%s", new_sub->id);
1936
1937             new_trans->target_subvertex = dst_sub;
1938             snprintf(new_trans->target, sizeof(new_trans->target),
1939                      "%s", dst_sub->id);
1940
1941             /* Update event link */
1942             // trans -> event
1943             new_trans->event = eventWrapper;  // TSS_PCR_EVENT_WRAPPER
1944             new_trans->event_num = 1;
1945             // event -> trans
1946             eventWrapper->fsm_trans = new_trans;
1947
1948             /* Update Original Trans */
1949             fsm_trans->event_num--;
1950             fsm_trans->copy_num++;
1951
1952             /* Copy digest value to trans  */
1953             if (0 == eventWrapper->transparent) {
1954                 new_trans->digestFlag = DIGEST_FLAG_EQUAL;
1955                 new_trans->digestSize = event->ulPcrValueLength;
1956                 new_trans->digest = xmalloc(event->ulPcrValueLength);
1957                 if (new_trans->digest == NULL) {
1958                     return -1;
1959                 }
1960                 memcpy(new_trans->digest, event->rgbPcrValue, event->ulPcrValueLength);
1961             } else {
1962                 DEBUG_FSM("Changing digestFlag == DIGEST_FLAG_TRANSPARENT\n");
1963                 new_trans->digestFlag = DIGEST_FLAG_TRANSPARENT;
1964             }
1965
1966             DEBUG_FSM("new  Trans BIN(%s -> %s)\n",
1967                       new_trans->source, new_trans->target);
1968             DEBUG_FSM("orig Trans BIN(%s -> %s) share = %d\n",
1969                       fsm_trans->source, fsm_trans->target, fsm_trans->event_num);
1970
1971         } else if (fsm_trans->event_num == 1) {
1972             /* Last loop, B-B -> BN-B, just update the trans */
1973
1974             /* Update new Trans  */
1975             fsm_trans->source_subvertex = new_sub;
1976             snprintf(fsm_trans->source, sizeof(new_trans->source),
1977                      "%s", new_sub->id);
1978
1979             /* Copy digest value to FSM */
1980             if (0 == eventWrapper->transparent) {
1981                 fsm_trans->digestFlag = DIGEST_FLAG_EQUAL;
1982                 fsm_trans->digestSize = event->ulPcrValueLength;
1983                 fsm_trans->digest = xmalloc(event->ulPcrValueLength);
1984                 if (fsm_trans->digest == NULL) {
1985                     return -1;
1986                 }
1987                 memcpy(fsm_trans->digest, event->rgbPcrValue, event->ulPcrValueLength);
1988             } else {
1989                 fsm_trans->digestFlag = DIGEST_FLAG_TRANSPARENT;
1990             }
1991
1992             // DEBUG_FSM("\tupdate Trans %p->%p->%p\n",
1993             //          fsm_trans->prev, fsm_trans, fsm_trans->next);
1994             DEBUG_FSM("\tUpdate Trans BIN(%s -> %s)\n",
1995                       fsm_trans->source, fsm_trans->target);
1996         } else {
1997             LOG(LOG_ERR, "BAD LOOP");
1998             return PTS_FATAL;
1999         }
2000     } else {
2001         LOG(LOG_ERR, "Not a loop");
2002         return PTS_FATAL;
2003     }
2004
2005     DEBUG_FSM("insertFsm - done\n");
2006     return rc;
2007 }
2008
2009
2010 /**
2011  *  remove the trans from transition chain
2012  */
2013 int removeFsmTrans(
2014         OPENPTS_FSM_CONTEXT *fsm_ctx,
2015         OPENPTS_FSM_Transition * trans) {
2016     int rc =0;
2017     OPENPTS_FSM_Transition * trans_prev;
2018     OPENPTS_FSM_Transition * trans_next;
2019
2020     /* check */
2021     if (fsm_ctx == NULL) {
2022         LOG(LOG_ERR, "null input");
2023         return PTS_FATAL;
2024     }
2025     if (trans == NULL) {
2026         LOG(LOG_ERR, "null input");
2027         return PTS_FATAL;
2028     }
2029
2030     /* save */
2031     trans_prev = trans->prev;
2032     trans_next = trans->next;
2033
2034     /* remove link */
2035     if (trans_prev != NULL) {
2036         trans_prev->next = trans_next;
2037     } else {  // 1st trans
2038         fsm_ctx->fsm_trans = trans_next;
2039     }
2040
2041     if (trans_next != NULL) {
2042         trans_next->prev = trans_prev;
2043     } else {  // last trans
2044         //
2045     }
2046
2047     return rc;
2048 }
2049
2050
2051 /**
2052  * remove FSM subvertex
2053  */
2054 int removeFsmSub(
2055         OPENPTS_FSM_CONTEXT *fsm_ctx,
2056         OPENPTS_FSM_Subvertex * sub) {
2057     int rc =0;
2058     OPENPTS_FSM_Subvertex * sub_prev;
2059     OPENPTS_FSM_Subvertex * sub_next;
2060
2061     /* check */
2062     if (fsm_ctx == NULL) {
2063         LOG(LOG_ERR, "null input");
2064         return PTS_FATAL;
2065     }
2066     if (sub == NULL) {
2067         LOG(LOG_ERR, "null input");
2068         return PTS_FATAL;
2069     }
2070
2071     /* save */
2072     sub_prev = sub->prev;
2073     sub_next = sub->next;
2074
2075     /* remove link */
2076     if (sub_prev != NULL) {
2077         sub_prev->next = sub_next;
2078     } else {  // 1st sub
2079         fsm_ctx->fsm_sub = sub_next;
2080     }
2081     if (sub_next != NULL) {
2082         sub_next->prev = sub_prev;
2083     } else {  // last sub
2084         //
2085     }
2086
2087     // TODO(munetoh) Free
2088
2089     return rc;
2090 }
2091
2092 /**
2093  *  clean up FSM
2094  *   - delete unused BHV Transitions
2095  *   - delete unused BHV Subvertex
2096  *
2097  */
2098 int cleanupFsm(OPENPTS_FSM_CONTEXT *fsm_ctx) {
2099     int rc = 0;
2100     int count = 0;
2101     int hit;
2102     OPENPTS_FSM_Transition * trans;
2103     OPENPTS_FSM_Transition * trans_next;
2104     OPENPTS_FSM_Subvertex * sub;
2105     OPENPTS_FSM_Subvertex * sub_next;
2106
2107     /* check */
2108     if (fsm_ctx == NULL) {
2109         LOG(LOG_ERR, "null input");
2110         return PTS_FATAL;
2111     }
2112
2113     DEBUG_FSM("cleanupFsm - start, PCR[%d]\n", fsm_ctx->pcrIndex);
2114
2115     /* Delete BHV Transitions */
2116
2117     trans = fsm_ctx->fsm_trans;
2118
2119     if (trans == NULL) {
2120         LOG(LOG_ERR, "ERROR No FSM TRANS\n");
2121         return -1;
2122     }
2123
2124     count = 0;
2125     while (trans != NULL) {
2126         trans_next = trans->next;
2127         if (trans->digestFlag == DIGEST_FLAG_IGNORE) {
2128             DEBUG_FSM("\tHIT %s->%s - removed\n",
2129                       trans->source, trans->target);
2130             rc = removeFsmTrans(fsm_ctx, trans);  // remove Trans
2131             if (rc < 0) {
2132                 LOG(LOG_ERR, "removeFsmTrans of %s -> %s was failed\n",
2133                       trans->source, trans->target);
2134                 return -1;
2135             }
2136             count++;
2137         } else {
2138             // printf("MISS \n");
2139         }
2140         trans = trans_next;
2141     }
2142
2143     DEBUG_FSM("cleanupFsm - %d trans was removed\n", count);
2144     fsm_ctx->transition_num -= count;
2145
2146     /* Delete state which does not have incomming trans */
2147     sub = fsm_ctx->fsm_sub;
2148     if (sub == NULL) {
2149         LOG(LOG_ERR, "ERROR No FSM SUB\n");
2150         return -1;
2151     }
2152
2153     count = 0;
2154     while (sub != NULL) {
2155         sub_next = sub->next;
2156         if (!strcmp(sub->id, "Start")) {
2157             // START state
2158         } else if (!strcmp(sub->id, "Final")) {
2159             // FINAL state
2160         } else {
2161             // Other states
2162             /* check trans */
2163             trans = fsm_ctx->fsm_trans;
2164             hit = 0;
2165             while (trans != NULL) {
2166                 if (!strcmp(trans->target, sub->id)) {
2167                     hit++;
2168                     if (trans->target_subvertex == sub) {
2169                         // hit++;
2170                         // TODO(munetoh)
2171                         //   EV_S_CRTM_VERSION is not detected. BAD link:-(
2172                         // break;
2173                     } else {
2174                         // printf("ERROR BAD LINK\n");
2175                         // printf("SUB id=%s name=%s \n",
2176                         //   sub->id,sub->name);
2177                         // printf("TRANS %s ->  %s \n",
2178                         //   trans->source,trans->target);
2179                     }
2180                 }
2181                 trans = trans->next;
2182             }
2183
2184             if (hit == 0) {
2185                 DEBUG_FSM("\tSub %p  id=%s name=%s not used\n",
2186                           sub, sub->id, sub->name);
2187                 /* remove sub */
2188                 removeFsmSub(fsm_ctx, sub);
2189             }
2190         }
2191
2192         sub = sub_next;
2193     }
2194
2195     DEBUG_FSM("cleanupFsm - %d trans was removed\n", count);
2196     fsm_ctx->subvertex_num -= count;
2197
2198
2199     /* Again, Delete trans which does not have source target */
2200
2201     trans = fsm_ctx->fsm_trans;
2202
2203     if (trans == NULL) {
2204         LOG(LOG_ERR, "No FSM TRANS\n");
2205         return -1;
2206     }
2207
2208     count = 0;
2209     while (trans != NULL) {
2210         trans_next = trans->next;
2211
2212         sub = getSubvertex(fsm_ctx, trans->source);
2213         if (sub == NULL) {
2214             DEBUG_FSM("\tMISSING SOURCE %s->%s\n",
2215                        trans->source, trans->target);
2216             removeFsmTrans(fsm_ctx, trans);
2217             count++;
2218         } else {
2219         }
2220
2221         trans = trans_next;
2222     }
2223
2224
2225     DEBUG_FSM("cleanupFsm - %d trans was removed - missing source\n", count);
2226     fsm_ctx->transition_num -= count;
2227
2228
2229     DEBUG_FSM("cleanupFsm - done\n");
2230     return rc;
2231 }
2232
2233 /**
2234  * write DOT State Diagram for Graphviz
2235  * dot -Tpng tests/bios_pcr0.dot -o tests/bios_pcr0.png; eog tests/bios_pcr0.png
2236  * @param ctx FSM_CONTEXT
2237  * @param filename dot filename to write
2238  *
2239  * Return
2240  *   PTS_SUCCESS
2241  *   PTS_OS_ERROR
2242  *   PTS_INTERNAL_ERROR
2243  */
2244 int writeDotModel(OPENPTS_FSM_CONTEXT *ctx, char * filename) {
2245     int rc = PTS_SUCCESS;
2246     FILE *fp;
2247     int j;
2248     OPENPTS_FSM_Subvertex *sptr;
2249     OPENPTS_FSM_Transition *ptr;
2250
2251     DEBUG("writeDotModel - start %s\n", filename);
2252
2253     /* check */
2254     if (ctx == NULL) {
2255         LOG(LOG_ERR, "null input");
2256         return PTS_FATAL;
2257     }
2258
2259     if (filename == NULL) {
2260         fp = stdout;
2261     } else {
2262         if ((fp = fopen(filename, "w")) == NULL) {
2263             LOG(LOG_ERR, "fopen fail %s\n", filename);
2264             return PTS_OS_ERROR;
2265         }
2266     }
2267
2268     DEBUG_FSM("Subvertex  num= %d \n", ctx->subvertex_num);
2269     DEBUG_FSM("Transition num= %d \n", ctx->transition_num);
2270
2271     fprintf(fp, "digraph G {\n");
2272
2273     /* Subvertex */
2274     sptr =ctx->fsm_sub;
2275
2276     while (sptr != NULL) {
2277         if (!strcmp(sptr->id, "Start")) {
2278             fprintf(fp, "\t%s [label =\"\", fillcolor=black];\n", sptr->id);
2279             // TODO(munetoh) fillcolor not work
2280         } else if (!strcmp(sptr->id, "Final")) {
2281             fprintf(fp, "\t%s [label =\"\", peripheries = 2];\n", sptr->id);
2282         } else if (strlen(sptr->action) > 0) {
2283             fprintf(fp, "\t%s [label=\"%s\\naction=%s\"];\n",
2284                     sptr->id,
2285                     sptr->name,
2286                     sptr->action);
2287         } else {
2288             fprintf(fp, "\t%s [label=\"%s\"];\n",
2289                     sptr->id,
2290                     sptr->name);
2291         }
2292         sptr = sptr->next;
2293     }
2294
2295     /* Transition */
2296     ptr = ctx->fsm_trans;
2297
2298     while (ptr != NULL) {
2299         DEBUG_FSM("\tTransition = (%s->%s)\n", ptr->source, ptr->target);
2300         /* cond */
2301         if (ptr->digestFlag == DIGEST_FLAG_EQUAL) {  // BIN
2302             fprintf(fp, "\t%s -> %s [label=\"",
2303                     ptr->source,
2304                     ptr->target);
2305             /* eventytpte */
2306             if (ptr->eventTypeFlag == EVENTTYPE_FLAG_EQUAL) {
2307                 fprintf(fp, "eventtype == 0x%x, ", ptr->eventType);
2308             } else if (ptr->eventTypeFlag == EVENTTYPE_FLAG_NOT_EQUAL) {
2309                 fprintf(fp, "eventtype != 0x%x, ", ptr->eventType);
2310             }
2311             /* digest */
2312             fprintf(fp, "\\nhexdigest == ");
2313             for (j = 0; j < ptr->digestSize; j++) {
2314                 fprintf(fp, "%02x", ptr->digest[j]);
2315                 // TODO(munetoh) Hex, also supports Base64
2316             }
2317             fprintf(fp, "\"];\n");
2318         } else {  // BHV
2319             fprintf(fp, "\t%s -> %s [label=\"%s\"];\n",
2320                     ptr->source,
2321                     ptr->target,
2322                     ptr->cond);
2323         }
2324         ptr = ptr->next;
2325     }
2326
2327     fprintf(fp, "}\n");
2328
2329     fclose(fp);
2330
2331     DEBUG("writeDotModel - done\n");
2332
2333     return rc;
2334 }
2335
2336 /**
2337  * write CSV file, RFC 4180 style
2338  *
2339  * @param ctx FSM_CONTEXT
2340  * @param filename csv filename to write
2341  */
2342 int writeCsvTable(OPENPTS_FSM_CONTEXT *ctx, char * filename) {
2343     int rc = 0;
2344     FILE *fp;
2345     int i;
2346     OPENPTS_FSM_Transition *ptr;
2347
2348     /* check */
2349     if (ctx == NULL) {
2350         LOG(LOG_ERR, "null input");
2351         return -1;
2352     }
2353     if (filename == NULL) {
2354         LOG(LOG_ERR, "writeCsvTable - filename is NULL\n");
2355         return -1;
2356     }
2357
2358     /* Open */
2359     if ((fp = fopen(filename, "w")) == NULL) {
2360         return -1;
2361     }
2362
2363     fprintf(fp,
2364         "current state,condition type(hex), condition digest,next state\n");
2365
2366     ptr = ctx->fsm_trans;
2367     for (i = 0; i < ctx->transition_num; i++) {
2368         fprintf(fp, "%s, ", getSubvertexName(ctx, ptr->source));
2369
2370         if (ptr->eventTypeFlag == 1) {
2371             fprintf(fp, "type==0x%x,", ptr->eventType);
2372         } else if (ptr->eventTypeFlag == 1) {
2373             fprintf(fp, "type!=0x%x,", ptr->eventType);
2374         } else {
2375             fprintf(fp, ",");
2376         }
2377
2378
2379         if (ptr->digestFlag == DIGEST_FLAG_EQUAL) {
2380             fprintf(fp, "digest==0x");
2381             // for (i=0;i<DIGEST_SIZE;i++) fprintf(fp,"%02x",ptr->digest[i]);
2382             fprintf(fp, ",");
2383         } else if (ptr->digestFlag == DIGEST_FLAG_IGNORE) {
2384             fprintf(fp, "digest==base64!,");
2385         } else if (ptr->digestFlag == DIGEST_FLAG_TRANSPARENT) {
2386             fprintf(fp, "digest==transparent!,");
2387         } else {
2388             fprintf(fp, ",");
2389         }
2390         fprintf(fp, "%s\n", getSubvertexName(ctx, ptr->target));
2391
2392         ptr = ptr->next;
2393     }
2394
2395     /* close */
2396     fclose(fp);
2397     return rc;
2398 }
2399
2400
2401 /**
2402  * print FSM State Diagram
2403  *
2404  * @param ctx FSM_CONTEXT
2405  */
2406 int printFsmModel(OPENPTS_FSM_CONTEXT *ctx) {
2407     int rc = 0;
2408     int i, j;
2409     OPENPTS_FSM_Transition *ptr;
2410
2411     /* check */
2412     if (ctx == NULL) {
2413         LOG(LOG_ERR, "null input");
2414         return PTS_FATAL;
2415     }
2416
2417     OUTPUT(NLS(MS_OPENPTS, OPENPTS_PRINT_FSM_HEADER,
2418            "ctx->transition_num = %d\n"
2419            "trans\t\tcurrent state\t\t\tcondition\t\t\\ttnext state\n"
2420            "  id  \t\t\t\t\ttype(hex)\tdigest(hex)\n"), ctx->transition_num);
2421     OUTPUT("----------------------------------------------------------------------------------------------\n");
2422
2423
2424     ptr = ctx->fsm_trans;
2425     for (i = 0; i < ctx->transition_num; i++) {
2426         if (ptr == NULL) {
2427             LOG(LOG_ERR, "PTR is NULL at %d\n", i);
2428             return PTS_FATAL;
2429         }
2430         OUTPUT("%5d ", i);
2431         OUTPUT("%30s ", getSubvertexName(ctx, ptr->source));
2432
2433         if (ptr->eventTypeFlag == 1) {
2434             OUTPUT(" 0x%08x  ", ptr->eventType);
2435         } else if (ptr->eventTypeFlag == 1) {
2436             OUTPUT("!0x%08x  ", ptr->eventType);
2437         } else {
2438             OUTPUT("             ");
2439         }
2440
2441         if (ptr->digestFlag == DIGEST_FLAG_EQUAL) {
2442             OUTPUT("0x");
2443             for (j = 0; j < ptr->digestSize; j++) OUTPUT("%02x", ptr->digest[j]);
2444             OUTPUT(" ");
2445         } else if (ptr->digestFlag == DIGEST_FLAG_IGNORE) {
2446             OUTPUT(NLS(MS_OPENPTS, OPENPTS_PRINT_FSM_BASE64, "base64                                     "));
2447         } else if (ptr->digestFlag == DIGEST_FLAG_TRANSPARENT) {
2448             /* WORK NEEDED: say transparent here? */
2449             OUTPUT("                                           ");
2450         } else {
2451             OUTPUT("                                           ");
2452         }
2453         OUTPUT("%-30s\n", getSubvertexName(ctx, ptr->target));
2454
2455         ptr = ptr->next;
2456     }
2457
2458     return rc;
2459 }
2460