|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 |
|
17 #include "PPPLCP.H" |
|
18 #include "PPPBASE.H" |
|
19 #include "PPPLOG.H" |
|
20 #include "ncpip.h" |
|
21 #include "PPPCCP.H" // for KPppIdCcp |
|
22 #include <es_ini.h> |
|
23 |
|
24 // |
|
25 // PPP State machine |
|
26 // |
|
27 |
|
28 MPppFsm::MPppFsm(CPppLcp* aPppLcp, TPppPhase aPhase, TUint aPppId) |
|
29 : MPppRecvr(aPppLcp, aPhase, aPppId), |
|
30 // Values may be initialized via .ini file, but unless specified otherwise: |
|
31 iTerminateRequestEnabled(ETrue), // RFC-compliant termination phase (TerminateRequest) is enabled |
|
32 iTerminateAckEnabled(ETrue), // RFC-compliant termination phase (TerminateAck) is enabled |
|
33 iFsmTerminationCauseError(KErrNone), |
|
34 iMaxTerminateRequest(KPppFsmTerminateRequestRetries), // Wait after Sending TerminateRequest |
|
35 iTerminateRequestTimeout(KPppFsmTerminateRequestTimeout), // Wait for TerminateAck after sending TerminateRequest |
|
36 iTerminateAckTimeout(KPppFsmTerminateAckTimeout), // Wait after sending TerminateAck |
|
37 iFsmTermination(EFalse), |
|
38 iNoEvidenceOfPeer(EFalse), |
|
39 iWaitTimeNoIncrease(EFalse) |
|
40 { |
|
41 } |
|
42 |
|
43 MPppFsm::~MPppFsm() |
|
44 { |
|
45 TimerDelete(); |
|
46 if (!iRequestList.IsEmpty()) |
|
47 iRequestList.Free(); |
|
48 } |
|
49 |
|
50 void MPppFsm::FsmConstructL() |
|
51 /** |
|
52 Construct the state machine object |
|
53 */ |
|
54 { |
|
55 ReadIniFileL(); |
|
56 // Dump the configuration resulting from the .ini file: |
|
57 |
|
58 LOG(iPppLcp->iLogger->Printf(_L("%s FSM: TerminateRequestEnabled[%d], MaxTerminateRequest[%d], TerminateRequestTimeout[%d]"),\ |
|
59 __iFsmName, |
|
60 iTerminateRequestEnabled, |
|
61 iMaxTerminateRequest, |
|
62 iTerminateRequestTimeout);) |
|
63 |
|
64 LOG(iPppLcp->iLogger->Printf(_L("%s FSM: TerminateAckEnabled[%d], TerminateAckTimeout[%d]"),\ |
|
65 __iFsmName, |
|
66 iTerminateAckEnabled, |
|
67 iTerminateAckTimeout);) |
|
68 |
|
69 TimerConstructL(KPppFsmTimerPriority); |
|
70 } |
|
71 |
|
72 void MPppFsm::TerminateLink() |
|
73 /** |
|
74 Tear down the protocol, regardless of the state of the FSM. |
|
75 */ |
|
76 { |
|
77 // Support for Termination Phase. |
|
78 // This is not according to the RFC, but it is done to avoid |
|
79 // any regressions in the existing PPP. |
|
80 switch(iState) |
|
81 { |
|
82 case EPppFsmStopping: // We have received TerminateRequest, sent TerminateAck and |
|
83 // are waiting for one timeout to expire. |
|
84 break; // Stay in EPppFsmStopping state |
|
85 default: |
|
86 SendInitialTerminateRequest(); |
|
87 SetState(EPppFsmClosing); |
|
88 } |
|
89 } |
|
90 |
|
91 // |
|
92 // Open/Close calls from higher level protocols |
|
93 // |
|
94 |
|
95 TInt MPppFsm::FsmOpen() |
|
96 /** |
|
97 Begin the state machine and protocol. |
|
98 Called by the derived class during initialization. |
|
99 |
|
100 @return KErrNone if successful, otherwise one of the system-wide error codes |
|
101 */ |
|
102 { |
|
103 LOG( iPppLcp->iLogger->Printf(_L("%s FSM Open Request"), __iFsmName); ) |
|
104 TInt err = KErrNone; |
|
105 |
|
106 InitMaxFailure(); |
|
107 |
|
108 switch (iState) |
|
109 { |
|
110 case EPppFsmInitial: |
|
111 err = FsmLayerStarted(); |
|
112 SetState(EPppFsmStarting); |
|
113 break; |
|
114 case EPppFsmStarting: |
|
115 break; |
|
116 case EPppFsmClosed: |
|
117 err = FsmLayerStarted(); |
|
118 SendInitialConfigRequest(); |
|
119 SetState(EPppFsmReqSent); |
|
120 break; |
|
121 case EPppFsmStopped: |
|
122 case EPppFsmClosing: |
|
123 case EPppFsmStopping: |
|
124 case EPppFsmOpened: |
|
125 // Check that we *really* want to do this! |
|
126 LowerLayerDown(); |
|
127 LowerLayerUp(); |
|
128 break; |
|
129 case EPppFsmReqSent: |
|
130 case EPppFsmAckRecvd: |
|
131 case EPppFsmAckSent: |
|
132 break; |
|
133 } |
|
134 iPppAbortCode = KErrNone; |
|
135 return err; |
|
136 } |
|
137 |
|
138 void MPppFsm::FsmClose(TInt aReason) |
|
139 /** |
|
140 Close the state machine and protocol. |
|
141 Called by the derived class on closing. |
|
142 |
|
143 @param aReason Reason for closing |
|
144 */ |
|
145 { |
|
146 LOG( iPppLcp->iLogger->Printf(_L("%s FSM Close Request, error[%d]"), __iFsmName, aReason); ) |
|
147 switch (iState) |
|
148 { |
|
149 case EPppFsmInitial: |
|
150 case EPppFsmClosed: |
|
151 case EPppFsmClosing: |
|
152 break; |
|
153 case EPppFsmStarting: |
|
154 FsmLayerFinished(); |
|
155 SetState(EPppFsmInitial); |
|
156 break; |
|
157 case EPppFsmStopped: |
|
158 SetState(EPppFsmClosed); |
|
159 break; |
|
160 case EPppFsmStopping: |
|
161 SetState(EPppFsmClosing); |
|
162 break; |
|
163 case EPppFsmOpened: |
|
164 FsmLayerDown(aReason); |
|
165 // continue into next statement |
|
166 case EPppFsmReqSent: |
|
167 case EPppFsmAckRecvd: |
|
168 case EPppFsmAckSent: |
|
169 SendInitialTerminateRequest(); |
|
170 SetState(EPppFsmClosing); |
|
171 break; |
|
172 } |
|
173 } |
|
174 |
|
175 void MPppFsm::FsmAbort(TInt aReason) |
|
176 /** |
|
177 Abort the protocol. |
|
178 |
|
179 @param aReason Reason for aborting |
|
180 */ |
|
181 // 29.11.00. Changed slightly so that this does the same as RXJ- |
|
182 // in the PPP RFC for all states. |
|
183 { |
|
184 LOG( iPppLcp->iLogger->Printf(_L("%s FSM Abort Request, error[%d]"), __iFsmName, aReason); ) |
|
185 switch (iState) |
|
186 { |
|
187 case EPppFsmInitial: |
|
188 case EPppFsmStarting: |
|
189 // bad event |
|
190 break; |
|
191 case EPppFsmClosed: |
|
192 case EPppFsmStopped: |
|
193 FsmLayerFinished(); |
|
194 break; |
|
195 case EPppFsmClosing: |
|
196 FsmLayerFinished(); |
|
197 SetState(EPppFsmClosed); |
|
198 break; |
|
199 case EPppFsmStopping: |
|
200 FsmLayerFinished(); |
|
201 SetState(EPppFsmStopped); |
|
202 break; |
|
203 case EPppFsmOpened: |
|
204 FsmLayerDown(); |
|
205 SendInitialTerminateRequest(); |
|
206 SetState(EPppFsmStopping); |
|
207 break; |
|
208 case EPppFsmReqSent: |
|
209 case EPppFsmAckRecvd: |
|
210 case EPppFsmAckSent: |
|
211 FsmLayerFinished(aReason); |
|
212 SetState(EPppFsmStopped); |
|
213 break; |
|
214 } |
|
215 iPppAbortCode = aReason; |
|
216 } |
|
217 |
|
218 |
|
219 |
|
220 // |
|
221 // Upcall from Timer |
|
222 // |
|
223 |
|
224 EXPORT_C void MPppFsm::TimerComplete(TInt /*aStatus*/) |
|
225 /** |
|
226 Called by MTimer on timer expiry. |
|
227 |
|
228 @param aStatus Aynchronous request completion status (ignored) |
|
229 */ |
|
230 { |
|
231 LOG( iPppLcp->iLogger->Printf(_L("%s FSM Timer Expired %d "), __iFsmName, iRestartCount); ) |
|
232 |
|
233 switch (iState) |
|
234 { |
|
235 case EPppFsmInitial: |
|
236 case EPppFsmStarting: |
|
237 case EPppFsmClosed: |
|
238 case EPppFsmStopped: |
|
239 case EPppFsmOpened: |
|
240 // Bad Event |
|
241 return; |
|
242 default: |
|
243 break; |
|
244 } |
|
245 |
|
246 if (iRestartCount>0) |
|
247 { |
|
248 switch (iState) |
|
249 { |
|
250 case EPppFsmClosing: |
|
251 case EPppFsmStopping: |
|
252 SendTerminateRequest(); |
|
253 break; |
|
254 case EPppFsmReqSent: |
|
255 case EPppFsmAckRecvd: |
|
256 case EPppFsmAckSent: |
|
257 //PG RFC 1661 4.6 double timeout period |
|
258 // Allow for configuration of non-doubling of timeout period (initially for |
|
259 // conformance testing) - default behaviour is for doubling to occur. |
|
260 if (!iWaitTimeNoIncrease && iWaitTime*2 < KPppFsmRequestMaxTimeout) |
|
261 { |
|
262 iWaitTime = iWaitTime * 2; |
|
263 } |
|
264 SendConfigRequest(); |
|
265 if(iState == EPppFsmAckRecvd) |
|
266 SetState(EPppFsmReqSent); |
|
267 break; |
|
268 default: |
|
269 break; |
|
270 } |
|
271 } |
|
272 else |
|
273 { |
|
274 switch(iState) |
|
275 { |
|
276 case EPppFsmClosing: // We sent out TerminateRequests, no TerminateAcks received. |
|
277 FsmLayerFinished(iFsmTerminationCauseError); // Authoritative Close of the Link --> KErrCancel |
|
278 break; |
|
279 case EPppFsmStopping: // We've sent TerminateAck and waited one restart period |
|
280 FsmLayerFinished(iFsmTerminationCauseError); // Peer initiated disconnection. |
|
281 break; |
|
282 default: |
|
283 // Don't abort if we're configured to persist. |
|
284 if(!iPersist) |
|
285 { |
|
286 iFsmTermination = ETrue; // Used later to bring down the FSM as opposed to restarting it. |
|
287 FsmLayerFinished(KErrTimedOut); |
|
288 } |
|
289 else |
|
290 { |
|
291 LOG( iPppLcp->iLogger->Printf(_L("%s FSM going idle"), __iFsmName); ) |
|
292 } |
|
293 break; |
|
294 } |
|
295 |
|
296 switch (iState) |
|
297 { |
|
298 case EPppFsmClosing: |
|
299 SetState(EPppFsmClosed); |
|
300 break; |
|
301 case EPppFsmStopping: |
|
302 case EPppFsmReqSent: |
|
303 case EPppFsmAckRecvd: |
|
304 case EPppFsmAckSent: |
|
305 SetState(EPppFsmStopped); |
|
306 break; |
|
307 case EPppFsmInitial: |
|
308 case EPppFsmStarting: |
|
309 case EPppFsmClosed: |
|
310 case EPppFsmStopped: |
|
311 case EPppFsmOpened: |
|
312 default: |
|
313 break; |
|
314 } |
|
315 } |
|
316 } |
|
317 |
|
318 // |
|
319 // Upcalls from Recvr |
|
320 // |
|
321 |
|
322 EXPORT_C void MPppFsm::LowerLayerUp() |
|
323 /** |
|
324 Called when the lower layer protocol has come up. |
|
325 */ |
|
326 { |
|
327 LOG( iPppLcp->iLogger->Printf(_L("%s FSM Up Event"), __iFsmName); ) |
|
328 switch (iState) |
|
329 { |
|
330 case EPppFsmInitial: |
|
331 SetState(EPppFsmOpened); |
|
332 break; |
|
333 case EPppFsmStarting: |
|
334 SendInitialConfigRequest(); |
|
335 SetState(EPppFsmReqSent); |
|
336 break; |
|
337 case EPppFsmClosed: |
|
338 case EPppFsmStopped: |
|
339 case EPppFsmClosing: |
|
340 case EPppFsmStopping: |
|
341 case EPppFsmReqSent: |
|
342 case EPppFsmAckRecvd: |
|
343 case EPppFsmAckSent: |
|
344 case EPppFsmOpened: |
|
345 // Bad Event |
|
346 break; |
|
347 } |
|
348 } |
|
349 |
|
350 |
|
351 EXPORT_C void MPppFsm::LowerLayerDown(TInt aStatus) |
|
352 /** |
|
353 Signals the Down event. |
|
354 Called when the lower layer protocol has gone down. |
|
355 This means that our layer can no longer receive or transmit anything. |
|
356 |
|
357 In case of LCP, this means that the physical link is closed (e.g. Peer dropped DTR) |
|
358 If we are LCP, this may mean that PPP is finished, because the link is no longer available. |
|
359 |
|
360 @param aStatus Error code indicating the reason the layer is going down |
|
361 */ |
|
362 { |
|
363 LOG( iPppLcp->iLogger->Printf(_L("%s FSM Down Event, error[%d]"), __iFsmName, aStatus); ) |
|
364 |
|
365 switch (iState) |
|
366 { |
|
367 case EPppFsmInitial: |
|
368 // Bad Event |
|
369 break; |
|
370 case EPppFsmStarting: |
|
371 FsmLayerDown(aStatus); |
|
372 break; |
|
373 case EPppFsmClosed: |
|
374 SetState(EPppFsmInitial); |
|
375 break; |
|
376 case EPppFsmClosing: // We are waiting for Terminate Ack (or TerminateRequest retransmission) |
|
377 SetState(EPppFsmInitial); |
|
378 break; |
|
379 case EPppFsmStopped: |
|
380 if(!iFsmTermination) // We are not terminating, so we restart the FSM. |
|
381 { |
|
382 FsmLayerStarted(); |
|
383 SetState(EPppFsmStarting); |
|
384 return; // The alternative is calling FsmTerminationPhaseComplete from every case. |
|
385 } |
|
386 // If we are terminating, we terminate the FSM and notify Nifman that the NIF is finished. |
|
387 SetState(EPppFsmStarting); |
|
388 break; |
|
389 case EPppFsmStopping: // We are waiting 1 restart period after transmitting Terminate Ack |
|
390 SetState(EPppFsmStarting); |
|
391 break; |
|
392 case EPppFsmReqSent: |
|
393 case EPppFsmAckRecvd: |
|
394 case EPppFsmAckSent: |
|
395 FsmLayerDown(aStatus); |
|
396 SetState(EPppFsmStarting); |
|
397 break; |
|
398 case EPppFsmOpened: |
|
399 FsmLayerDown(aStatus); |
|
400 SetState(EPppFsmStarting); |
|
401 break; |
|
402 } |
|
403 // This call is critical to make sure PPP reports its demise correctly. Otherwise, Nifman remains unaware, and |
|
404 // ESock / Nifman / PPP hangs. |
|
405 FsmTerminationPhaseComplete(); // ASSUMPTION: LCP signals to Nifman. Others do nothing. |
|
406 // Note: early return from EPppFsmStopped. |
|
407 } |
|
408 |
|
409 EXPORT_C void MPppFsm::FrameError() |
|
410 /** |
|
411 Called when a bad frame is received. |
|
412 No action is currently taken. |
|
413 |
|
414 @see RecvFrame() is called instead when a good frame is received |
|
415 */ |
|
416 { |
|
417 return; |
|
418 } |
|
419 |
|
420 EXPORT_C void MPppFsm::KillProtocol() |
|
421 /** |
|
422 Called when the lower level protocol is killed. |
|
423 */ |
|
424 { |
|
425 // |
|
426 // This came to light as a result of the CCP work |
|
427 // This happens if a protocol is told to shut down, |
|
428 // I'm not sure how to handle it?? Do we just Stop it??? |
|
429 // |
|
430 return; |
|
431 } |
|
432 |
|
433 EXPORT_C TBool MPppFsm::RecvFrame(RMBufChain& aPacket) |
|
434 /** |
|
435 Receives and processes a PPP frame. |
|
436 Called by CPppLcp. |
|
437 |
|
438 @see FrameError() is called instead when a bad frame is received |
|
439 |
|
440 @param aPacket MBuf chain containing packet |
|
441 |
|
442 @return EFalse |
|
443 */ |
|
444 { |
|
445 RMBufPacket pkt; |
|
446 pkt.Assign(aPacket); |
|
447 pkt.Unpack(); |
|
448 RMBufPktInfo* info = pkt.Info(); |
|
449 |
|
450 TUint8 op; |
|
451 TUint8 id; |
|
452 TInt len; |
|
453 |
|
454 // Extract and drop LCP header |
|
455 pkt.Align(4); |
|
456 TUint8* ptr = pkt.First()->Ptr(); |
|
457 op = *ptr++; |
|
458 id = *ptr++; |
|
459 len = BigEndian::Get16(ptr); |
|
460 |
|
461 // Check packet length is OK |
|
462 if (info->iLength<len || info->iLength<4 ) |
|
463 { |
|
464 // Too short! |
|
465 pkt.Free(); |
|
466 return EFalse; |
|
467 } |
|
468 else if (info->iLength > len) |
|
469 pkt.TrimEnd(len); |
|
470 |
|
471 // Received a potentially valid packet; probably we have a meaningful relationship with peer |
|
472 iNoEvidenceOfPeer = EFalse; |
|
473 // If op is unknown |
|
474 switch (op) |
|
475 { |
|
476 case KPppLcpConfigAck: |
|
477 case KPppLcpConfigNak: |
|
478 case KPppLcpConfigReject: |
|
479 // Filter out bad acks |
|
480 if (iState>=EPppFsmReqSent && id!=iRequestId) |
|
481 break; |
|
482 else |
|
483 iRequestId |= KPppRequestIdAnswered; |
|
484 // fall through ... |
|
485 case KPppLcpConfigRequest: |
|
486 // Option negotiation ops |
|
487 // Split the MBuf chain in separate options |
|
488 |
|
489 //if(len<=4) |
|
490 if(len<4) |
|
491 break; |
|
492 |
|
493 // |
|
494 // Hmmm sometimes we receive a Config request of Length 4 |
|
495 // i.e. no options Send a Config ACK |
|
496 // |
|
497 if ( (len == 4) && (op == KPppLcpConfigRequest)) |
|
498 { |
|
499 if (ProcessEmptyConfigReq()) |
|
500 { |
|
501 if (iPppId == KPppIdCcp) |
|
502 { |
|
503 // For empty CCP Config Requests send a Protocol Reject, |
|
504 // otherwise we can end up continually exchanging empty |
|
505 // Config Requests and Config ACK's. KPppIdLcp is passed to |
|
506 // CPppHdlcLink::Send() via FsmRejectPacket() to ensure |
|
507 // transmission of an *LCP* Protocol Reject of CCP rather than |
|
508 // a *CCP* Protocol Reject of CCP (subtle difference). |
|
509 pkt.Pack(); |
|
510 FsmRejectPacket(pkt, KPppLcpProtocolReject, KPppIdLcp); |
|
511 } |
|
512 else |
|
513 { |
|
514 // Send an acknowledgement |
|
515 ptr = pkt.First()->Ptr(); |
|
516 *ptr = KPppLcpConfigAck; |
|
517 pkt.Pack(); |
|
518 SendFrame(pkt); |
|
519 } |
|
520 } |
|
521 else |
|
522 { |
|
523 break; |
|
524 } |
|
525 } |
|
526 else if (len == 4 && (op != KPppLcpConfigAck && iPppLcp->QueryExternalIPConfiguration())) |
|
527 { |
|
528 // With Mobile IP, there is the possibility of having no options to negotiate, in which |
|
529 // case an empty ConfigReq would be sent out. This would be acknowledged by an empty |
|
530 // ConfigAck, so ensure that we process the latter. |
|
531 break; |
|
532 } |
|
533 else |
|
534 { |
|
535 pkt.TrimStart(4); |
|
536 ProcessConfig(op, id, len-4, pkt); |
|
537 } |
|
538 |
|
539 break; |
|
540 case KPppLcpTerminateAck: |
|
541 // Filter out bad acks |
|
542 if ((iState==EPppFsmClosing || iState==EPppFsmStopping) && id!=iTerminateId) |
|
543 break; |
|
544 else |
|
545 iTerminateId |= KPppRequestIdAnswered; |
|
546 // fall through ... |
|
547 case KPppLcpTerminateRequest: |
|
548 if(len<4) |
|
549 break; |
|
550 |
|
551 pkt.TrimStart(4); |
|
552 ProcessTerminate(op, id, len-4, pkt); |
|
553 break; |
|
554 case KPppLcpCodeReject: |
|
555 case KPppLcpProtocolReject: |
|
556 if(len<=4) |
|
557 break; |
|
558 pkt.TrimStart(4); |
|
559 ProcessReject(op, id, len-4, pkt); |
|
560 break; |
|
561 default: |
|
562 if (!FsmRecvUnknownCode(op, id, len, pkt)) |
|
563 { |
|
564 pkt.Pack(); |
|
565 FsmRejectPacket(pkt); |
|
566 } |
|
567 break; |
|
568 } |
|
569 pkt.Free(); |
|
570 return EFalse; |
|
571 } |
|
572 |
|
573 // |
|
574 // Rest of PPP |
|
575 // |
|
576 |
|
577 TBool MPppFsm::FsmRecvUnknownCode(TUint8 /*aCode*/, TUint8 /*aId*/, TInt /*aLength*/, RMBufChain& /*aPacket*/) |
|
578 /** |
|
579 Handle a received packet with an unknown code. |
|
580 |
|
581 @param aCode Packet code (ignored) |
|
582 @param aId Packet identifier (ignored) |
|
583 @param aLength Length of packet (ignored) |
|
584 @param aPacket MBuf chain containing packet (ignored) |
|
585 |
|
586 @return EFalse |
|
587 */ |
|
588 { |
|
589 return EFalse; |
|
590 } |
|
591 |
|
592 void MPppFsm::ProcessReject(TUint8 aCode, TUint8 /*aId*/, TInt /* aLength */, RMBufChain& aPacket) |
|
593 /** |
|
594 Handle a Code Reject or Protocol Reject. |
|
595 If the reject rejects a code (or protocol) that should |
|
596 be known terminate layer. |
|
597 (Note, As the behaviour of protocol reject is the same |
|
598 as code reject, this function handles protocol reject for LCP) |
|
599 |
|
600 @param aCode Packet code |
|
601 @param aId Packet identifier (ignored) |
|
602 @param aLength Length of packet (ignored) |
|
603 @param aPacket MBuf chain containing packet. |
|
604 */ |
|
605 { |
|
606 TBool isCatastrophic = EFalse; |
|
607 |
|
608 // Valid reject packets should have a len >=4 |
|
609 if(aPacket.Length()<4) |
|
610 return; |
|
611 |
|
612 // Determine if the reject is acceptable |
|
613 if (aCode==KPppLcpProtocolReject) |
|
614 { |
|
615 |
|
616 aPacket.Align(2); |
|
617 TUint prot = BigEndian::Get16(aPacket.First()->Ptr()); |
|
618 aPacket.TrimStart(2); |
|
619 switch (prot) |
|
620 { |
|
621 case KPppIdLcp: |
|
622 isCatastrophic = ETrue; |
|
623 break; |
|
624 |
|
625 case KPppIdCompressedData: |
|
626 // Shut down and unload the current compressor |
|
627 LOG( iPppLcp->iLogger->Printf(_L("Compressed Packet rejected: Unloading compressor.")); ) |
|
628 iPppLcp->PppUnloadCompressor() ; |
|
629 break ; |
|
630 |
|
631 default: |
|
632 { |
|
633 /* |
|
634 * Tut tut the existing code only handled Protocol rejects for the |
|
635 * LCP protocol. What about all the others? |
|
636 */ |
|
637 iFsmTermination = ETrue; // Used later to bring down the FSM as opposed to restarting it. |
|
638 iPppLcp->StopProtocol(prot); |
|
639 break; |
|
640 } |
|
641 } |
|
642 } |
|
643 else |
|
644 { |
|
645 TUint8 code = aPacket.First()->Get(0); |
|
646 switch (code) |
|
647 { |
|
648 case KPppLcpConfigRequest: |
|
649 case KPppLcpConfigAck: |
|
650 case KPppLcpConfigNak: |
|
651 case KPppLcpConfigReject: |
|
652 case KPppLcpTerminateRequest: |
|
653 case KPppLcpTerminateAck: |
|
654 isCatastrophic = ETrue; |
|
655 break; |
|
656 case KPppLcpCodeReject: |
|
657 case KPppLcpProtocolReject: |
|
658 iFsmTermination = ETrue; |
|
659 isCatastrophic = ETrue; |
|
660 break; |
|
661 default: |
|
662 break; |
|
663 } |
|
664 } |
|
665 |
|
666 if (!isCatastrophic) |
|
667 { |
|
668 if (iState==EPppFsmAckRecvd) |
|
669 SetState(EPppFsmReqSent); |
|
670 return; |
|
671 } |
|
672 |
|
673 LOG( iPppLcp->iLogger->Printf(_L("%s Catastrophic Reject, packet code[%d]"), __iFsmName, aCode); ) |
|
674 |
|
675 switch (iState) |
|
676 { |
|
677 case EPppFsmInitial: |
|
678 case EPppFsmStarting: |
|
679 // bad event |
|
680 break; |
|
681 case EPppFsmClosed: |
|
682 case EPppFsmStopped: |
|
683 FsmLayerFinished(); |
|
684 break; |
|
685 case EPppFsmClosing: |
|
686 FsmLayerFinished(); |
|
687 SetState(EPppFsmClosed); |
|
688 break; |
|
689 case EPppFsmStopping: |
|
690 case EPppFsmReqSent: |
|
691 case EPppFsmAckRecvd: |
|
692 case EPppFsmAckSent: |
|
693 FsmLayerFinished(); |
|
694 SetState(EPppFsmStopped); |
|
695 break; |
|
696 case EPppFsmOpened: |
|
697 FsmLayerDown(); |
|
698 SendInitialTerminateRequest(); |
|
699 SetState(EPppFsmStopped); |
|
700 break; |
|
701 } |
|
702 } |
|
703 |
|
704 void MPppFsm::ProcessTerminate(TUint8 aCode, TUint8 aId, TInt /*aLength*/, RMBufChain& /*aPacket*/) |
|
705 /** |
|
706 Handle a Terminate Request packet and cleanly terminate the connection. |
|
707 |
|
708 @param aCode Packet code |
|
709 @param aId Packet identifier |
|
710 @param aLength Length of packet (ignored) |
|
711 @param aPacket MBuf chain containing packet (ignored) |
|
712 */ |
|
713 { |
|
714 LOG( iPppLcp->iLogger->Printf(_L("%s Terminate Request, packet code[%d]"), __iFsmName, aCode); ) |
|
715 |
|
716 if (aCode==KPppLcpTerminateRequest) |
|
717 { |
|
718 LOG( iPppLcp->iLogger->Printf(_L("Rx: TerminateRequest Id[%d]"), aId); ) |
|
719 iFsmTermination = ETrue; // Used later to bring down the FSM as opposed to restarting it. |
|
720 iFsmTerminationCauseError = KErrDisconnected; |
|
721 switch (iState) |
|
722 { |
|
723 case EPppFsmInitial: |
|
724 case EPppFsmStarting: |
|
725 // bad event |
|
726 break; |
|
727 case EPppFsmClosed: |
|
728 case EPppFsmStopped: |
|
729 case EPppFsmClosing: |
|
730 case EPppFsmStopping: |
|
731 SendTerminateAck(aId); |
|
732 break; |
|
733 case EPppFsmReqSent: |
|
734 case EPppFsmAckRecvd: |
|
735 case EPppFsmAckSent: |
|
736 SendTerminateAck(aId); |
|
737 FsmLayerFinished(KErrCouldNotConnect); |
|
738 SetState(EPppFsmReqSent); |
|
739 break; |
|
740 case EPppFsmOpened: |
|
741 ZeroRestartCount(); |
|
742 if(iTerminateAckEnabled) // Fully RFC compliant shutdown sequence, as opposed to "Legacy" shutdown. |
|
743 // Once "Legacy" shutdown is removed, a check for TerminateAckEnabled may |
|
744 // be safely removed as well. |
|
745 { |
|
746 SendTerminateAck(aId); |
|
747 |
|
748 // RFC1661 3.7: wait at least one restart period |
|
749 TimerCancel(); |
|
750 TimerAfter(iTerminateAckTimeout * 1000); |
|
751 // If iTerminateAckTimeout is zero, we proceed to terminate the FSM and close the link almost |
|
752 // immediately. This may result in TerminateAck send being cancelled when we close the actual link. |
|
753 |
|
754 FsmLayerDown(KErrDisconnected); |
|
755 } |
|
756 else // "Legacy" shutdown sequence |
|
757 // Once "legacy" behaviour is not required any more, this section of code may be safely removed. |
|
758 { |
|
759 // We do not send terminate Ack. |
|
760 FsmLayerDown(); |
|
761 FsmLayerFinished(KErrCommsLineFail); |
|
762 // Note: |
|
763 // KErrCommsLineFail is given a special interpreation by the NCP, which may inform Nifman to |
|
764 // renegotiate the link, rather than terminate. |
|
765 } |
|
766 |
|
767 SetState(EPppFsmStopping); |
|
768 break; |
|
769 default: |
|
770 break; |
|
771 } |
|
772 } // KPppLcpterminateRequest |
|
773 else // KPppLcpTerminateAck |
|
774 { |
|
775 LOG( iPppLcp->iLogger->Printf(_L("Rx: TerminateAck Id[%d]"), aId); ) |
|
776 |
|
777 if (iPppAbortCode!=KErrNone) |
|
778 { |
|
779 iPppLcp->PhaseAborted(iPppAbortCode); |
|
780 } |
|
781 else |
|
782 { |
|
783 switch (iState) |
|
784 { |
|
785 case EPppFsmInitial: |
|
786 case EPppFsmStarting: |
|
787 // bad event |
|
788 break; |
|
789 case EPppFsmClosed: |
|
790 case EPppFsmStopped: |
|
791 break; |
|
792 case EPppFsmClosing: // Terminate Request Sent |
|
793 FsmLayerFinished(iFsmTerminationCauseError); |
|
794 SetState(EPppFsmClosed); |
|
795 break; |
|
796 case EPppFsmStopping: // Terminate Ack sent |
|
797 FsmLayerFinished(iFsmTerminationCauseError); |
|
798 SetState(EPppFsmStopped); |
|
799 break; |
|
800 case EPppFsmReqSent: |
|
801 case EPppFsmAckSent: |
|
802 KillProtocol(); |
|
803 break; |
|
804 case EPppFsmAckRecvd: |
|
805 SetState(EPppFsmReqSent); |
|
806 break; |
|
807 case EPppFsmOpened: |
|
808 FsmLayerDown(); |
|
809 SendConfigRequest(); |
|
810 SetState(EPppFsmReqSent); |
|
811 break; |
|
812 } |
|
813 } |
|
814 } |
|
815 } |
|
816 |
|
817 TBool MPppFsm::ProcessEmptyConfigReq() |
|
818 /** |
|
819 Handle Config Request with no options. |
|
820 |
|
821 @return ETrue on a valid state change |
|
822 */ |
|
823 { |
|
824 LOG( iPppLcp->iLogger->Printf(_L("%s Empty Config Request"), __iFsmName); ) |
|
825 |
|
826 |
|
827 TBool retCode = EFalse; |
|
828 |
|
829 |
|
830 // About to drop out of opened state to need to reset things |
|
831 // BEFORE the new request is processed. |
|
832 if (iState==EPppFsmOpened) |
|
833 { |
|
834 FsmLayerDown(); |
|
835 InitialiseConfigRequest(); |
|
836 } |
|
837 |
|
838 |
|
839 // State processing |
|
840 |
|
841 switch (iState) |
|
842 { |
|
843 case EPppFsmInitial: |
|
844 case EPppFsmStarting: |
|
845 // Bad event |
|
846 case EPppFsmClosing: |
|
847 case EPppFsmStopping: |
|
848 break; |
|
849 |
|
850 case EPppFsmClosed: |
|
851 //SendTerminateAck(aId); |
|
852 break; |
|
853 case EPppFsmStopped: |
|
854 { |
|
855 SendInitialConfigRequest(); |
|
856 SetState(EPppFsmAckSent); |
|
857 retCode = ETrue; |
|
858 break; |
|
859 } |
|
860 case EPppFsmReqSent: |
|
861 { |
|
862 retCode = ETrue; |
|
863 SetState(EPppFsmAckSent); |
|
864 break; |
|
865 } |
|
866 case EPppFsmAckRecvd: |
|
867 { |
|
868 retCode = ETrue; |
|
869 SetState(EPppFsmOpened); |
|
870 FsmLayerUp(); |
|
871 break; |
|
872 } |
|
873 case EPppFsmAckSent: |
|
874 { |
|
875 retCode = ETrue; |
|
876 break; |
|
877 } |
|
878 case EPppFsmOpened: |
|
879 { |
|
880 // This will cause empty config request to restart config negotiation |
|
881 SendInitialConfigRequest(); |
|
882 SetState(EPppFsmAckSent); |
|
883 retCode=ETrue; |
|
884 break; |
|
885 } |
|
886 } |
|
887 return retCode; |
|
888 } |
|
889 |
|
890 void MPppFsm::ProcessConfig(TUint8 aCode, TUint8 aId, TInt /* aLength */, RMBufChain& aPacket) |
|
891 /** |
|
892 Handle ConfigRequest, ConfigAck, ConfigNak and ConfigReject |
|
893 |
|
894 @param aCode Packet code |
|
895 @param aId Packet identifier |
|
896 @param aLength Length of packet (ignored) |
|
897 @param aPacket MBuf chain containing packet. |
|
898 */ |
|
899 { |
|
900 LOG( iPppLcp->iLogger->Printf(_L("%s Process Config, packet code[%d]"), __iFsmName, aCode); ) |
|
901 |
|
902 // Split the recvd packet into separate options |
|
903 // placing each option in a queue where it can be |
|
904 // easily parsed and manipulated in the upcall handlers. |
|
905 RPppOptionList rcvlist; // Recvd list of options |
|
906 |
|
907 TRAPD(err, rcvlist.SetL(aPacket)); |
|
908 if (err!=KErrNone) |
|
909 return; |
|
910 |
|
911 enum TCheckResult { ENop, EAck, ENak, ERej } reply = ENop; |
|
912 |
|
913 RPppOptionList acklist; // List of Ack'd options - only valid of the following are empty |
|
914 RPppOptionList naklist; // List of Nak'd options - only valid of the following is empty |
|
915 RPppOptionList rejlist; // List of Rejected options |
|
916 |
|
917 if (aCode==KPppLcpConfigRequest) |
|
918 { |
|
919 // About to drop out of opened state to need to reset things |
|
920 // BEFORE the new request is processed. |
|
921 if (iState==EPppFsmOpened) |
|
922 { |
|
923 FsmLayerDown(); |
|
924 InitialiseConfigRequest(); |
|
925 } |
|
926 |
|
927 // If any duplicated RFC1661 options, then discard the packet |
|
928 if (!FsmConfigRequestOptionsValid(rcvlist)) |
|
929 { |
|
930 LOG( iPppLcp->iLogger->Printf(_L("%s FSM - ConfigRequest discarded due to duplicate RFC1661 options"), __iFsmName); ) |
|
931 rcvlist.Free(); |
|
932 return; |
|
933 } |
|
934 |
|
935 // Check options, and split into list of OK, Bad and Unknown |
|
936 // Note - the naklist options will have been updated to |
|
937 // contain acceptable values. |
|
938 |
|
939 FsmCheckConfigRequest(rcvlist, acklist, naklist, rejlist); |
|
940 |
|
941 if (!rejlist.IsEmpty()) |
|
942 { |
|
943 reply = ERej; |
|
944 naklist.Free(); |
|
945 acklist.Free(); |
|
946 } |
|
947 else if (!naklist.IsEmpty()) |
|
948 { |
|
949 reply = ENak; |
|
950 acklist.Free(); |
|
951 } |
|
952 else if (!acklist.IsEmpty()) |
|
953 { |
|
954 reply = EAck; |
|
955 FsmApplyConfigRequest(acklist); |
|
956 } |
|
957 else |
|
958 { |
|
959 // Panic - options lost by derived class! |
|
960 } |
|
961 } |
|
962 |
|
963 // State processing |
|
964 |
|
965 switch (iState) |
|
966 { |
|
967 case EPppFsmInitial: |
|
968 case EPppFsmStarting: |
|
969 // Bad event |
|
970 case EPppFsmClosing: |
|
971 case EPppFsmStopping: |
|
972 break; |
|
973 |
|
974 case EPppFsmClosed: |
|
975 SendTerminateAck(aId); |
|
976 break; |
|
977 |
|
978 case EPppFsmStopped: |
|
979 switch (aCode) |
|
980 { |
|
981 case KPppLcpConfigRequest: |
|
982 SendInitialConfigRequest(); |
|
983 switch (reply) |
|
984 { |
|
985 case EAck: |
|
986 SendConfigReply(acklist, KPppLcpConfigAck, aId); |
|
987 SetState(EPppFsmAckSent); |
|
988 break; |
|
989 case ENak: |
|
990 SendConfigReply(naklist, KPppLcpConfigNak, aId); |
|
991 SetState(EPppFsmReqSent); |
|
992 break; |
|
993 case ERej: |
|
994 SendConfigReply(rejlist, KPppLcpConfigReject, aId); |
|
995 SetState(EPppFsmReqSent); |
|
996 break; |
|
997 default: |
|
998 break; |
|
999 } |
|
1000 break; |
|
1001 case KPppLcpConfigAck: |
|
1002 case KPppLcpConfigNak: |
|
1003 case KPppLcpConfigReject: |
|
1004 SendTerminateAck(aId); |
|
1005 break; |
|
1006 default: |
|
1007 break; |
|
1008 } |
|
1009 break; |
|
1010 |
|
1011 case EPppFsmReqSent: |
|
1012 switch (aCode) |
|
1013 { |
|
1014 case KPppLcpConfigRequest: |
|
1015 switch (reply) |
|
1016 { |
|
1017 case EAck: |
|
1018 SendConfigReply(acklist, KPppLcpConfigAck, aId); |
|
1019 SetState(EPppFsmAckSent); |
|
1020 break; |
|
1021 case ENak: |
|
1022 // RFC 1661 4.6 |
|
1023 if(MaxFailureExceeded()) |
|
1024 SendConfigReply(naklist, KPppLcpConfigReject, aId); |
|
1025 else |
|
1026 { |
|
1027 DecrementMaxFailure(); |
|
1028 SendConfigReply(naklist, KPppLcpConfigNak, aId); |
|
1029 } |
|
1030 SetState(EPppFsmReqSent); |
|
1031 break; |
|
1032 case ERej: |
|
1033 SendConfigReply(rejlist, KPppLcpConfigReject, aId); |
|
1034 SetState(EPppFsmReqSent); |
|
1035 break; |
|
1036 default: |
|
1037 break; |
|
1038 } |
|
1039 break; |
|
1040 case KPppLcpConfigAck: |
|
1041 if (FsmAckOptionsValid(rcvlist, iRequestList)) |
|
1042 { |
|
1043 InitRestartCountForConfig(); |
|
1044 FsmRecvConfigAck(rcvlist); |
|
1045 SetState(EPppFsmAckRecvd); |
|
1046 } |
|
1047 else |
|
1048 { |
|
1049 LOG( iPppLcp->iLogger->Printf(_L("%s FSM - ConfigAck discarded due to option mismatch with original ConfigRequest"), __iFsmName); ) |
|
1050 } |
|
1051 break; |
|
1052 case KPppLcpConfigNak: |
|
1053 InitRestartCountForConfig(); |
|
1054 FsmRecvConfigNak(rcvlist, iRequestList); |
|
1055 SendConfigRequestAfterNak(rcvlist); |
|
1056 break; |
|
1057 case KPppLcpConfigReject: |
|
1058 InitRestartCountForConfig(); |
|
1059 FsmRecvConfigReject(rcvlist, iRequestList); |
|
1060 SendConfigRequestAfterReject(rcvlist); |
|
1061 break; |
|
1062 default: |
|
1063 break; |
|
1064 } |
|
1065 break; |
|
1066 |
|
1067 case EPppFsmAckRecvd: |
|
1068 switch (aCode) |
|
1069 { |
|
1070 case KPppLcpConfigRequest: |
|
1071 switch (reply) |
|
1072 { |
|
1073 case EAck: |
|
1074 SendConfigReply(acklist, KPppLcpConfigAck, aId); |
|
1075 SetState(EPppFsmOpened); |
|
1076 FsmLayerUp(); |
|
1077 break; |
|
1078 case ENak: |
|
1079 // RFC 1661 4.6 |
|
1080 if(MaxFailureExceeded()) |
|
1081 SendConfigReply(naklist, KPppLcpConfigReject, aId); |
|
1082 else |
|
1083 { |
|
1084 DecrementMaxFailure(); |
|
1085 SendConfigReply(naklist, KPppLcpConfigNak, aId); |
|
1086 } |
|
1087 break; |
|
1088 case ERej: |
|
1089 SendConfigReply(rejlist, KPppLcpConfigReject, aId); |
|
1090 break; |
|
1091 default: |
|
1092 break; |
|
1093 } |
|
1094 break; |
|
1095 case KPppLcpConfigAck: |
|
1096 case KPppLcpConfigNak: |
|
1097 case KPppLcpConfigReject: |
|
1098 SendConfigRequest(); |
|
1099 SetState(EPppFsmReqSent); |
|
1100 break; |
|
1101 default: |
|
1102 break; |
|
1103 } |
|
1104 break; |
|
1105 |
|
1106 case EPppFsmAckSent: |
|
1107 switch (aCode) |
|
1108 { |
|
1109 case KPppLcpConfigRequest: |
|
1110 switch (reply) |
|
1111 { |
|
1112 case EAck: |
|
1113 SendConfigReply(acklist, KPppLcpConfigAck, aId); |
|
1114 break; |
|
1115 case ENak: |
|
1116 // RFC 1661 4.6 |
|
1117 if(MaxFailureExceeded()) |
|
1118 SendConfigReply(naklist, KPppLcpConfigReject, aId); |
|
1119 else |
|
1120 { |
|
1121 DecrementMaxFailure(); |
|
1122 SendConfigReply(naklist, KPppLcpConfigNak, aId); |
|
1123 } |
|
1124 SetState(EPppFsmReqSent); |
|
1125 break; |
|
1126 case ERej: |
|
1127 SendConfigReply(rejlist, KPppLcpConfigReject, aId); |
|
1128 SetState(EPppFsmReqSent); |
|
1129 break; |
|
1130 default: |
|
1131 break; |
|
1132 } |
|
1133 break; |
|
1134 case KPppLcpConfigAck: |
|
1135 if (FsmAckOptionsValid(rcvlist, iRequestList)) |
|
1136 { |
|
1137 InitRestartCountForConfig(); |
|
1138 FsmRecvConfigAck(rcvlist); |
|
1139 SetState(EPppFsmOpened); |
|
1140 FsmLayerUp(); |
|
1141 } |
|
1142 else |
|
1143 { |
|
1144 LOG( iPppLcp->iLogger->Printf(_L("%s FSM - ConfigAck discarded due to option mismatch with original ConfigRequest"), __iFsmName); ) |
|
1145 } |
|
1146 break; |
|
1147 case KPppLcpConfigNak: |
|
1148 InitRestartCountForConfig(); |
|
1149 FsmRecvConfigNak(rcvlist, iRequestList); |
|
1150 SendConfigRequestAfterNak(rcvlist); |
|
1151 break; |
|
1152 case KPppLcpConfigReject: |
|
1153 if (FsmRejectOptionsValid(rcvlist, iRequestList)) |
|
1154 { |
|
1155 InitRestartCountForConfig(); |
|
1156 FsmRecvConfigReject(rcvlist, iRequestList); |
|
1157 SendConfigRequestAfterReject(rcvlist); |
|
1158 } |
|
1159 else |
|
1160 { |
|
1161 LOG( iPppLcp->iLogger->Printf(_L("%s FSM - ConfigReject discarded due to option mismatch with original ConfigRequest"), __iFsmName); ) |
|
1162 } |
|
1163 break; |
|
1164 default: |
|
1165 break; |
|
1166 } |
|
1167 break; |
|
1168 |
|
1169 case EPppFsmOpened: |
|
1170 // Config Reset done above |
|
1171 switch (aCode) |
|
1172 { |
|
1173 case KPppLcpConfigRequest: |
|
1174 SendConfigRequest(); |
|
1175 switch (reply) |
|
1176 { |
|
1177 case EAck: |
|
1178 SendConfigReply(acklist, KPppLcpConfigAck, aId); |
|
1179 SetState(EPppFsmAckSent); |
|
1180 break; |
|
1181 case ENak: |
|
1182 SendConfigReply(naklist, KPppLcpConfigNak, aId); |
|
1183 SetState(EPppFsmReqSent); |
|
1184 break; |
|
1185 case ERej: |
|
1186 SendConfigReply(rejlist, KPppLcpConfigReject, aId); |
|
1187 SetState(EPppFsmReqSent); |
|
1188 break; |
|
1189 default: |
|
1190 break; |
|
1191 } |
|
1192 break; |
|
1193 case KPppLcpConfigAck: |
|
1194 SendConfigRequest(); |
|
1195 FsmRecvConfigAck(rcvlist); |
|
1196 SetState(EPppFsmReqSent); |
|
1197 break; |
|
1198 case KPppLcpConfigNak: |
|
1199 FsmRecvConfigNak(rcvlist, iRequestList); |
|
1200 SendConfigRequestAfterNak(rcvlist); |
|
1201 SetState(EPppFsmReqSent); |
|
1202 break; |
|
1203 case KPppLcpConfigReject: |
|
1204 FsmRecvConfigReject(rcvlist, iRequestList); |
|
1205 SendConfigRequestAfterReject(rcvlist); |
|
1206 SetState(EPppFsmReqSent); |
|
1207 break; |
|
1208 default: |
|
1209 break; |
|
1210 } |
|
1211 break; |
|
1212 |
|
1213 default: |
|
1214 // Invalid state |
|
1215 LOG( iPppLcp->iLogger->Printf(_L("%s Invalid state %d"), __iFsmName, iState); ) |
|
1216 break; |
|
1217 } |
|
1218 rcvlist.Free(); |
|
1219 acklist.Free(); |
|
1220 naklist.Free(); |
|
1221 rejlist.Free(); |
|
1222 } |
|
1223 |
|
1224 void MPppFsm::SendConfigRequest() |
|
1225 /** |
|
1226 Send the config request in iRequestList |
|
1227 */ |
|
1228 { |
|
1229 if (iPppAbortCode!=KErrNone) |
|
1230 return; |
|
1231 |
|
1232 |
|
1233 // With Mobile IP, there is the possibility of having no options to negotiate, in which case |
|
1234 // we would send an empty ConfigRequest rather than nothing. |
|
1235 |
|
1236 TBool emptyList = iRequestList.IsEmpty(); |
|
1237 if (emptyList && !iPppLcp->QueryExternalIPConfiguration()) |
|
1238 { |
|
1239 LOG( iPppLcp->iLogger->Printf(_L("%s FSM Request list empty"), __iFsmName); ) |
|
1240 return; |
|
1241 } |
|
1242 |
|
1243 RMBufPacket pkt; |
|
1244 iRequestId &= 0xff; |
|
1245 TRAPD(err, iRequestList.CreatePacketL(pkt, iPppId, KPppLcpConfigRequest, (TUint8)iRequestId, emptyList)); |
|
1246 if (err!=KErrNone) |
|
1247 { |
|
1248 //__DEBUGGER(); |
|
1249 return; |
|
1250 } |
|
1251 SendFrame(pkt); |
|
1252 --iRestartCount; |
|
1253 TimerCancel(); |
|
1254 TInt temp=iWaitTime; |
|
1255 if (iPppId==KPppIdIpcp && iLengthenTimers) |
|
1256 temp=KPppFsmLengthenedRequestTimeout; |
|
1257 TimerAfter(temp*1000); |
|
1258 } |
|
1259 |
|
1260 |
|
1261 TInt MPppFsm::InitialiseConfigRequest() |
|
1262 /** |
|
1263 Delete any existing request list, then create a new one. |
|
1264 Initialise counters for sending config requests. |
|
1265 |
|
1266 @return Error code |
|
1267 |
|
1268 @post iRequestList is initialized |
|
1269 */ |
|
1270 { |
|
1271 iLastCfgReqFcs = 0; |
|
1272 iConsecCfgReq = 0; |
|
1273 iRequestId = FsmNewId(); |
|
1274 InitRestartCountForConfig(); |
|
1275 if (!iRequestList.IsEmpty()) |
|
1276 iRequestList.Free(); |
|
1277 TRAPD(err, FsmFillinConfigRequestL(iRequestList)); |
|
1278 return err; |
|
1279 } |
|
1280 |
|
1281 void MPppFsm::SendInitialConfigRequest() |
|
1282 /** |
|
1283 Initialise request list and send a request if successful. |
|
1284 */ |
|
1285 { |
|
1286 if (InitialiseConfigRequest()==KErrNone) |
|
1287 SendConfigRequest(); |
|
1288 } |
|
1289 |
|
1290 void MPppFsm::SendConfigRequestAfterNak(RPppOptionList& /*aOptsList*/) |
|
1291 /** |
|
1292 Update the options list and send a new config request after a Nak. |
|
1293 |
|
1294 @param aOptList Options list (ignored) |
|
1295 */ |
|
1296 { |
|
1297 iRequestId = FsmNewId(); |
|
1298 |
|
1299 // Calc a 32bit CRC of the request list data |
|
1300 // and compare with last recorded RequestAfterNAK CRC. |
|
1301 // If the same, then it is more likely that negotiation |
|
1302 // is not converging. |
|
1303 TPppFcs32 fcs; |
|
1304 iRequestList.Crc32(fcs); |
|
1305 |
|
1306 if (fcs.Fcs()==iLastCfgReqFcs) |
|
1307 { |
|
1308 if (++iConsecCfgReq>KPppFsmNonConvergeLimit) |
|
1309 { |
|
1310 LOG( iPppLcp->iLogger->Printf(_L("NonConvergence limit reached")); ) |
|
1311 FsmAbort(KErrTimedOut); |
|
1312 return; |
|
1313 } |
|
1314 } |
|
1315 else |
|
1316 { |
|
1317 iLastCfgReqFcs = fcs.Fcs(); |
|
1318 iConsecCfgReq = 0; |
|
1319 } |
|
1320 |
|
1321 SendConfigRequest(); |
|
1322 } |
|
1323 |
|
1324 void MPppFsm::SendConfigRequestAfterReject(RPppOptionList& /*aOptsList*/) |
|
1325 /** |
|
1326 Update the options list and send a new config request after a Reject. |
|
1327 |
|
1328 @param aOptList Options list (ignored) |
|
1329 */ |
|
1330 { |
|
1331 iRequestId = FsmNewId(); |
|
1332 SendConfigRequest(); |
|
1333 } |
|
1334 |
|
1335 void MPppFsm::SendConfigReply(RPppOptionList& aOptList, TUint8 aType, TUint8 aId) |
|
1336 /** |
|
1337 Reply to a config request with a set of options. |
|
1338 |
|
1339 @param aOptList Options list |
|
1340 @param aType Packet type (Ack, Nak, Rej) |
|
1341 @param aId Packet identifier |
|
1342 */ |
|
1343 { |
|
1344 if (iPppAbortCode!=KErrNone) |
|
1345 return; |
|
1346 |
|
1347 RMBufPacket pkt; |
|
1348 TRAPD(err, aOptList.CreatePacketL(pkt, iPppId, aType, aId, EFalse)); |
|
1349 if (err!=KErrNone) |
|
1350 { |
|
1351 //__DEBUGGER(); |
|
1352 return; |
|
1353 } |
|
1354 SendFrame(pkt); |
|
1355 // TimerCancel(); |
|
1356 // TimerAfter(iWaitTime*1000); |
|
1357 } |
|
1358 |
|
1359 void MPppFsm::SendInitialTerminateRequest() |
|
1360 /** |
|
1361 Send the first Terminate Request packet to begin connection teardown. |
|
1362 */ |
|
1363 { |
|
1364 iTerminateId = FsmNewId(); |
|
1365 InitRestartCountForTerminate(); |
|
1366 if(iRestartCount > 0) |
|
1367 { |
|
1368 SendTerminateRequest(); |
|
1369 } |
|
1370 else // We are configured to send zero Terminate Requests. |
|
1371 { |
|
1372 TimerCancel(); |
|
1373 TimerAfter(0); // As if we finished transmitting Terminate Requests. |
|
1374 } |
|
1375 } |
|
1376 |
|
1377 void MPppFsm::SendTerminateRequest() |
|
1378 /** |
|
1379 Send a Terminate Request packet. |
|
1380 |
|
1381 @pre SendInitialTerminateRequest() must have previously been called |
|
1382 */ |
|
1383 { |
|
1384 RMBufPacket pkt; |
|
1385 const TUint pktLen = 4; |
|
1386 TUint8* ptr = NewPacket(pkt, pktLen); |
|
1387 if (ptr == NULL) |
|
1388 { |
|
1389 __ASSERT_DEBUG(EFalse,PppPanic(EPppPanic_PPPNoMemory)); |
|
1390 return; |
|
1391 } |
|
1392 *ptr++ = KPppLcpTerminateRequest; |
|
1393 iTerminateId &= 0xff; |
|
1394 *ptr++ = (TUint8)iTerminateId; |
|
1395 BigEndian::Put16(ptr, (TUint16)pktLen); |
|
1396 pkt.Pack(); |
|
1397 SendFrame(pkt); |
|
1398 |
|
1399 --iRestartCount; |
|
1400 TimerCancel(); |
|
1401 TInt temp=iWaitTime; |
|
1402 if (iLengthenTimers) |
|
1403 temp=KPppFsmLengthenedTerminateTimeout; |
|
1404 TimerAfter(temp*1000); |
|
1405 LOG( iPppLcp->iLogger->Printf(_L("Tx: TerminateRequest Id[%d]. Restart Count[%d]"), iTerminateId, iRestartCount); ) |
|
1406 } |
|
1407 |
|
1408 void MPppFsm::SendTerminateAck(TUint8 aId) |
|
1409 /** |
|
1410 Send a Terminate Ack packet. |
|
1411 |
|
1412 @param aId Packet identifier |
|
1413 */ |
|
1414 { |
|
1415 RMBufPacket pkt; |
|
1416 const TUint pktLen = 4; |
|
1417 TUint8* ptr = NewPacket(pkt, pktLen); |
|
1418 if (ptr == NULL) |
|
1419 { |
|
1420 __ASSERT_DEBUG(EFalse,PppPanic(EPppPanic_PPPNoMemory)); |
|
1421 return; |
|
1422 } |
|
1423 *ptr++ = KPppLcpTerminateAck; |
|
1424 *ptr++ = aId; |
|
1425 BigEndian::Put16(ptr, (TUint16)pktLen); |
|
1426 pkt.Pack(); |
|
1427 SendFrame(pkt); |
|
1428 |
|
1429 LOG(iPppLcp->iLogger->Printf(_L("Tx: TerminateAck Id[%d]."),aId);) |
|
1430 } |
|
1431 |
|
1432 void MPppFsm::InitRestartCountForConfig() |
|
1433 /** |
|
1434 Initialize the restart count and wait time |
|
1435 with values appropriate for the config phase. |
|
1436 */ |
|
1437 { |
|
1438 |
|
1439 // RFC 1661 4.6 Max-Configure |
|
1440 iWaitTime = iWaitTimeConfig; |
|
1441 iRestartCount = iMaxRestartConfig; |
|
1442 } |
|
1443 |
|
1444 void MPppFsm::InitRestartCountForTerminate() |
|
1445 /** |
|
1446 Initialize the restart count and wait time for |
|
1447 with values appropriate for the termination phase. |
|
1448 */ |
|
1449 { |
|
1450 if(iNoEvidenceOfPeer) |
|
1451 { |
|
1452 // If we've been told to terminate by our control and haven't yet heard anything from the peer then we |
|
1453 // don't attempt to send it a disconnect. This is a little unpleasant because if we've sent it a config |
|
1454 // packet it may be left waiting for us until it times out, however the more likely state is that we |
|
1455 // haven't yet completed sending the packet to it because the BCA is still waiting on its bearer to |
|
1456 // set up. Unfortunately we don't seem to have a palatable way to abort this BCA write from here. |
|
1457 LOG(iPppLcp->iLogger->Printf(_L("InitRestartCountForTerminate: no evidence of peer contact so terminating without notice"));) |
|
1458 ZeroRestartCount(); |
|
1459 } |
|
1460 else |
|
1461 { |
|
1462 iWaitTime = iTerminateRequestTimeout; |
|
1463 iRestartCount = iMaxTerminateRequest; |
|
1464 } |
|
1465 } |
|
1466 |
|
1467 void MPppFsm::ZeroRestartCount() |
|
1468 /** |
|
1469 Clear the restart count. |
|
1470 */ |
|
1471 { |
|
1472 iRestartCount = 0; |
|
1473 } |
|
1474 |
|
1475 TUint8 MPppFsm::FsmNewId() |
|
1476 /** |
|
1477 Generate a new nonzero packet identifier. |
|
1478 |
|
1479 @return Packet identifier |
|
1480 */ |
|
1481 { |
|
1482 if (++iCurrentId==0) |
|
1483 ++iCurrentId; |
|
1484 return iCurrentId; |
|
1485 } |
|
1486 |
|
1487 void MPppFsm::SetState(TPppFsmState aState) |
|
1488 /** |
|
1489 Set the next state in the FSM. |
|
1490 Cancels the timer when appropriate. |
|
1491 |
|
1492 @param aState Next state |
|
1493 */ |
|
1494 { |
|
1495 LOG( iPppLcp->iLogger->DumpState(__iFsmName, iState, aState); ) |
|
1496 iState = aState; |
|
1497 if (iState<EPppFsmClosing || iState==EPppFsmOpened) |
|
1498 { |
|
1499 if(iState == EPppFsmStarting) |
|
1500 { |
|
1501 iNoEvidenceOfPeer = ETrue; |
|
1502 } |
|
1503 TimerCancel(); |
|
1504 } |
|
1505 } |
|
1506 |
|
1507 |
|
1508 void MPppFsm::FsmRejectPacket(RMBufChain& aPacket, TUint aReason, TUint aPppId) |
|
1509 /** |
|
1510 Send a Code Reject or Protocol Reject packet. |
|
1511 |
|
1512 @param aPacket MBuf chain containing packet; it will be used to send the reject message. |
|
1513 @param aReason Reason for rejecting (KPppLcpCodeReject or KPppLcpProtocolReject) |
|
1514 @param aPppId PPP protocol ID |
|
1515 */ |
|
1516 { |
|
1517 RMBufPacket pkt; |
|
1518 pkt.Assign(aPacket); |
|
1519 pkt.Unpack(); |
|
1520 RMBufPktInfo* info = pkt.Info(); |
|
1521 |
|
1522 // This function reuses the rejected packet chain to send the reject message, |
|
1523 // so reserve some space at the beginning for the reject header. |
|
1524 TInt prep = 0; |
|
1525 if (aReason==KPppLcpCodeReject) |
|
1526 prep = 4; |
|
1527 else if (aReason==KPppLcpProtocolReject) |
|
1528 prep = 6; |
|
1529 else |
|
1530 { |
|
1531 // Unknown reject reason |
|
1532 pkt.Free(); |
|
1533 return; |
|
1534 } |
|
1535 |
|
1536 TRAPD(err, pkt.PrependL(prep)); |
|
1537 if (err!=KErrNone) |
|
1538 { |
|
1539 pkt.Free(); |
|
1540 return; |
|
1541 } |
|
1542 info->iLength += prep; |
|
1543 |
|
1544 // If the frame to be sent is too large, lop off the end to make it fit. |
|
1545 __ASSERT_DEBUG(iPppLcp->MaxTransferSize() > 0, PppPanic(EPppPanic_InvalidData)); |
|
1546 if (info->iLength > iPppLcp->MaxTransferSize()) |
|
1547 { |
|
1548 pkt.TrimEnd(iPppLcp->MaxTransferSize()); |
|
1549 info->iLength = iPppLcp->MaxTransferSize(); |
|
1550 } |
|
1551 |
|
1552 TUint8* ptr = pkt.First()->Ptr(); |
|
1553 |
|
1554 *ptr++ = TUint8(aReason); // xxx |
|
1555 *ptr++ = FsmNewId(); |
|
1556 BigEndian::Put16(ptr, (TUint16)info->iLength); |
|
1557 ptr += 2; |
|
1558 if (aReason==KPppLcpProtocolReject) |
|
1559 { |
|
1560 BigEndian::Put16(ptr, (TUint16)TPppAddr::Cast((info->iDstAddr)).GetProtocol()); |
|
1561 TPppAddr::Cast((info->iDstAddr)).SetProtocol(KPppIdLcp); |
|
1562 } |
|
1563 |
|
1564 pkt.Pack(); |
|
1565 if (aPppId == KPppIdAsIs) |
|
1566 SendFrame(pkt); |
|
1567 else |
|
1568 iPppLcp->PppLink()->Send(pkt, aPppId); |
|
1569 } |
|
1570 |
|
1571 void MPppFsm::ReadIniFileL() |
|
1572 /** |
|
1573 Reads the contents of the ppp.ini file. |
|
1574 |
|
1575 @leave Error code if file cannot be read |
|
1576 */ |
|
1577 // Added September 1999 |
|
1578 // Currently can read from ini file :- |
|
1579 // Max-Configure |
|
1580 // Max-Failure |
|
1581 // Restart Timer |
|
1582 // Enable TerminateRequest / TerminateAck |
|
1583 // Max TerminateRequest |
|
1584 // TerminateRequest timeout |
|
1585 // TerminateAck timeout |
|
1586 { |
|
1587 // Check the ini file exists and can be opened |
|
1588 CESockIniData* ini = NULL; |
|
1589 TRAPD(res, |
|
1590 if (iPppLcp->PppLinkMode() == CPppLcpConfig::EPppLinkIsServer) |
|
1591 { |
|
1592 ini = CESockIniData::NewL(PPP_SERVER_INI_FILE); |
|
1593 } |
|
1594 else |
|
1595 { |
|
1596 ini = CESockIniData::NewL(PPP_INI_FILE); |
|
1597 } |
|
1598 ) |
|
1599 if(res!=KErrNone) |
|
1600 { |
|
1601 if(res==KErrNotFound) |
|
1602 { |
|
1603 // No .ini file; use default values |
|
1604 iMaxFailureConfig = KPppMaxFailureDefault; |
|
1605 iMaxRestartConfig = KPppFsmRequestRetries; |
|
1606 iWaitTimeConfig = KPppFsmRequestTimeout; |
|
1607 |
|
1608 |
|
1609 // Termination Phase Support. |
|
1610 // If the .ini file is missing, full support is enabled. |
|
1611 |
|
1612 iTerminateRequestEnabled = ETrue; |
|
1613 iMaxTerminateRequest = KPppFsmTerminateRequestRetries; |
|
1614 iTerminateRequestTimeout = KPppFsmTerminateRequestTimeout; |
|
1615 |
|
1616 iTerminateAckEnabled = ETrue; |
|
1617 iTerminateAckTimeout = KPppFsmTerminateAckTimeout; |
|
1618 |
|
1619 return; |
|
1620 } |
|
1621 User::Leave(res); |
|
1622 } |
|
1623 CleanupStack::PushL(ini); |
|
1624 TInt entry; |
|
1625 // |
|
1626 // Max-Failure |
|
1627 // Read enable switch |
|
1628 if (ini->FindVar(LCPSECTIONNAME,PPPMAXFAILUREENTRYNAME_ENABLE, entry)) |
|
1629 { |
|
1630 if (entry == 0) |
|
1631 iMaxFailureConfig = KPppMaxFailureDefault; |
|
1632 else |
|
1633 { |
|
1634 if (ini->FindVar(LCPSECTIONNAME,PPPMAXFAILUREENTRYNAME_COUNT, entry)) |
|
1635 iMaxFailureConfig = entry; |
|
1636 else |
|
1637 iMaxFailureConfig = KPppMaxFailureDefault; |
|
1638 } |
|
1639 } |
|
1640 else |
|
1641 iMaxFailureConfig = KPppMaxFailureDefault; |
|
1642 |
|
1643 // |
|
1644 // Max-Configure |
|
1645 // Read enable switch |
|
1646 if (ini->FindVar(LCPSECTIONNAME,PPPMAXRESTARTENTRYNAME_ENABLE, entry)) |
|
1647 { |
|
1648 if (entry == 0) |
|
1649 iMaxRestartConfig = KPppFsmRequestRetries; |
|
1650 else |
|
1651 { |
|
1652 if (ini->FindVar(LCPSECTIONNAME,PPPMAXRESTARTENTRYNAME_COUNT, entry)) |
|
1653 iMaxRestartConfig = entry; |
|
1654 else |
|
1655 iMaxRestartConfig = KPppFsmRequestRetries; |
|
1656 } |
|
1657 } |
|
1658 else |
|
1659 iMaxRestartConfig = KPppFsmRequestRetries; |
|
1660 // |
|
1661 // Restart Timer |
|
1662 // Read enable switch |
|
1663 if (ini->FindVar(LCPSECTIONNAME,PPPRESTARTTIMERENTRYNAME_ENABLE, entry)) |
|
1664 { |
|
1665 if (entry == 0) |
|
1666 iWaitTimeConfig = KPppFsmRequestTimeout; |
|
1667 else |
|
1668 { |
|
1669 if (ini->FindVar(LCPSECTIONNAME,PPPRESTARTTIMERENTRYNAME_PERIOD, entry)) |
|
1670 iWaitTimeConfig = entry; |
|
1671 else |
|
1672 iWaitTimeConfig = KPppFsmRequestTimeout; |
|
1673 } |
|
1674 } |
|
1675 else |
|
1676 iWaitTimeConfig = KPppFsmRequestTimeout; |
|
1677 |
|
1678 |
|
1679 // |
|
1680 // Support PPP Termination Sequence Configurability, required for |
|
1681 // CDMA support. |
|
1682 // |
|
1683 if(ini->FindVar(LCPSECTIONNAME, TERMINATE_REQUEST_ENABLE, entry)) |
|
1684 { |
|
1685 if(0 == entry) |
|
1686 { |
|
1687 iTerminateRequestEnabled = EFalse; |
|
1688 } |
|
1689 } |
|
1690 |
|
1691 // Max Terminate Requests to be sent. |
|
1692 if(iTerminateRequestEnabled) |
|
1693 { |
|
1694 if(ini->FindVar(LCPSECTIONNAME, MAX_TERMINATE_REQUEST_ENABLE, entry)) |
|
1695 { |
|
1696 if(0 != entry) |
|
1697 { |
|
1698 if (ini->FindVar(LCPSECTIONNAME, MAX_TERMINATE_REQUEST_COUNT, entry)) |
|
1699 { |
|
1700 iMaxTerminateRequest = entry; |
|
1701 } |
|
1702 } |
|
1703 } |
|
1704 |
|
1705 // Normal Terminate Request timeout |
|
1706 if(ini->FindVar(LCPSECTIONNAME, TERMINATE_REQUEST_TIMER_ENABLE, entry)) |
|
1707 { |
|
1708 if(0 != entry) |
|
1709 { |
|
1710 if (ini->FindVar(LCPSECTIONNAME, TERMINATE_REQUEST_TIMER_PERIOD, entry)) |
|
1711 { |
|
1712 iTerminateRequestTimeout = entry; |
|
1713 } |
|
1714 } |
|
1715 } |
|
1716 } |
|
1717 else |
|
1718 { |
|
1719 // Special Case: Support legacy shutdown behaviour: send only one Terminate Request. |
|
1720 // To disable sending TerminatRequest entirely, Enable TerminateRequest, and set MaxTerminateRequest to 0. |
|
1721 // When support for legacy shutdown is not necessary, this code can be safely removed. |
|
1722 iMaxTerminateRequest = 1; |
|
1723 } |
|
1724 |
|
1725 // |
|
1726 // Terminate ACK configurability |
|
1727 // |
|
1728 // Is sending a configure ACK enabled? |
|
1729 if(ini->FindVar(LCPSECTIONNAME, TERMINATE_ACK_ENABLE, entry)) |
|
1730 { |
|
1731 if(0 == entry) |
|
1732 { |
|
1733 iTerminateAckEnabled = EFalse; |
|
1734 } |
|
1735 } |
|
1736 |
|
1737 // Read Terminate ACK settings only if it is enabled |
|
1738 if(iTerminateAckEnabled) |
|
1739 { |
|
1740 if(ini->FindVar(LCPSECTIONNAME, TERMINATE_ACK_TIMER_ENABLE, entry)) |
|
1741 { |
|
1742 if(0 != entry) |
|
1743 { |
|
1744 if(ini->FindVar(LCPSECTIONNAME, TERMINATE_ACK_TIMER_PERIOD, entry)) |
|
1745 { |
|
1746 iTerminateAckTimeout = entry; |
|
1747 } |
|
1748 } |
|
1749 } |
|
1750 } |
|
1751 |
|
1752 // Setting that controls doubling of timeout value on restart timer |
|
1753 if (ini->FindVar(LCPSECTIONNAME, PPP_RESTARTTIMER_ENTRYNAME_MODE, entry)) |
|
1754 { |
|
1755 if (entry == 1) |
|
1756 { |
|
1757 iWaitTimeNoIncrease = ETrue; |
|
1758 } |
|
1759 } |
|
1760 |
|
1761 |
|
1762 CleanupStack::PopAndDestroy(); |
|
1763 } |
|
1764 |
|
1765 TUint8* MPppFsm::NewPacket(RMBufPacket& aPkt, TUint aLength) |
|
1766 /** |
|
1767 Allocate a new packet buffer and info header. The caller must fill in the |
|
1768 the packet and call its Pack() method before sending. |
|
1769 |
|
1770 @param aPkt reference to a packet |
|
1771 @param aLength length of the buffer |
|
1772 @return pointer to the beginning of the first packet in the chain or NULL on error |
|
1773 |
|
1774 @see RPppOptionList::CreatePacketL |
|
1775 */ |
|
1776 { |
|
1777 TRAPD(err, aPkt.AllocL(aLength)); |
|
1778 if (err != KErrNone) |
|
1779 { |
|
1780 return NULL; |
|
1781 } |
|
1782 RMBufPktInfo* info=NULL; |
|
1783 TRAP(err,info = aPkt.NewInfoL()); |
|
1784 if (err != KErrNone) |
|
1785 { |
|
1786 aPkt.Free(); |
|
1787 return NULL; |
|
1788 } |
|
1789 info->iLength = aLength; |
|
1790 TPppAddr::Cast((info->iDstAddr)).SetProtocol(iPppId); |
|
1791 return aPkt.First()->Ptr(); |
|
1792 } |
|
1793 |
|
1794 |
|
1795 TBool MPppFsm::FsmAckOptionsValid(RPppOptionList& /*aList*/, RPppOptionList& /*aRequestList*/) |
|
1796 /** |
|
1797 Perform validation checking on the option list of a ConfigAck or ConfigReject. |
|
1798 |
|
1799 @param aList option list of incoming ConfigAck or ConfigReject |
|
1800 @return ETrue if options valid, else EFalse. EFalse return causes packet to be discarded. |
|
1801 */ |
|
1802 { |
|
1803 return ETrue; |
|
1804 } |
|
1805 |
|
1806 TBool MPppFsm::FsmRejectOptionsValid(RPppOptionList& /*aList*/, RPppOptionList& /*aRequestList*/) |
|
1807 /** |
|
1808 Perform validation checking on the option list of a ConfigAck or ConfigReject. |
|
1809 |
|
1810 @param aList option list of incoming ConfigAck or ConfigReject |
|
1811 @return ETrue if options valid, else EFalse. EFalse return causes packet to be discarded. |
|
1812 */ |
|
1813 { |
|
1814 return ETrue; |
|
1815 } |
|
1816 TBool MPppFsm::FsmConfigRequestOptionsValid(RPppOptionList& /*aList*/) |
|
1817 /** |
|
1818 Perform validation checking on the option list of a ConfigRequest. |
|
1819 |
|
1820 @param aList option list of incoming ConfigRequest |
|
1821 @return ETrue if options valid, else EFalse. EFalse return causes packet to be discarded. |
|
1822 */ |
|
1823 { |
|
1824 return ETrue; |
|
1825 } |
|
1826 |