/* * PROMELA Validation Model * FLOW CONTROL LAYER VALIDATION */ #define LOSS 1 /* message loss */ #define DUPS 0 /* duplicate msgs */ #define QSZ 2 /* queue size */ mtype = { red, white, blue, abort, accept, ack, sync_ack, close, connect, create, data, eof, open, reject, sync, transfer, FATAL, NON_FATAL, COMPLETE } chan ses_to_flow[2] = [QSZ] of { byte, byte }; chan flow_to_ses[2] = [QSZ] of { byte, byte }; chan dll_to_flow[2] = [QSZ] of { byte, byte }; /* * Flow Control Layer Validation Model */ #define true 1 #define false 0 #define M 4 /* range sequence numbers */ #define W 2 /* window size: M/2 */ proctype fc(chan s2f, f2d, f2s, d2f) { bool busy[M]; /* outstanding messages */ byte q; /* seq# oldest unacked msg */ byte m; /* seq# last msg received */ byte s; /* seq# next msg to send */ byte window; /* nr of outstanding msgs */ byte type; /* msg type */ bit received[M]; /* receiver housekeeping */ bit x; /* scratch variable */ byte p; /* seq# of last msg acked */ byte I_buf[M], O_buf[M]; /* message buffers */ xr s2f; xs f2d; xs f2s; xr d2f; /* sender part */ end: do :: atomic { (window < W && nempty(s2f) && nfull(f2d)) -> s2f?type,x; window = window + 1; busy[s] = true; O_buf[s] = type; f2d!type,s; if :: (type != sync) -> s = (s+1)%M :: (type == sync) -> window = 0; s = M; do :: (s > 0) -> s = s-1; busy[s] = false :: (s == 0) -> break od fi } :: atomic { (window > 0 && busy[q] == false) -> window = window - 1; q = (q+1)%M } #if DUPS :: atomic { (nfull(f2d) && window > 0 && busy[q] == true) -> f2d!O_buf[q],q } #endif :: atomic { (timeout && nfull(f2d) && window > 0 && busy[q] == true) -> f2d!O_buf[q],q } /* receiver part */ #if LOSS :: d2f?type,m /* lose any message */ #endif :: d2f?type,m -> if :: atomic { (type == ack) -> busy[m] = false } :: atomic { (type == sync) -> m = 0; do :: (m < M) -> received[m] = 0; m = m+1 :: (m == M) -> break od }; f2d!sync_ack,0 :: (type == sync_ack) -> f2s!sync_ack,0 :: (type != ack && type != sync && type != sync_ack)-> if :: atomic { (received[m] == true) -> x = ((0 f2d!ack,m :: (!x) /* else skip */ fi :: atomic { (received[m] == false) -> I_buf[m] = type; received[m] = true; received[(m-W+M)%M] = false } fi fi :: /* atomic { */ (received[p] == true && nfull(f2s) && nfull(f2d)) -> f2s!I_buf[p],0; f2d!ack,p; p = (p+1)%M /* } */ od } proctype upper_s(chan s2f, f2s0) { byte s_state; byte type, toggle; xs s2f; xr f2s0; s2f!sync,toggle; do :: f2s0?sync_ack,type -> if :: (type != toggle) :: (type == toggle) -> break fi :: timeout -> s2f!sync,toggle od; toggle = 1 - toggle; end: do :: s2f!white,0 :: atomic { (s_state == 0 && nfull(s2f)) -> s2f!red,0 -> s_state = 1 } :: atomic { (s_state == 1 && nfull(s2f)) -> s2f!blue,0 -> s_state = 2 } od } proctype upper_r(chan f2s1) { byte r_state; xr f2s1; do :: f2s1?white,0 :: f2s1?red,0 -> break :: f2s1?blue,0 -> assert(0) od; do :: f2s1?white,0 :: f2s1?red,0 -> assert(0) :: f2s1?blue,0 -> goto end od; end: do :: f2s1?white,0 :: f2s1?red,0 -> assert(0) :: f2s1?blue,0 -> assert(0) od } init { atomic { run fc(ses_to_flow[0], dll_to_flow[1], flow_to_ses[0], dll_to_flow[0]); run fc(ses_to_flow[1], dll_to_flow[0], flow_to_ses[1], dll_to_flow[1]); run upper_s(ses_to_flow[0], flow_to_ses[0]); run upper_r(flow_to_ses[1]) } }