113e3f4d6SMark Murray 213e3f4d6SMark Murray Three pieces of state need to be kept for each side of each option. 313e3f4d6SMark Murray (You need the localside, sending WILL/WONT & receiving DO/DONT, and 413e3f4d6SMark Murray the remoteside, sending DO/DONT and receiving WILL/WONT) 513e3f4d6SMark Murray 613e3f4d6SMark Murray MY_STATE: What state am I in? 713e3f4d6SMark Murray WANT_STATE: What state do I want? 813e3f4d6SMark Murray WANT_RESP: How many requests have I initiated? 913e3f4d6SMark Murray 1013e3f4d6SMark Murray Default values: 1113e3f4d6SMark Murray MY_STATE = WANT_STATE = DONT 1213e3f4d6SMark Murray WANT_RESP = 0 1313e3f4d6SMark Murray 1413e3f4d6SMark Murray The local setup will change based on the state of the Telnet 1513e3f4d6SMark Murray variables. When we are the originator, we can either make the 1613e3f4d6SMark Murray local setup changes at option request time (in which case if 1713e3f4d6SMark Murray the option is denied we need to change things back) or when 1813e3f4d6SMark Murray the option is acknowledged. 1913e3f4d6SMark Murray 2013e3f4d6SMark Murray To initiate a switch to NEW_STATE: 2113e3f4d6SMark Murray 2213e3f4d6SMark Murray if ((WANT_RESP == 0 && NEW_STATE == MY_STATE) || 2313e3f4d6SMark Murray WANT_STATE == NEW_STATE) { 2413e3f4d6SMark Murray do nothing; 2513e3f4d6SMark Murray } else { 2613e3f4d6SMark Murray /* 2713e3f4d6SMark Murray * This is where the logic goes to change the local setup 2813e3f4d6SMark Murray * if we are doing so at request initiation 2913e3f4d6SMark Murray */ 3013e3f4d6SMark Murray WANT_STATE = NEW_STATE; 3113e3f4d6SMark Murray send NEW_STATE; 3213e3f4d6SMark Murray WANT_RESP += 1; 3313e3f4d6SMark Murray } 3413e3f4d6SMark Murray 3513e3f4d6SMark Murray When receiving NEW_STATE: 3613e3f4d6SMark Murray 3713e3f4d6SMark Murray if (WANT_RESP) { 3813e3f4d6SMark Murray --WANT_RESP; 3913e3f4d6SMark Murray if (WANT_RESP && (NEW_STATE == MY_STATE)) 4013e3f4d6SMark Murray --WANT_RESP; 4113e3f4d6SMark Murray } 4213e3f4d6SMark Murray if (WANT_RESP == 0) { 4313e3f4d6SMark Murray if (NEW_STATE != WANT_STATE) { 4413e3f4d6SMark Murray /* 4513e3f4d6SMark Murray * This is where the logic goes to decide if it is ok 4613e3f4d6SMark Murray * to switch to NEW_STATE, and if so, do any necessary 4713e3f4d6SMark Murray * local setup changes. 4813e3f4d6SMark Murray */ 4913e3f4d6SMark Murray if (ok_to_switch_to NEW_STATE) 5013e3f4d6SMark Murray WANT_STATE = NEW_STATE; 5113e3f4d6SMark Murray else 5213e3f4d6SMark Murray WANT_RESP++; 5313e3f4d6SMark Murray* if (MY_STATE != WANT_STATE) 5413e3f4d6SMark Murray reply with WANT_STATE; 5513e3f4d6SMark Murray } else { 5613e3f4d6SMark Murray /* 5713e3f4d6SMark Murray * This is where the logic goes to change the local setup 5813e3f4d6SMark Murray * if we are doing so at request acknowledgment 5913e3f4d6SMark Murray */ 6013e3f4d6SMark Murray } 6113e3f4d6SMark Murray } 6213e3f4d6SMark Murray MY_STATE = NEW_STATE; 6313e3f4d6SMark Murray 6413e3f4d6SMark Murray* This if() line is not needed, it should be ok to always do the 6513e3f4d6SMark Murray "reply with WANT_STATE". With the if() line, asking to turn on 6613e3f4d6SMark Murray an option that the other side doesn't understand is: 6713e3f4d6SMark Murray Send DO option 6813e3f4d6SMark Murray Recv WONT option 6913e3f4d6SMark Murray Without the if() line, it is: 7013e3f4d6SMark Murray Send DO option 7113e3f4d6SMark Murray Recv WONT option 7213e3f4d6SMark Murray Send DONT option 7313e3f4d6SMark Murray If the other side does not expect to receive the latter case, 7413e3f4d6SMark Murray but generates the latter case, then there is a potential for 7513e3f4d6SMark Murray option negotiation loops. An implementation that does not expect 7613e3f4d6SMark Murray to get the second case should not generate it, an implementation 7713e3f4d6SMark Murray that does expect to get it may or may not generate it, and things 7813e3f4d6SMark Murray will still work. Being conservative in what we send, we have the 7913e3f4d6SMark Murray if() statement in, but we expect the other side to generate the 8013e3f4d6SMark Murray last response. 81