Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

Oberon/ETH Oberon/PPPFSM.Mod

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

(* ETH Oberon, Copyright 1990-2003 Computer Systems Institute, ETH Zurich, CH-8092 Zurich. Refer to the license.txt file provided with this distribution. *) MODULE PPPFSM; (** non-portable *) (* FSM = Finite State Machine; equivalent to "automaton" in RFC 1548. *) (* $VCS 2, Edgar.Schwarz@z.zgs.de, 5 Sep 99, 13:46:21 $ $Log$ $ 2, Edgar.Schwarz@z.zgs.de, 5 Sep 99, 13:46:21 log message for echo reply addes $ 1, Edgar.Schwarz@z.zgs.de, 28 Feb 99, 22:15:39 version for PPP 1.0.0 *) IMPORT HDLC := PPPHDLC, Debug := PPPDebug, Tools := PPPTools; CONST (** CP (LCP, IPCP, etc.) codes *) ConfReq* = 1; (* configuration request *) ConfAck* = 2; (* configuration ack *) ConfNak* = 3; (* configuration nak *) ConfRej* = 4; (* configuration reject *) TermReq = 5; (* termination request *) TermAck = 6; (* termination ack *) CodeRej = 7; (* code reject *) ProtRej = 8; (* protocol reject *) EchoReq = 9; EchoReply = 10; (** Link states *) Initial* = 0; (* down, hasn't been opened *) Starting* = 1; (* down, been opened *) Closed* = 2; (* up, hasn't been opened *) Stopped* = 3; (* open, waiting for down event *) Closing* = 4; (* Terminating the connection, not open *) Stopping* = 5; (* terminating, but open *) ReqSent* = 6; (* we've sent a config request *) AckRcvd* = 7; (* we've received a config ack *) AckSent* = 8; (* we've sent a config ack *) Opened* = 9; (* connection available *) (** Flags *) Passive* = 0; (* don't die if we don't get a response *) Restart* = 1; (* treat second Open as Down, Up *) Silent* = 2; (* wait for peer to speak first *) (** Timeouts *) DefTimeout* = 30000; (* timeout time in milliseconds *) DefMaxTermReqs* = 2; (* maximum terminate-request transmissions *) DefMaxConfReqs* = 10; (* maximum configure-request transmissions *) DefMaxNakLoops* = 10; (* maximum # of nak loops *) HeaderLen = 4; (* code(1) + id(1) + len(2) = HeaderLen of a CP-Packet *) StartPos = HDLC.StartPos + HDLC.HDLCHeaderLen + HeaderLen; newtransmit = TRUE; retransmit = FALSE; StrLen* = 33; TYPE Params = POINTER TO ParamsDesc; FSM* = POINTER TO FSMDesc; FSMDesc* = RECORD Protocol*: INTEGER; ProtoName*: ARRAY 32 OF CHAR; State*: SHORTINT; Flags*: SET; ID*, reqID*: SHORTINT; (* unsigned char *) TimeoutTime: LONGINT; MaxConfReqTransmits*, Retransmits*, MaxTermTransmits*, NakLoops*, MaxNakLoops*: INTEGER; (* Callback Procedures *) ResetCI*: PROCEDURE (f: FSM); CILen*: PROCEDURE (f: FSM): INTEGER; AddCI*: PROCEDURE (f: FSM; VAR p: ARRAY OF CHAR; pos: INTEGER; VAR len: INTEGER); AckCI*: PROCEDURE (f: FSM; VAR p: ARRAY OF CHAR; pos, len: INTEGER): BOOLEAN; NakCI*: PROCEDURE (f: FSM; VAR p: ARRAY OF CHAR; pos, len: INTEGER): BOOLEAN; RejCI*: PROCEDURE (f: FSM; VAR p: ARRAY OF CHAR; pos, len: INTEGER): BOOLEAN; ReqCI*: PROCEDURE (f: FSM; VAR p: ARRAY OF CHAR; VAR pos, len: INTEGER; mode: BOOLEAN): SHORTINT; Up*: PROCEDURE (f: FSM); Down*: PROCEDURE (f: FSM); (* Starting*: PROCEDURE (f: FSM); *) (* Finished*: PROCEDURE (f: FSM); *) ExtCode*: PROCEDURE (f: FSM; code, id:SHORTINT; VAR inp: ARRAY OF CHAR; pos, len: INTEGER): BOOLEAN; HDLCConfig*: HDLC.PPPUnit; params: Params; END; ParamsDesc = RECORD (HDLC.ParamsDesc) f:FSM END; String* = ARRAY StrLen OF CHAR; VAR ActTimeout*:LONGINT; ActMaxConfReqs*:INTEGER; PROCEDURE ^ Init* (f: FSM); PROCEDURE ^ LowerUp* (f: FSM); PROCEDURE ^ LowerDown* (f: FSM); PROCEDURE ^ Open* (f: FSM); PROCEDURE ^ Close* (f: FSM); PROCEDURE ^ Timeout (params: HDLC.Params); PROCEDURE ^ Input* (f: FSM; VAR p: ARRAY OF CHAR; pos, len: INTEGER); PROCEDURE ^ ReceiveConfReq* (f: FSM; id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); PROCEDURE ^ ReceiveConfAck* (f: FSM; id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); PROCEDURE ^ ReceiveConfNakRej* (f: FSM; code, id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); PROCEDURE ^ ReceiveTermReq* (f: FSM; id: SHORTINT); PROCEDURE ^ ReceiveTermAck* (f: FSM); PROCEDURE ^ ReceiveCodeRej* (f: FSM; VAR p: ARRAY OF CHAR; pos, len: INTEGER); PROCEDURE ^ ProtReject* (f: FSM); PROCEDURE ^ SendConfReq* (f: FSM; retransmit: BOOLEAN); PROCEDURE ^ SendData* (f: FSM; code, id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); PROCEDURE OutLog* (text1, text2:ARRAY OF CHAR; f:FSM) ; BEGIN Debug.String(text1); Debug.Ln; IF text2 # "" THEN Debug.String(text2); Debug.Ln; END; Debug.String("protocol: "); Debug.String(f.ProtoName); Debug.String(" - channel: "); Debug.String(f.HDLCConfig.cname); Debug.Ln; END OutLog; PROCEDURE OutCode* (code: SHORTINT); BEGIN Debug.String("code: "); CASE code OF ConfReq: Debug.String("ConfReq") | ConfAck: Debug.String("ConfAck") | ConfNak: Debug.String("ConfNak") | ConfRej: Debug.String("ConfRej") | TermReq: Debug.String("TermReq") | TermAck: Debug.String("TermAck") | CodeRej: Debug.String("CodeRej") | ProtRej: Debug.String("ProtocolRej") | EchoReply: Debug.String("EchoReply") ELSE Debug.String("*** illegal code ***"); Debug.Int(code, 4); END; Debug.Ln END OutCode; PROCEDURE GiveState*(state: SHORTINT; VAR s: String); BEGIN CASE state OF Initial: s:="Initial"; | Starting: s:="Starting"; | Closed: s:="Closed"; | Stopped: s:="Stopped"; | Closing: s:="Closing"; | Stopping: s:="Stopping"; | ReqSent: s:="ReqSent"; | AckRcvd: s:="AckRcvd"; | AckSent: s:="AckSent"; | Opened: s:="Opened"; ELSE s:=" *** unknown state ***"; END; END GiveState; PROCEDURE OutState* (state: SHORTINT); VAR s: String; BEGIN Debug.String("state: "); GiveState(state, s); Debug.String(s); Debug.Ln END OutState; (* Init FSM *) PROCEDURE Init* (f: FSM); BEGIN f.State := Initial; f.Flags := {}; f.ID := 0; (* f.reqID set later *) f.TimeoutTime := ActTimeout; f.MaxConfReqTransmits := ActMaxConfReqs; f.MaxTermTransmits := DefMaxTermReqs; f.MaxNakLoops := DefMaxNakLoops; NEW(f.params); f.params.f:=f; END Init; (* The lower layer is up *) PROCEDURE LowerUp* (f: FSM); BEGIN IF HDLC.debug THEN OutLog("FSM.LowerUp","",f); OutState(f.State); Debug.Ln; END; CASE f.State OF Initial: f.State := Closed | Starting: IF Silent IN f.Flags THEN f.State := Stopped ELSE SendConfReq(f, newtransmit); f.State := ReqSent (* send an initial configure-request *) END ELSE OutLog("FSM.LowerUp","ERROR: in wrong state",f); OutState(f.State); Debug.Ln; END END LowerUp; (* The lower layer is down - cancel all timeouts and inform upper layers *) PROCEDURE LowerDown* (f: FSM); BEGIN IF HDLC.debug THEN OutLog("FSM.LowerDown","",f); OutState(f.State); Debug.Ln; END; CASE f.State OF Closed: f.State := Initial | Stopped: f.State := Starting (* ; f.Starting (f) *) | Closing: f.State := Initial; HDLC.UNTIMEOUT(f.HDLCConfig, Timeout) (* cancel timeout *) | Stopping, ReqSent, AckRcvd, AckSent: f.State := Starting; HDLC.UNTIMEOUT(f.HDLCConfig, Timeout) (* cancel timeout *) | Opened: f.Down(f); f.State := Starting ELSE OutLog("FSM.LowerDown", "ERROR: in wrong state", f); OutState(f.State); Debug.Ln END END LowerDown; (* Link is allowed to come up *) PROCEDURE Open* (f: FSM); BEGIN IF HDLC.debug THEN OutLog("FSM.Open","",f); OutState(f.State); Debug.Ln; END; CASE f.State OF Initial: f.State := Starting; (* f.Starting(f) *) | Closed: IF Silent IN f.Flags THEN f.State := Stopped ELSE SendConfReq(f, newtransmit); f.State := ReqSent; (* send an initial configure-request *) END | Closing: f.State := Stopping; IF Restart IN f.Flags THEN LowerDown(f); LowerUp(f) END | Stopped, Opened: IF Restart IN f.Flags THEN LowerDown(f); LowerUp(f) END ELSE END END Open; (* Start closing connection *) PROCEDURE Close* (f: FSM); VAR p: ARRAY HDLC.ArrayLength OF CHAR; BEGIN IF HDLC.debug THEN OutLog("FSM.Close","",f); OutState(f.State); Debug.Ln; END; CASE f.State OF Starting: f.State := Initial | Stopped: f.State := Closed | Stopping: f.State := Closing | ReqSent, AckRcvd, AckSent, Opened: IF f.State # Opened THEN HDLC.UNTIMEOUT(f.HDLCConfig, Timeout) (* cancel timeout *) ELSE f.Down(f) (* inform upper layers we're down *) END; f.Retransmits := f.MaxTermTransmits; INC(f.ID); f.reqID := f.ID; SendData(f, TermReq, f.reqID, p, StartPos, 4); HDLC.TIMEOUT(f.HDLCConfig, Timeout, f.params, f.TimeoutTime); DEC(f.Retransmits); f.State := Closing ELSE END END Close; (* Timeout expired *) PROCEDURE Timeout (params: HDLC.Params); VAR f: FSM; BEGIN f := params(Params).f; IF HDLC.debug THEN OutLog("FSM.TimeOut","TimeOut-Handler called",f); OutState(f.State); Debug.Ln; END; CASE f.State OF Closing, Stopping: IF f.Retransmits <= 0 THEN (* we've waited for an ack long enough, peer probably heard us *) IF f.State = Closing THEN f.State := Closed ELSE f.State := Stopped END; (* f.Finished(f) *) ELSE (* send terminate-request *) INC(f.ID); f.reqID := f.ID; SendData(f, TermReq, f.reqID, f.HDLCConfig.data2, StartPos, 0); HDLC.TIMEOUT(f.HDLCConfig, Timeout, params, f.TimeoutTime); DEC(f.Retransmits) END | ReqSent, AckRcvd, AckSent: IF f.Retransmits <= 0 THEN OutLog("LOG: FSM.Timeout", "Stop: sended all TimeOuts, no answer", f); Debug.Ln; f.State := Stopped; (* IF ~(Passive IN f.Flags) THEN f.Finished(f) END *) ELSE (* retransmit the configure-request *) SendConfReq(f, retransmit); IF f.State = AckRcvd THEN f.State := ReqSent END END ELSE IF HDLC.debug THEN OutLog("FSM.Timeout", "ERROR:in wrong state", f); OutState(f.State); Debug.Ln; END END END Timeout; (* Input packet *) PROCEDURE Input* (f: FSM; VAR p: ARRAY OF CHAR; pos, len: INTEGER); VAR code, id: SHORTINT; size: INTEGER; BEGIN (* parse header (code, id and length). if packet too short, drop it. *) IF HDLC.debug THEN (* pe: "FSM.ReceiveData" was followed by redundant report "new Input". *) OutLog("FSM.ReceiveData","",f); OutState(f.State); Debug.Ln; Tools.OutPacket(p, pos, len); Debug.Ln; END; IF len < HeaderLen THEN IF HDLC.debug THEN OutLog("FSM.ReceiveData", "ERROR: Received short header", f); END; RETURN END; code := SHORT(ORD(p[pos])); id := SHORT(ORD(p[pos + 1])); size := Tools.GetInt(p, pos + 2); IF size < HeaderLen THEN IF HDLC.debug THEN OutLog("FSM.ReceiveData", "ERROR: Received illegal length", f); END; RETURN END; IF size < len THEN IF HDLC.debug THEN OutLog("FSM.ReceiveData", "ERROR: Received short packet", f); END; RETURN END; DEC(size, HeaderLen); INC(pos, HeaderLen); IF (f.State = Initial) OR (f.State = Starting) THEN IF HDLC.debug THEN OutLog("FSM.ReceiveData", "ERROR: Received packet in wrong state", f); OutState(f.State); Debug.Ln; END; RETURN END; (* action depends on code *) CASE code OF ConfReq: ReceiveConfReq(f, id, p, pos, size) | ConfAck: ReceiveConfAck(f, id, p, pos, size) | ConfNak, ConfRej: ReceiveConfNakRej(f, code, id, p, pos, size) | TermReq: ReceiveTermReq(f, id) | TermAck: ReceiveTermAck(f) | CodeRej: ReceiveCodeRej(f, p, pos, size) ELSE IF ~f.ExtCode(f, code, id, p, pos, size) THEN INC(f.ID); SendData(f, CodeRej, f.ID, p, pos - HeaderLen, size + HeaderLen) END END END Input; (* Receive Configure-Request *) PROCEDURE ReceiveConfReq* (f: FSM; id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); VAR code: SHORTINT; RejectIfDisagree: BOOLEAN; BEGIN IF HDLC.debug THEN OutLog("FSM.ReceiveConfigureRequest", "", f); Debug.String("id: "); Debug.Int(id, 4); Debug.Ln; Debug.Ln END; CASE f.State OF Closed: SendData(f, TermAck, id, p, StartPos, 0); RETURN (* go away, we're closed *) | Closing, Stopping: RETURN | Opened: f.Down(f); SendConfReq(f, newtransmit) (* go down and restart negotiation, inform upper layers, send initial configure-request *) | Stopped: SendConfReq(f, newtransmit); f.State := ReqSent; (* send initial configure-request *) ELSE END; (* pass the requested configuration options to protocol-specific code for checking *) RejectIfDisagree := f.NakLoops >= f.MaxNakLoops; code := f.ReqCI(f, p, pos, len, RejectIfDisagree); (* send the Ack, Nak or Rej to the peer *) SendData(f, code, id, p, pos, len); IF code = ConfAck THEN IF f.State = AckRcvd THEN HDLC.UNTIMEOUT(f.HDLCConfig, Timeout); f.State := Opened; f.Up(f) ELSE f.State := AckSent; f.NakLoops := 0 END ELSE (* we sent ConfAck or ConfRej *) IF f.State # AckRcvd THEN f.State := ReqSent END; IF code = ConfNak THEN INC(f.NakLoops) END; END END ReceiveConfReq; (* Receive Configure-Ack *) PROCEDURE ReceiveConfAck* (f: FSM; id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); BEGIN IF HDLC.debug THEN OutLog("FSM.ReceiveConfAck", "", f); Debug.String("id: "); Debug.Int(id, 4); Debug.Ln; Debug.Ln END; IF (id=f.reqID) & f.AckCI(f, p, pos, len) THEN f.reqID := -1; CASE f.State OF Closed, Stopped: SendData(f, TermAck, id, p, StartPos, 0) | ReqSent: f.State := AckRcvd; f.Retransmits := f.MaxConfReqTransmits | AckRcvd: SendConfReq(f, newtransmit); f.State := ReqSent (* huh?, an extra Ack? oh well... *) | AckSent: HDLC.UNTIMEOUT(f.HDLCConfig, Timeout); (* cancel timeout *) f.State := Opened; f.Retransmits := f.MaxConfReqTransmits; f.Up(f) | Opened: (* go down and restart negotiation *) f.Down(f); SendConfReq(f, newtransmit); f.State := ReqSent ELSE END END END ReceiveConfAck; (* Receive Configure-Nak or Configure-Reject *) PROCEDURE ReceiveConfNakRej* (f: FSM; code, id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); BEGIN IF HDLC.debug THEN OutLog("FSM.ReceiveConfigureNak/Reject", "", f); Debug.String("id = "); Debug.Int(id, 4); Debug.String(", reqID = "); Debug.Int(f.reqID, 4); Debug.Ln; Debug.Ln END; IF id # f.reqID THEN RETURN END; (* expected ID? nope -> toss... *) IF ((code = ConfNak) & ~f.NakCI(f, p, pos, len)) OR ((code=ConfRej) & ~f.RejCI(f, p, pos, len)) THEN (* Nak/Reject is bad - ignore it *) IF HDLC.debug THEN OutLog("FSM.ReceiveConfNakRej", "ERROR: Received bad Nak/Rej", f); Debug.String("id: "); Debug.Int(f.ID, 4); Debug.Ln; OutCode(code); Debug.Ln; RETURN END END; f.reqID := -1; CASE f.State OF Closed, Stopped: SendData(f, TermAck, id, p, StartPos, 0) | ReqSent, AckSent: HDLC.UNTIMEOUT(f.HDLCConfig, Timeout); SendConfReq(f, newtransmit) (* They didn't agree to what we wanted - try another request *) (*(*pe*) SendConfReq(f, retransmit) *) | AckRcvd: SendConfReq(f, newtransmit); f.State := ReqSent (* got a Nak/Reject when we had already had an Ack?? oh well... *) | Opened: (* go down and restart negotiation *) f.Down(f); SendConfReq(f, newtransmit); f.State := ReqSent ELSE END END ReceiveConfNakRej; (* Receive Terminate-Request *) PROCEDURE ReceiveTermReq* (f: FSM; id: SHORTINT); VAR p: ARRAY HDLC.ArrayLength OF CHAR; BEGIN IF HDLC.debug THEN OutLog("FSM.ReceiveTermReq", "", f); Debug.String("id: "); Debug.Int(id, 4); Debug.Ln; Debug.Ln END; CASE f.State OF AckRcvd, AckSent: f.State := ReqSent | Opened: OutLog("FSM.ReceiveTermReq", "Terminated at peer's request", f); f.Down(f); f.Retransmits := 0; f.State := Stopping; HDLC.TIMEOUT(f.HDLCConfig, Timeout, f.params, f.TimeoutTime) ELSE END; SendData(f, TermAck, id, p, StartPos, 0) END ReceiveTermReq; (* Receive Terminate-Ack *) PROCEDURE ReceiveTermAck* (f: FSM); BEGIN IF HDLC.debug THEN OutLog("FSM.ReceiveTermAck", "", f); Debug.Ln; END; CASE f.State OF Closing: f.State := Closed (* ; IF f.Finished # NIL THEN f.Finished(f) END *) | Stopping: f.State := Stopped (* ; IF f.Finished # NIL THEN f.Finished(f) END *) | AckRcvd: f.State := ReqSent | Opened: f.Down(f); SendConfReq(f, newtransmit) ELSE END END ReceiveTermAck; (* Receive a Code-Reject *) PROCEDURE ReceiveCodeRej* (f: FSM; VAR p: ARRAY OF CHAR; pos, len: INTEGER); VAR code, id: SHORTINT; BEGIN IF len < HeaderLen THEN IF HDLC.debug THEN OutLog("FSM.ReceiveCodeRej", "ERROR: too short", f); Debug.Ln; END; RETURN END; code := SHORT(ORD(p[pos])); id := SHORT(ORD(p[pos + 1])); (* syslog *) IF HDLC.debug THEN OutLog("FSM.ReceiveCodeRej", "Received Code-Reject", f); OutCode(code); Debug.String("id: "); Debug.Int(id, 4); Debug.Ln; Debug.Ln; END; IF f.State = AckRcvd THEN f.State := ReqSent END END ReceiveCodeRej; (* Peer doesn't speak this protocol - Treat this as a catastrophic error (RXJ-)*) PROCEDURE ProtReject* (f: FSM); VAR p: ARRAY HDLC.ArrayLength OF CHAR; BEGIN IF HDLC.debug THEN OutLog("FSM.ProtReject", "", f); Debug.Ln; END; CASE f.State OF Closing: HDLC.UNTIMEOUT(f.HDLCConfig, Timeout); f.State := Closed; (* IF f.Finished # NIL THEN f.Finished(f) END *) | Closed: f.State := Closed; (* IF f.Finished # NIL THEN f.Finished(f) END *) | Stopping, ReqSent, AckRcvd, AckSent: HDLC.UNTIMEOUT(f.HDLCConfig, Timeout); f.State := Stopped (* ; IF f.Finished # NIL THEN f.Finished(f) END *) | Stopped: f.State := Stopped (* IF f.Finished # NIL THEN f.Finished(f) END *) | Opened: f.Down(f); (* init restart counter, send terminate-request *) f.Retransmits := f.MaxTermTransmits; INC(f.ID); f.reqID := f.ID; SendData(f, TermReq, f.reqID, p, StartPos, 0); HDLC.TIMEOUT(f.HDLCConfig, Timeout, f.params, f.TimeoutTime); DEC(f.Retransmits); f.State := Stopping ELSE IF HDLC.debug THEN OutLog("FSM.ProtReject", "ERROR: in wrong state", f); OutState(f.State); Debug.Ln END END END ProtReject; (* Send a Configure-Request *) PROCEDURE SendConfReq* (f: FSM; retransmit: BOOLEAN); VAR pos: INTEGER; CILen: INTEGER; p: ARRAY HDLC.ArrayLength OF CHAR; BEGIN IF (f.State # ReqSent) & (f.State # AckRcvd) & (f.State # AckSent) THEN (* not currently negotiating - reset options *) f.ResetCI(f); f.NakLoops := 0 END; IF retransmit THEN (* new request - reset transmission counter, use new ID *) f.Retransmits := f.MaxConfReqTransmits; INC(f.ID); f.reqID := f.ID END; IF HDLC.debug THEN OutLog("FSM.SendConfReq", "", f); Debug.String("id: "); Debug.Int(f.reqID, 4); Debug.String(" "); OutState(f.State); Debug.Ln END; (* make up a request packet *) pos := StartPos; IF f.CILen(f) < f.HDLCConfig.MTU - HeaderLen THEN f.AddCI(f, p, pos, CILen) ELSE OutLog("FSM.SendConfReq", "ERROR: Configure Request too big", f); RETURN END; (* send the request to our peer *) SendData(f, ConfReq, f.reqID, p, pos, CILen); (* start the retransmit timer *) DEC(f.Retransmits); HDLC.TIMEOUT(f.HDLCConfig, Timeout, f.params, f.TimeoutTime); END SendConfReq; (* SendData - Create a packet with code, id and data, data is in p[pos .. pos+len] *) PROCEDURE SendData* (f: FSM; code, id: SHORTINT; VAR p: ARRAY OF CHAR; pos, len: INTEGER); VAR minpos, maxlen: INTEGER; BEGIN maxlen:=f.HDLCConfig.MTU - HeaderLen; IF len > maxlen THEN len := maxlen; END; (* adjust length (of information + padding) to be smaller than MTU *) minpos:=HDLC.HDLCHeaderLen+HeaderLen; IF pos<minpos THEN Tools.CopyString(p, pos, minpos, len); pos:=minpos; END; DEC(pos, HeaderLen); INC(len, HeaderLen); p[pos]:=CHR(code); p[pos+1]:=CHR(id); Tools.PutInt(len, p, pos+2); IF HDLC.debug THEN OutLog("FSM.SendData", "", f); OutCode(code); OutState(f.State); Debug.String("id: "); Debug.Int(id, 4); Debug.Ln; Tools.OutPacket(p, pos, len); Debug.Ln; END; HDLC.SendPacket(f.HDLCConfig, f.Protocol, p, pos, len); END SendData; BEGIN ActTimeout:=DefTimeout; ActMaxConfReqs:=DefMaxConfReqs END PPPFSM.