1/*
2    File:       IrLSAPConn.cpp
3
4    Contains:   Implementation of the TIrLSAPConn class
5
6
7*/
8
9#include "IrLSAPConn.h"
10#include "IrGlue.h"
11#include "IrLMP.h"
12#include "CList.h"
13#include "CListIterator.h"
14#include "CBufferSegment.h"
15#include "IrDALog.h"
16
17#if (hasTracing > 0 && hasLSAPConnTracing > 0)
18
19enum IrLSAPConnTraceCodes
20{
21    kNullEvent = 1,
22    kDestroy,
23    kDeInit,
24    kUnexpectedEvent,
25
26    kDiscConnectEvent,
27    kDiscListenEvent,
28    kDiscDiscRequestEvent,
29    kDiscLeftoversReplyEvent,
30
31    kConnectPendConnectReplyEvent,
32    kConnectPendPutReplyEvent,
33    kConnectPendDiscRequestEvent,
34    kConnectPendDiscReplyEvent,
35
36    kConnectGetReplyEvent,
37    kConnectWatchdogTimeoutEvent,
38    kConnectDisconnectRequestEvent,
39    kConnectDisconnectReplyEvent,
40
41    kListenPendListenReplyEvent,
42    kListenPendDiscRequestEvent,
43    kListenPendDiscReplyEvent,
44
45    kListenGetReplyEvent,
46    kListenPutReplyEvent,
47    kListenDisconnectRequestEvent,
48    kListenDisconnectReplyEvent,
49
50    kAcceptConnectRequestEvent,
51    kRejectConnectRequestEvent,
52    kAccRejPutReplyEvent,
53    kAccRejDisconnectReplyEvent,
54
55    kDTRPutRequestEvent,
56    kDTRGetRequestEvent,
57    kDTRPutReplyEvent,
58    kDTRGetReplyEvent,
59    kDTRCancelPutRequestEvent,
60    kDTRCancelGetRequestEvent,
61    kDTRCancelPutReplyEvent,
62    kDTRCancelGetReplyEvent,
63    kDTRDisconnectRequestEvent,
64    kDTRDisconnectReplyEvent,
65    kDTRReleaseRequestEvent,
66
67    kMyData,
68    kDataForMe,
69    kDataWaitingForMe,
70    kLogRejectingMyData,
71
72    kGetMyId,           //
73
74    kLogDiscPendingEvent,
75    kLogDiscPendingClient,
76    kLogDiscPendingRejectRequest,
77    kLogDiscPendingMiscReply,
78    kLogDiscPendingConnLstnDone,
79    kLogDiscPendingInternalDisc,
80    kLogDiscPendingWatchDog,
81    kLogDiscPendingDiscDone,
82    kLogDiscPendingRequeue,
83
84    kEnqueueEvent,
85    kDequeueEventStart,
86    kDequeueEventEnd
87
88};
89
90static
91EventTraceCauseDesc IrLSAPConnTraceEvents[] = {
92    {kNullEvent,                    "IrLSAPConn: null event"},
93    {kDestroy,                      "IrLSAPConn: destroy obj="},
94    {kDeInit,                       "IrLSAPConn: DeInit"},
95    {kUnexpectedEvent,              "IrLSAPConn: unexpected event"},
96
97    {kDiscConnectEvent,             "IrLSAPConn: disc connect request"},
98    {kDiscListenEvent,              "IrLSAPConn: disc listen request"},
99    {kDiscDiscRequestEvent,         "IrLSAPConn: disc disconnect request"},
100    {kDiscLeftoversReplyEvent,      "IrLSAPConn: disc leftovers reply"},
101
102    {kConnectPendConnectReplyEvent, "IrLSAPConn: conn pend got LAP reply"},
103    {kConnectPendPutReplyEvent,     "IrLSAPConn: conn pend put LM-PDU conn request"},
104    {kConnectPendDiscRequestEvent,  "IrLSAPConn: conn pend disconnect request"},
105    {kConnectPendDiscReplyEvent,    "IrLSAPConn: conn pend disconnect reply"},
106
107    {kConnectGetReplyEvent,         "IrLSAPConn: connect got LM-PDU conn reply"},
108    {kConnectWatchdogTimeoutEvent,  "IrLSAPConn: connect watchdog timed out"},
109    {kConnectDisconnectRequestEvent,"IrLSAPConn: connect disconnect request"},
110    {kConnectDisconnectReplyEvent,  "IrLSAPConn: connect disconnect reply"},
111
112    {kListenPendListenReplyEvent,   "IrLSAPConn: lstn pend got LAP reply"},
113    {kListenPendDiscRequestEvent,   "IrLSAPConn: lstn pend disconnect request"},
114    {kListenPendDiscReplyEvent,     "IrLSAPConn: lstn pend disconnect reply"},
115
116    {kListenGetReplyEvent,          "IrLSAPConn: listen got LM-PDU conn request"},
117    {kListenPutReplyEvent,          "IrLSAPConn: listen put LM-PDU disc reply"},
118    {kListenDisconnectRequestEvent, "IrLSAPConn: listen disconnect request"},
119    {kListenDisconnectReplyEvent,   "IrLSAPConn: listen disconnect reply"},
120
121    {kAcceptConnectRequestEvent,    "IrLSAPConn: accept connect request"},
122    {kRejectConnectRequestEvent,    "IrLSAPConn: reject connect request"},
123    {kAccRejPutReplyEvent,          "IrLSAPConn: acc/rej put LM-PDU conn/disc reply"},
124    {kAccRejDisconnectReplyEvent,   "IrLSAPConn: acc/rej disconnect reply"},
125
126    {kDTRPutRequestEvent,           "IrLSAPConn: DTR put request"},
127    {kDTRGetRequestEvent,           "IrLSAPConn: DTR get request"},
128    {kDTRPutReplyEvent,             "IrLSAPConn: DTR put reply"},
129    {kDTRGetReplyEvent,             "IrLSAPConn: DTR get reply"},
130    {kDTRCancelPutRequestEvent,     "IrLSAPConn: DTR cancel put request"},
131    {kDTRCancelGetRequestEvent,     "IrLSAPConn: DTR cancel get request"},
132    {kDTRCancelPutReplyEvent,       "IrLSAPConn: DTR cancel put reply"},
133    {kDTRCancelGetReplyEvent,       "IrLSAPConn: DTR cancel get reply"},
134    {kDTRDisconnectRequestEvent,    "IrLSAPConn: DTR disconnect request"},
135    {kDTRDisconnectReplyEvent,      "IrLSAPConn: DTR disconnect reply"},
136    {kDTRReleaseRequestEvent,       "IrLSAPConn: DTR release request"},
137
138    {kMyData,                       "IrLSAPConn: checking packet header"},
139    {kDataForMe,                    "IrLSAPConn: data for this LSAP" },
140    {kDataWaitingForMe,             "IrLSAPConn: data waiting for this LSAP" },
141    {kLogRejectingMyData,           "IrLSAPConn: rejecting listen attempt, state="},
142
143    {kGetMyId,                      "IrLSAPConn: get my id. obj=, id="},
144    {kLogDiscPendingEvent,          "IrLSAPConn: disconnect pending, 0, event"},
145    {kLogDiscPendingClient,         "IrLSAPConn: disconnect pending, client=="},
146    {kLogDiscPendingRejectRequest,  "IrLSAPConn: disconnect pending, rejecting request"},
147    {kLogDiscPendingMiscReply,      "IrLSAPConn: disconnect pending, reply. event, pendevent"},
148    {kLogDiscPendingConnLstnDone,   "IrLSAPConn: disconnect pending, connlstn done"},
149    {kLogDiscPendingInternalDisc,   "IrLSAPConn: disconnect pending, internal discon (pending event, result)"},
150    {kLogDiscPendingWatchDog,       "IrLSAPConn: disconnect pending, watchdog timer"},
151    {kLogDiscPendingDiscDone,       "IrLSAPConn: disconnect pending, disconnect complete, result="},
152    {kLogDiscPendingRequeue,        "IrLSAPConn: disconnect pending, requeue event"},
153
154
155    {kEnqueueEvent,                 "IrLSAPConn: Event Queued"},
156    {kDequeueEventStart,            "IrLSAPConn: Event Start"},
157    {kDequeueEventEnd,              "IrLSAPConn: Event End"}
158};
159
160#define XTRACE(x, y, z) IrDALogAdd( x, y, (uintptr_t)z & 0xffff, IrLSAPConnTraceEvents, true)
161#else
162#define XTRACE(x, y, z) ((void)0)
163#endif
164
165#define GetLMP  (fIrDA->GetLMP())
166
167#define super TIrStream
168    OSDefineMetaClassAndStructors(TLSAPConn, TIrStream);
169
170//--------------------------------------------------------------------------------
171//      TLSAPConn
172//--------------------------------------------------------------------------------
173/*static*/
174TLSAPConn *
175TLSAPConn::tLSAPConn(TIrGlue* irda, TIrStream* client)
176{
177    TLSAPConn *obj = new TLSAPConn;
178
179    XTRACE(kNullEvent, 0, obj);
180
181    if (obj && !obj->Init(irda, client)) {
182	obj->release();
183	obj = nil;
184    }
185    return obj;
186}
187
188
189//--------------------------------------------------------------------------------
190//      free
191//--------------------------------------------------------------------------------
192void
193TLSAPConn::free()
194{
195    XTRACE(kDestroy, 0, this);
196    // Free things allocated by TLSAPConn
197    // Release my lsapId if it was obtained
198    if ((fMyLSAPId != kInvalidLSAPId) && (fMyLSAPId != kNameServerLSAPId)) {
199	fIrDA->ReleaseLSAPId(fMyLSAPId);
200    }
201    fMyLSAPId = kInvalidLSAPId;
202
203    if (fPendingRequests) {     // cleanup pending event list
204	fPendingRequests->release();
205	fPendingRequests = nil;
206    }
207
208    super::free();
209} // TLSAPConn::free
210
211
212//--------------------------------------------------------------------------------
213//      Init
214//--------------------------------------------------------------------------------
215Boolean TLSAPConn::Init(TIrGlue* irda, TIrStream* client)
216{
217
218    fState = kLSAPConnDisconnected;
219    fConnecting = false;
220    fClient = nil;
221    fResult = noErr;
222
223    fPendConnLstn = nil;
224    fConnLstnUserData = nil;
225    fGetData = nil;
226    fGetOffset = fGetLength = 0;
227
228    fMyLSAPId = fPeerLSAPId = kInvalidLSAPId;
229    fDevAddr = fLSAPId = 0;
230
231    fPendingRequests = nil;
232    fWatchdogTimerActive = false;
233    fWatchdogTimerCount = 0;
234
235
236#if (hasTracing > 0 && hasLSAPConnTracing > 0)
237    if (!super::Init(irda, IrLSAPConnTraceEvents, kEnqueueEvent)) return false;
238#else
239    if (!super::Init(irda)) return false;
240#endif
241
242    // All confirms/indications directed back to the client
243    fClient = client;
244
245    fPendingRequests = CList::cList();
246    require(fPendingRequests, Fail);
247
248    return true;
249
250Fail:
251
252    return false;
253
254} // TLSAPConn::Init
255
256
257//--------------------------------------------------------------------------------
258//      AssignId
259//--------------------------------------------------------------------------------
260void TLSAPConn::AssignId(ULong id)
261{
262    XASSERT(fMyLSAPId == kInvalidLSAPId);
263    fMyLSAPId = (UByte)id;
264
265} // TLSAPConn::AssignId
266
267
268//--------------------------------------------------------------------------------
269//      GetMyLSAPId
270//--------------------------------------------------------------------------------
271UByte TLSAPConn::GetMyLSAPId(void)
272{
273    XTRACE(kGetMyId, 0, this);
274    XTRACE(kGetMyId, 0, fMyLSAPId);
275    return fMyLSAPId;
276};
277
278
279
280//--------------------------------------------------------------------------------
281//      NextState
282//--------------------------------------------------------------------------------
283void TLSAPConn::NextState(ULong event)
284{
285    switch (fState) {
286	case kLSAPConnDisconnected:
287	    HandleDisconnectedStateEvent(event);
288	    break;
289
290	case kLSAPConnConnectPending:
291	    HandleConnectPendingStateEvent(event);
292	    break;
293
294	case kLSAPConnConnect:
295	    HandleConnectStateEvent(event);
296	    break;
297
298	case kLSAPConnListenPending:
299	    HandleListenPendingStateEvent(event);
300	    break;
301
302	case kLSAPConnListen:
303	    HandleListenStateEvent(event);
304	    break;
305
306	case kLSAPConnAccept:
307	    HandleAcceptStateEvent(event);
308	    break;
309
310	case kLSAPConnDataTransferReady:
311	    HandleDataTransferReadyStateEvent(event);
312	    break;
313
314	case kLSAPDisconnectPending:
315	    HandleDisconnectPendingStateEvent(event);
316	    break;
317
318
319	default:
320	    DebugLog("TLSAPConn::NextState: bad fState");
321	    break;
322    }
323
324} // TLSAPConn::NextState
325
326
327//--------------------------------------------------------------------------------
328//      HandleDisconnectedStateEvent
329//--------------------------------------------------------------------------------
330void TLSAPConn::HandleDisconnectedStateEvent(ULong event)
331{
332    switch (event) {
333	case kIrConnectRequestEvent:
334	case kIrListenRequestEvent:
335	    {
336		XTRACE(event == kIrConnectRequestEvent ? kDiscConnectEvent : kDiscListenEvent,  fMyLSAPId, 0);
337		// Forward the connect/listen request to IrLAPConn (via LMP station control)
338		TIrConnLstnRequest* connLstnReq = (TIrConnLstnRequest*)GetCurrentEvent();
339
340		// Queue request for LMP
341		PassRequestToLMP();
342
343		// Remember original request (to distinguish internal/external disconnect replies)
344		SaveCurrentRequest();
345
346		// Keep track of original connect request so IrLAPConn can reply
347		XASSERT(fPendConnLstn == nil);
348		fPendConnLstn = GetCurrentEvent();
349
350		// Remember the user data buffer until needed by GetControlFrame or PutControlFrame
351		fConnLstnUserData = connLstnReq->fData;
352
353		if (event == kIrConnectRequestEvent) {
354		    fConnecting = true;
355
356		    // For connect, remember lsap id we're connecting to
357		    fPeerLSAPId = connLstnReq->fLSAPId;
358
359		    // Wait for bind complete
360		    fState = kLSAPConnConnectPending;
361		}
362		else {
363		    fConnecting = false;
364
365		    // For listen, set lsap id to pending connect
366		    fPeerLSAPId = kPendingConnectLSAPId;
367
368		    // Wait for bind complete
369		    fState = kLSAPConnListenPending;
370		}
371	    }
372	    break;
373
374	case kIrDisconnectRequestEvent:
375	    {
376		XTRACE(kDiscDiscRequestEvent, 0, 0);
377		// We're not connected - return reply back to client
378		TIrDisconnectRequest* disconnectReq = (TIrDisconnectRequest*)GetCurrentEvent();
379		disconnectReq->fEvent = kIrDisconnectReplyEvent;
380		fClient->EnqueueEvent(disconnectReq);
381	    }
382	    break;
383
384	case kIrGetDataRequestEvent:
385	case kIrPutDataRequestEvent:
386	    {
387		// Throw any get/put requests that were in the pipeline back with an error
388		TIrEvent* getPutReq = (TIrEvent*)GetCurrentEvent();
389		XTRACE(kDiscLeftoversReplyEvent, event, 0);
390		XTRACE(kDiscLeftoversReplyEvent, 0, fClient);   // testing
391		getPutReq->fEvent = (UByte)RequestIdToReplyId(getPutReq->fEvent);
392		getPutReq->fResult = kIrDAErrNotConnected;  // ***FIXME: Better result code?
393		fClient->EnqueueEvent(getPutReq);
394	    }
395	    break;
396
397	case kIrGetDataReplyEvent:
398	case kIrPutDataReplyEvent:
399	case kIrDisconnectReplyEvent:
400	    {
401		check(event != kIrDisconnectReplyEvent);     // jdg: shouldn't be getting disconnect complete anymore
402		// Some requests unwind after going to the disconnect state
403		// Pass the replies up to the client
404		TIrEvent* reply = (TIrEvent*)GetCurrentEvent();
405		XTRACE(kDiscLeftoversReplyEvent, event, reply->fPendEvent);
406		XTRACE(kDiscLeftoversReplyEvent, 0, fClient);   // testing
407		reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent);
408		fClient->EnqueueEvent(reply);
409	    }
410	    break;
411
412	default:
413	    XTRACE(kUnexpectedEvent, fState, event);
414	    DebugLog("TLSAPConn::HandleDisconnectedStateEvent: bad event");
415	    break;
416    }
417
418} // TLSAPConn::HandleDisconnectedStateEvent
419
420
421//--------------------------------------------------------------------------------
422//      HandleConnectPendingStateEvent
423//--------------------------------------------------------------------------------
424void TLSAPConn::HandleConnectPendingStateEvent(ULong event)
425{
426    switch (event) {
427	case kIrConnectReplyEvent:
428	    {
429		TIrConnLstnReply* connectReply = (TIrConnLstnReply*)GetCurrentEvent();
430		XTRACE(kConnectPendConnectReplyEvent, 0, connectReply->fResult);
431		if (connectReply->fResult != noErr) {
432		    // Connect failed - unbind from LAPConn.
433		    DisconnectStart(connectReply->fResult);     // need to take this lsapconn off lapconn's list
434		    //fPendConnLstn = nil;                      // jdg
435		    //fState = kLSAPConnDisconnected;               // jdg added
436		    //fClient->EnqueueEvent(GetCurrentEvent()); // jdg added
437		}
438		else {
439		    // JDG: SAVE SOME USEFUL INFO from the connect reply event record!
440		    fDevAddr = connectReply->fDevAddr;  // restored to event record during listen complete
441		    fLSAPId  = connectReply->fLSAPId;
442
443		    // Connect succeeded - send LM-PDU connect request
444		    PutControlFrame(kLMPDUConnectRequest, 0);
445		}
446	    }
447	    break;
448
449	case kIrPutDataReplyEvent:
450	    {
451		TIrPutReply* putReply = (TIrPutReply*)GetCurrentEvent();
452		XTRACE(kConnectPendPutReplyEvent, 0, putReply->fResult);
453		// The LM-PDU connect request has been sent and received by peer device
454		if (putReply->fResult != noErr) {
455		    // Put failed (perhaps IrLAP disconnected) - unbind from LAPConn.
456		    DisconnectStart(putReply->fResult);
457		}
458		else {
459		    // Start watchdog timer
460		    StartConnectTimer();
461		    // Now wait for the LM-PDU connect reply
462		    GetControlFrame();
463		    fState = kLSAPConnConnect;
464		}
465	    }
466	    break;
467
468	case kIrDisconnectRequestEvent:
469	    {
470		XTRACE(kConnectPendDiscRequestEvent, 0, 0);
471		// Remember original request (to distinguish internal/external disconnect replies)
472		SaveCurrentRequest();
473		fState = kLSAPDisconnectPending;            // JDG: we're on the way out, change state
474		// Pass disconnect on
475		PassRequestToLMP();
476	    }
477	    break;
478
479	case kIrDisconnectReplyEvent:
480	    {
481		check(event != kIrDisconnectReplyEvent); // jdg: shouldn't be getting disconnect complete anymore
482		fState = kLSAPConnDisconnected;
483		if (InternalDisconnectRequest()) {
484		    XTRACE(kConnectPendDiscReplyEvent, 0, fResult);
485		    ConnLstnComplete(fResult);
486		}
487		else {
488		    XTRACE(kConnectPendDiscReplyEvent, 0, 0);
489		    fPendConnLstn = nil;                        // jdg: this is done by ConnLstnComplete, need it here too
490		    fClient->EnqueueEvent(GetCurrentEvent());
491		}
492	    }
493	    break;
494
495	default:
496	    XTRACE(kUnexpectedEvent, fState, event);
497	    DebugLog("TLSAPConn::HandleConnectPendingStateEvent: bad event");
498	    break;
499    }
500
501} // TLSAPConn::HandleConnectPendingStateEvent
502
503
504//--------------------------------------------------------------------------------
505//      HandleConnectStateEvent
506//--------------------------------------------------------------------------------
507void TLSAPConn::HandleConnectStateEvent(ULong event)
508{
509    switch (event) {
510	case kIrGetDataReplyEvent:
511	    {
512		TIrGetReply* getReply = (TIrGetReply*)GetCurrentEvent();
513		XTRACE(kConnectGetReplyEvent, getReply->fCtrlOpCode, getReply->fResult);
514		// Cancel watchdog timer
515		StopConnectTimer();
516		if (getReply->fResult != noErr) {
517		    // Get failed (perhaps IrLAP disconnected) - unbind from LAPConn.
518		    DisconnectStart(getReply->fResult);
519		}
520		else {
521		    switch(getReply->fCtrlOpCode) {
522			case kLMPDUConnectRequest:
523			    DisconnectStart(kIrDAErrGeneric /* FIXME: kIrErrConnectionRace */);
524			    break;
525
526			case kLMPDUDisconnectEvent:
527			    // ***FIXME: Translate fCtrlInfo to result code?
528			    DisconnectStart(kIrDAErrGeneric /* FIXME: kIrErrSomeError */);
529			    break;
530
531			case kLMPDUConnectReply:
532			    ConnLstnComplete(noErr);
533			    fState = kLSAPConnDataTransferReady;
534			    break;
535
536			default:
537			    DebugLog("TLSAPConn::HandleConnectStateEvent: unexpected ctrl opcode");
538			    break;
539		    }
540		}
541	    }
542	    break;
543
544	case kIrConnWatchdogExpiredEvent:
545	    {
546		XTRACE(kConnectWatchdogTimeoutEvent, 0, 0);
547		// Cancel watchdog timer
548		StopConnectTimer();
549
550		// JDG: I don't think we can just grab our pending listen event, since it's been turned
551		// into a 'get' event request and passed onto LMP and LAPConn and LAP
552		//DisconnectStart(kIRErrGeneric /* FIXME: kIrErrNonResponsivePeer */, (TIrDisconnectRequest*)fPendConnLstn);
553		if (1) {        // let's allocate a new event block for a disconnect request
554		    TIrDisconnectRequest    *disconnectRequest;
555		    disconnectRequest = (TIrDisconnectRequest*)fIrDA->GrabEventBlock(kIrDisconnectRequestEvent, sizeof(TIrDisconnectRequest));
556		    check(disconnectRequest);           // better have one available
557		    if (disconnectRequest) {
558			// we're going to use the fPendEvent field as a flag to disconnect complete that
559			// this event is one that we've allocated ourselves, not to be confused with a
560			// client disconnect request, or another internally generated disconnect request
561			// and one that should have the event record freed!
562			disconnectRequest->fPendEvent = kIrConnWatchdogExpiredEvent;    // mark as ours
563			DisconnectStart(kIrDAErrGeneric, disconnectRequest);
564			// note - in disconnect reply, it frees the event record fPendingEvent is watchdog
565		    }
566		}
567	    }
568	    break;
569
570	case kIrDisconnectRequestEvent:
571	    XTRACE(kConnectDisconnectRequestEvent, 0, 0);
572	    // Cancel watchdog timer
573	    StopConnectTimer();
574	    // Remember original request (to distinguish internal/external disconnect replies)
575	    SaveCurrentRequest();
576	    fState = kLSAPDisconnectPending;            // JDG: we're on the way out, change state
577	    // Pass disconnect on
578	    PassRequestToLMP();
579	    break;
580
581	case kIrDisconnectReplyEvent:
582	    check(event != kIrDisconnectReplyEvent); // jdg: shouldn't be getting disconnect complete anymore
583	    fState = kLSAPConnDisconnected;
584	    if (InternalDisconnectRequest()) {
585		XTRACE(kConnectDisconnectReplyEvent, 0, fResult);
586		ConnLstnComplete(fResult);
587	    }
588	    else {
589		XTRACE(kConnectDisconnectReplyEvent, 0, 0);
590		fPendConnLstn = nil;                        // jdg: this is done by ConnLstnComplete, need it here too
591		fClient->EnqueueEvent(GetCurrentEvent());
592	    }
593	    break;
594
595	default:
596	    XTRACE(kUnexpectedEvent, fState, event);
597	    DebugLog("TLSAPConn::HandleConnectStateEvent: bad event");
598	    break;
599    }
600
601} // TLSAPConn::HandleConnectStateEvent
602
603
604//--------------------------------------------------------------------------------
605//      HandleListenPendingStateEvent
606//--------------------------------------------------------------------------------
607void TLSAPConn::HandleListenPendingStateEvent(ULong event)
608{
609    switch (event) {
610	case kIrListenReplyEvent:
611	    {
612		TIrConnLstnReply* listenReply = (TIrConnLstnReply*)GetCurrentEvent();
613		XTRACE(kListenPendListenReplyEvent, fMyLSAPId, listenReply->fResult);
614		if (listenReply->fResult != noErr) {
615		    // Listen failed - unbind from LAPConn.
616		    DisconnectStart(listenReply->fResult);  // jdg . may be broken
617		    /////////////////////////////////////////////////////////////////////////////
618		    //fPendConnLstn = nil;                      // jdg added
619		    //fState = kLSAPConnDisconnected;               // jdg added
620		    //fClient->EnqueueEvent(GetCurrentEvent()); // jdg added
621
622		}
623		else {
624		    // JDG: SAVE SOME USEFUL INFO from the listen reply event record!
625		    fDevAddr = listenReply->fDevAddr;   // restored to event record during listen complete
626		    fLSAPId  = listenReply->fLSAPId;
627
628		    // Wait for an LM-PDU connect request
629		    GetControlFrame();
630		    fState = kLSAPConnListen;
631		}
632	    }
633	    break;
634
635	case kIrDisconnectRequestEvent:
636	    XTRACE(kListenPendDiscRequestEvent, 0, 0);
637	    // Remember original request (to distinguish internal/external disconnect replies)
638	    SaveCurrentRequest();
639	    fState = kLSAPDisconnectPending;            // JDG: we're on the way out, change state
640	    // Pass disconnect on
641	    PassRequestToLMP();
642	    break;
643
644	case kIrDisconnectReplyEvent:
645	    check(event != kIrDisconnectReplyEvent); // jdg: shouldn't be getting disconnect complete anymore
646	    fState = kLSAPConnDisconnected;
647	    if (InternalDisconnectRequest()) {
648		XTRACE(kListenPendDiscReplyEvent, 1, fResult);
649		// jdg: well if it's an internal disconnect, why bother the lsap owner with an
650		// abort?  let's just requeue it and let it work later
651		ConnLstnComplete(fResult);
652		if (0) {                // needs more testing
653		    TIrConnLstnRequest *req = (TIrConnLstnRequest*)GetCurrentEvent();
654		    check(req->fPendEvent == kIrListenRequestEvent);
655		    req->fEvent = req->fPendEvent;      // restore original request
656		    fPendConnLstn = nil;                // reset pending
657		    this->EnqueueEvent(req);            // requeue back for another try
658		}
659	    }
660	    else {
661		XTRACE(kListenPendDiscReplyEvent, 2, 0);
662		if (1) {            // jdg: new code to clean up pending listen request
663		    TIrConnLstnReply* reply = (TIrConnLstnReply*)fPendConnLstn;
664		    XASSERT(fPendConnLstn != nil);      // there should be a pending listen at this point
665		    reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent);   // turn into listen complete
666		    reply->fResult = kIrDAErrRequestCanceled;
667		    fClient->EnqueueEvent(reply);
668		}
669		fPendConnLstn = nil;                        // jdg: this is done by ConnLstnComplete, need it here too
670		fClient->EnqueueEvent(GetCurrentEvent());   // jdg: or we can't do another listen/connect request
671	    }
672	    break;
673
674	default:
675	    XTRACE(kUnexpectedEvent, fState, event);
676	    DebugLog("TLSAPConn::HandleListenPendingStateEvent: bad event");
677	    break;
678    }
679
680} // TLSAPConn::HandleListenPendingStateEvent
681
682
683//--------------------------------------------------------------------------------
684//      HandleListenStateEvent
685//--------------------------------------------------------------------------------
686void TLSAPConn::HandleListenStateEvent(ULong event)
687{
688    switch (event) {
689	case kIrGetDataReplyEvent:
690	    {
691		TIrGetReply *getReply = (TIrGetReply *) GetCurrentEvent();
692		XTRACE(kListenGetReplyEvent, getReply->fCtrlOpCode, getReply->fResult);
693		if (getReply->fResult != noErr) {
694		    // Get failed (perhaps IrLAP disconnected) - unbind from LAPConn.
695		    DisconnectStart(getReply->fResult);     // jdg - may be broken
696		    //fPendConnLstn = nil;                      // jdg added
697		    //fState = kLSAPConnDisconnected;               // jdg added
698		    //fClient->EnqueueEvent(GetCurrentEvent()); // jdg added
699		}
700		else {
701		    switch(getReply->fCtrlOpCode) {
702			case kLMPDUDataEvent:
703			case kLMPDUConnectReply:
704			    PutControlFrame(kLMPDUDisconnectEvent, kIrDataSentOnDiscLSAPConn);
705			    break;
706
707			case kLMPDUConnectRequest:
708			    {
709				TIrConnLstnReply* listenReply = (TIrConnLstnReply*)GetCurrentEvent();
710
711				// Do the LM-Listen reply
712				listenReply->fLSAPId = fPeerLSAPId;
713				ConnLstnComplete(noErr);
714				fState = kLSAPConnAccept;
715			    }
716			    break;
717
718			default:
719			    DebugLog("TLSAPConn::HandleListenStateEvent: unexpected ctrl opcode");
720			    break;
721		    }
722		}
723	    }
724	    break;
725
726	case kIrPutDataReplyEvent:
727	    {
728		TIrPutReply *putReply = (TIrPutReply *) GetCurrentEvent();
729		XTRACE(kListenPutReplyEvent, 0, putReply->fResult);
730		// The LM-PDU disconnect event has been sent and received by peer device
731		if (putReply->fResult != noErr) {
732		    // Put failed (perhaps IrLAP disconnected) - unbind from LAPConn.
733		    DisconnectStart(putReply->fResult);
734		}
735		else {
736		    // Wait for an LM-PDU connect request (again)
737		    GetControlFrame();
738		}
739	    }
740	    break;
741
742	case kIrDisconnectRequestEvent:
743	    XTRACE(kListenDisconnectRequestEvent, 0, 0);
744	    // Remember original request (to distinguish internal/external disconnect replies)
745	    SaveCurrentRequest();
746	    fState = kLSAPDisconnectPending;            // JDG: we're on the way out, change state
747	    // Pass disconnect on
748	    PassRequestToLMP();
749	    break;
750
751	case kIrDisconnectReplyEvent:
752	    check(event != kIrDisconnectReplyEvent); // jdg: shouldn't be getting disconnect complete anymore
753	    fState = kLSAPConnDisconnected;
754	    if (InternalDisconnectRequest()) {
755		XTRACE(kListenDisconnectReplyEvent, 0, fResult);
756		ConnLstnComplete(fResult);
757		if (0) {            // jdg: let's reissue the listen instead of aborting it
758		    TIrConnLstnRequest *req = (TIrConnLstnRequest*)GetCurrentEvent();
759		    //check(req->fPendEvent == kIrListenRequestEvent);
760		    if (req->fPendEvent == kIrListenRequestEvent) { // if a listen pending
761			req->fEvent = req->fPendEvent;      // restore original request
762			fPendConnLstn = nil;                // reset pending
763			this->EnqueueEvent(req);            // requeue back for another try
764		    }
765		}
766
767	    }
768	    else {
769		XTRACE(kListenDisconnectReplyEvent, 0, 0);
770		fPendConnLstn = nil;                        // jdg: this is done by ConnLstnComplete, need it here too
771		fClient->EnqueueEvent(GetCurrentEvent());
772	    }
773	    break;
774
775	default:
776	    XTRACE(kUnexpectedEvent, fState, event);
777	    DebugLog("TLSAPConn::HandleListenStateEvent: bad event");
778	    break;
779    }
780
781} // TLSAPConn::HandleListenStateEvent
782
783
784//--------------------------------------------------------------------------------
785//      HandleAcceptStateEvent
786//--------------------------------------------------------------------------------
787void TLSAPConn::HandleAcceptStateEvent(ULong event)
788{
789    switch (event) {
790	case kIrAcceptRequestEvent:
791	    // Client accepts the incoming connection
792	    XTRACE(kAcceptConnectRequestEvent, 0, 0);
793	    // Remember the accept request (to distinguish internal/external disconnect replies)
794	    SaveCurrentRequest();
795	    // Remember the user data buffer until needed by PutControlFrame
796	    fConnLstnUserData = ((TIrConnLstnRequest*)GetCurrentEvent())->fData;
797	    // Send a LM-Listen reply
798	    PutControlFrame(kLMPDUConnectReply, 0);
799	    break;
800
801	case kIrDisconnectRequestEvent:
802	    // Client rejects the incoming connection
803	    XTRACE(kRejectConnectRequestEvent, 0, 0);
804	    // Remember the disconnect request (to distinguish internal/external disconnect replies)
805	    SaveCurrentRequest();
806	    // Send a Disconnect request
807	    PutControlFrame(kLMPDUDisconnectEvent, kIrUserRequestedDisconnect);
808	    break;
809
810	case kIrPutDataReplyEvent:
811	    XTRACE(kAccRejPutReplyEvent, 0, 0);
812	    if (GetCurrentEvent()->fPendEvent == kIrAcceptRequestEvent) {
813		// Finish up the accept of the connection
814		// The LM-PDU connect reply has been sent and received by peer device
815		// Now ready to send and receive data on this connection
816		// Let the caller know by replying to the accept
817		TIrPutReply* putReply = (TIrPutReply*)GetCurrentEvent();
818		if (putReply->fResult != noErr) {
819		    DisconnectStart(putReply->fResult);
820		}
821		else {
822		    ConnLstnComplete(noErr);
823		    fState = kLSAPConnDataTransferReady;
824		}
825	    }
826	    else {
827		XASSERT(GetCurrentEvent()->fPendEvent == kIrDisconnectRequestEvent);
828		// Finish up the rejection of the connection
829		// The LM-PDU disconnect has been sent and received by peer device
830		// Now unbind from LAPConn.
831		// Note: passing noErr since initiated by client.
832		// Note: Do the disconnect even if error came back from put.
833		DisconnectStart(noErr);
834	    }
835	    break;
836
837	case kIrDisconnectReplyEvent:
838	    check(event != kIrDisconnectReplyEvent); // jdg: shouldn't be getting disconnect complete anymore
839	    XTRACE(kAccRejDisconnectReplyEvent, 0, fResult);
840	    // LAPConn unbind complete.  Now complete the accept or disconnect request
841	    ConnLstnComplete(fResult);
842	    fState = kLSAPConnDisconnected;
843	    break;
844
845	default:
846	    XTRACE(kUnexpectedEvent, fState, event);
847	    DebugLog("TLSAPConn::HandleAcceptStateEvent: bad event");
848	    break;
849    }
850
851} // TLSAPConn::HandleAcceptStateEvent
852
853
854//--------------------------------------------------------------------------------
855//      HandleDataTransferReadyStateEvent
856//--------------------------------------------------------------------------------
857void TLSAPConn::HandleDataTransferReadyStateEvent(ULong event)
858{
859    switch (event) {
860	case kIrGetDataRequestEvent:
861	    XTRACE(kDTRGetRequestEvent, 0, 0);
862	    // Remember original request (to distinguish internal/external disconnect replies)
863	    SaveCurrentRequest();
864	    // Pass get request to station control (LMP)
865	    GetDataFrame();
866	    break;
867
868	case kIrPutDataRequestEvent:
869	    XTRACE(kDTRPutRequestEvent, 0, 0);
870	    // Remember original request (to distinguish internal/external disconnect/put replies)
871	    SaveCurrentRequest();
872	    // Fill in opCode, dstSel, srcSel fields and pass request to station control (LMP)
873	    PutDataFrame();
874	    break;
875
876	case kIrCancelGetRequestEvent:
877	case kIrCancelPutRequestEvent:
878	    XTRACE(event == kIrCancelGetRequestEvent ? kDTRCancelGetRequestEvent : kDTRCancelPutRequestEvent, 0, 0);
879	    // Pass request to station control (LMP)
880	    PassRequestToLMP();
881	    break;
882
883	case kIrReleaseRequestEvent:
884	case kIrDisconnectRequestEvent:
885	    XTRACE(event == kIrReleaseRequestEvent ? kDTRReleaseRequestEvent : kDTRDisconnectRequestEvent, 0, 0);
886	    // Remember original request (to distinguish internal/external disconnect replies)
887	    SaveCurrentRequest();
888	    // Send a Disconnect request
889	    fState = kLSAPDisconnectPending;            // JDG: we're on the way out, change state
890	    PutControlFrame(kLMPDUDisconnectEvent, kIrUserRequestedDisconnect);
891	    break;
892
893	case kIrGetDataReplyEvent:
894	    {
895		TIrGetReply* getReply = (TIrGetReply*)GetCurrentEvent();
896		XTRACE(kDTRGetReplyEvent, getReply->fCtrlOpCode, 0);
897		if (getReply->fResult != noErr) {
898		    // Check to see if get was cancelled (vs error from IrLAP)
899		    if (getReply->fResult == kIrDAErrRequestCanceled) {
900			// Pass get reply up to the client
901			fClient->EnqueueEvent(getReply);
902		    }
903		    // Get failed (perhaps IrLAP disconnected) - unbind from LAPConn.
904		    else {
905			DisconnectStart(getReply->fResult);
906		    }
907		}
908		else {
909		    switch(getReply->fCtrlOpCode) {
910			case kLMPDUDataEvent:
911			    // Pass get reply up to the client
912			    fClient->EnqueueEvent(getReply);
913			    break;
914
915			case kLMPDUConnectRequest:
916			    // Reply with half open error
917			    PutControlFrame(kLMPDUDisconnectEvent, kIrHalfOpen);
918			    break;
919
920			case kLMPDUDisconnectEvent:
921			    // ***FIXME: Translate fCtrlInfo to result code?
922			    DisconnectStart(kIrDAErrGeneric /* FIXME: kIrErrSomeError */);
923			    break;
924
925			default:
926			    DebugLog("TLSAPConn::HandleDataTransferReadyStateEvent: unexpected ctrl opcode");
927			    GetDataFrame(true /* re-"posting" the request*/);
928			    break;
929		    }
930		}
931	    }
932	    break;
933
934	case kIrPutDataReplyEvent:
935	    {
936		TIrPutReply* putReply = (TIrPutReply*)GetCurrentEvent();
937		XTRACE(kDTRPutReplyEvent, 0, putReply->fResult);
938		if (InternalPutRequest()) {
939		    // If put reply was initiated by release or disconnect, send disconnect
940		    if ((putReply->fPendEvent == kIrReleaseRequestEvent) || (putReply->fPendEvent == kIrDisconnectRequestEvent)) {
941			DisconnectStart(noErr);
942		    }
943		    // Else put reply was in response to an unwanted received control frame (a connect)
944		    else {
945			XASSERT(putReply->fPendEvent == kIrGetDataRequestEvent);
946			DisconnectStart(kIrDAErrGeneric /* FIXME: kIrErrHalfOpen */);
947		    }
948		}
949		else {
950		    // Pass put reply up to the client
951		    fClient->EnqueueEvent(putReply);
952		}
953	    }
954	    break;
955
956	case kIrCancelGetReplyEvent:
957	case kIrCancelPutReplyEvent:
958	    XTRACE(event == kIrCancelGetReplyEvent ? kDTRCancelGetReplyEvent : kDTRCancelPutReplyEvent, 0, 0);
959	    // Pass put reply up to the client
960	    fClient->EnqueueEvent(GetCurrentEvent());
961	    break;
962
963	case kIrDisconnectReplyEvent:
964	    check(event != kIrDisconnectReplyEvent); // jdg: shouldn't be getting disconnect complete anymore
965	    if (InternalDisconnectRequest()) {
966		// Finish up whichever request initiated the disconnect
967		TIrEvent* reply = (TIrEvent*)GetCurrentEvent();
968		XTRACE(kDTRDisconnectReplyEvent, 0, fResult);
969		// Pass reply up to the client
970		reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent);
971		reply->fResult = fResult;
972		fClient->EnqueueEvent(reply);
973	    }
974	    else {
975		TIrDisconnectReply* disconnectReply;
976		disconnectReply = (TIrDisconnectReply*)GetCurrentEvent();
977		XTRACE(kDTRDisconnectReplyEvent, 0, disconnectReply->fResult);
978		// Pass disconnect reply up to the client
979		fClient->EnqueueEvent(disconnectReply);
980	    }
981	    fPendConnLstn = nil;                        // jdg: this is done by ConnLstnComplete, need it here too (?)
982	    fState = kLSAPConnDisconnected;
983	    break;
984
985	default:
986	    XTRACE(kUnexpectedEvent, fState, event);
987	    DebugLog("TLSAPConn::HandleDataTransferReadyStateEvent: bad event");
988	    break;
989    }
990
991} // TLSAPConn::HandleDataTransferReadyStateEvent
992
993//--------------------------------------------------------------------------------
994//      HandleDisconnectPendingStateEvent
995//--------------------------------------------------------------------------------
996void TLSAPConn::HandleDisconnectPendingStateEvent(ULong event)
997{
998    TIrEvent* eventBlock = (TIrEvent*)GetCurrentEvent();
999    //static int rejectCount = 0;               // temp debugging
1000
1001    XTRACE(kLogDiscPendingEvent, 0, event);
1002    XTRACE(kLogDiscPendingClient, 0, fClient);
1003
1004    switch (event) {
1005
1006	case kIrDisconnectRequestEvent:     // stall these requests until we can handle them
1007	case kIrConnectRequestEvent:
1008	case kIrListenRequestEvent:
1009	    fPendingRequests->InsertLast(GetCurrentEvent());
1010	    break;
1011
1012					    // we have a disconnect pending, don't do new requests
1013	case kIrAcceptRequestEvent:         // we have a disconnect pending, don't do new requests yet
1014	case kIrGetDataRequestEvent:
1015	case kIrPutDataRequestEvent:
1016	    // just send these back to the client
1017	    //rejectCount++;        // debugging
1018	    //XTRACE(kLogDiscPendingRejectRequest, rejectCount, event);
1019	    eventBlock->fEvent = (UByte)RequestIdToReplyId(eventBlock->fEvent);
1020	    eventBlock->fResult = kIrDAErrNotConnected;
1021	    fClient->EnqueueEvent(eventBlock);
1022	    //if (rejectCount == 20) DebugLog("lsapconn reject count hit 20");
1023	    break;
1024
1025	    // convert event back to reply of original, who cares if it worked or not,
1026	    // we have a disconnect reply coming real soon now
1027	case kIrListenReplyEvent:
1028	case kIrConnectReplyEvent:
1029	    eventBlock->fResult = kIrDAErrNotConnected;         // lap listen/conn reply, but we're disconnecting
1030	    // continue on
1031	case kIrGetDataReplyEvent:
1032	case kIrPutDataReplyEvent:
1033	    XTRACE(kLogDiscPendingMiscReply, event, eventBlock->fPendEvent);
1034	    if (GetCurrentEvent() == fPendConnLstn) {
1035		XTRACE(kLogDiscPendingConnLstnDone, 0, fPendConnLstn);
1036		fPendConnLstn = nil;            // there isn't a listen/connect pending event anymore
1037	    }
1038
1039	    eventBlock->fEvent = (UByte)RequestIdToReplyId(eventBlock->fPendEvent);
1040	    // don't stop on the result, it might have worked, esp with
1041	    // a lookup release request!
1042	    //eventBlock->fResult = kCommErrNotConnected;
1043
1044	    // oh my. if the client requested a disconnect, then the event is a putreply, even
1045	    // though the client requested a disconnect.  Sigh.  Let's rewrite this to use a
1046	    // different event record in the lsap/lmp/lap path than the one passed to us by
1047	    // the client!  Ok, let's see what's getting returned to the client ....
1048	    if (eventBlock->fEvent == kIrDisconnectReplyEvent       // client asked for a disconnect
1049		|| eventBlock->fEvent == kIrReleaseReplyEvent) {    // client asked for a disconnect via release
1050		check(fPendConnLstn == nil);        // should already have been cleared
1051		DisconnectStart(noErr);             // need to unbind from LAPConn's list of active LSAPConns
1052	    }
1053	    else
1054		fClient->EnqueueEvent(eventBlock);
1055	    break;
1056
1057
1058	case kIrDisconnectReplyEvent:
1059	    if (InternalDisconnectRequest()) {
1060		// Finish up whichever request initiated the disconnect
1061		XTRACE(kLogDiscPendingInternalDisc, eventBlock->fPendEvent, fResult);
1062		// Pass reply up to the client
1063		// but only if the event wasn't a disconnect generated by the watchdogtimer
1064		if (eventBlock->fPendEvent != kIrConnWatchdogExpiredEvent) {    // have a client's event block
1065		    eventBlock->fEvent = (UByte)RequestIdToReplyId(eventBlock->fPendEvent);
1066		    eventBlock->fResult = fResult;
1067		    fClient->EnqueueEvent(eventBlock);
1068		}
1069		else {          // else we have fPendEvent of kIrConnWatchdogExpiredEvent, so it's our event record
1070		    DebugLog("IrLSAPConn: just fyi, got disconnect reply after watchdog timeout");
1071		    XTRACE(kLogDiscPendingWatchDog, 0, 0);
1072		    fIrDA->ReleaseEventBlock(eventBlock);
1073		}
1074	    }
1075	    else {                              // original request was a disconnect request
1076		XTRACE(kLogDiscPendingDiscDone, 0, eventBlock->fResult);
1077		// Pass disconnect reply up to the client
1078		fClient->EnqueueEvent(eventBlock);
1079	    }
1080	    check(fPendConnLstn == nil);        // should already have been cleared
1081	    fState = kLSAPConnDisconnected;
1082
1083	    // Ok, now that we're cleanly disconnected (I hope), let's requeue all
1084	    // the pending requests that we've collected since the disconnect started
1085	    if (fPendingRequests && !fPendingRequests->Empty()) {
1086		TIrEvent* request;
1087		CListIterator *iter = CListIterator::cListIterator(fPendingRequests);
1088		for (request = (TIrEvent*)iter->FirstItem();
1089		     iter->More(); request = (TIrEvent*)iter->NextItem()) {
1090			XTRACE(kLogDiscPendingRequeue, 0, request->fEvent);
1091			this->EnqueueEvent(request);
1092		}
1093		while (!fPendingRequests->Empty())
1094		    fPendingRequests->RemoveLast();
1095		iter->release();
1096	    }
1097
1098	    break;
1099
1100	default:
1101	    XTRACE(kUnexpectedEvent, fState, event);
1102	    DebugLog("TLSAPConn::HandleDisconnectPendingStateEvent: bad event");
1103	    break;
1104    }
1105} // HandleDisconnectPendingStateEvent
1106
1107//================================ Helper methods ================================
1108
1109
1110//--------------------------------------------------------------------------------
1111//      SaveCurrentRequest
1112//--------------------------------------------------------------------------------
1113void TLSAPConn::SaveCurrentRequest()
1114{
1115    TIrEvent* request = GetCurrentEvent();
1116
1117    // Store the original request in fPendEvent
1118    request->fPendEvent = request->fEvent;
1119
1120} // TLSAPConn::SaveCurrentRequest
1121
1122
1123//--------------------------------------------------------------------------------
1124//      InternalDisconnectRequest?
1125//--------------------------------------------------------------------------------
1126Boolean TLSAPConn::InternalDisconnectRequest()
1127{
1128    // Is the current request *not* a disconnect request.  If its not, then this must
1129    // be a reply to an internally generated disconnect request sent to IrLMP.
1130    return GetCurrentEvent()->fPendEvent != kIrDisconnectRequestEvent;
1131
1132} // TLSAPConn::InternalDisconnectRequest
1133
1134
1135//--------------------------------------------------------------------------------
1136//      InternalPutRequest?
1137//--------------------------------------------------------------------------------
1138Boolean TLSAPConn::InternalPutRequest()
1139{
1140    // Is the current request *not* a put request.  If its not, then this must
1141    // be a reply to an internally generated put request sent to IrLMP.
1142    return GetCurrentEvent()->fPendEvent != kIrPutDataRequestEvent;
1143
1144} // TLSAPConn::InternalPutRequest
1145
1146
1147//--------------------------------------------------------------------------------
1148//      GetPendConnLstn
1149//--------------------------------------------------------------------------------
1150TIrEvent* TLSAPConn::GetPendConnLstn()
1151{
1152    // This is used by IrLAPConn so it can reply to pending conn/lstn reqs for each LSAP
1153    //XASSERT(fPendConnLstn != nil);     // jdg: sometimes it's already open and the pending conn/lstn is nil
1154    return fPendConnLstn;
1155
1156} // TLSAPConn::GetPendConnLstn
1157
1158
1159//--------------------------------------------------------------------------------
1160//      PassRequestToLMP
1161//--------------------------------------------------------------------------------
1162void TLSAPConn::PassRequestToLMP()
1163{
1164    // All requests forwarded to LMP need to identify themselves for the reply
1165    TIrLSAPConnEvent* theEvent = (TIrLSAPConnEvent*)GetCurrentEvent();
1166
1167    theEvent->fLSAPConn = this;
1168    GetLMP->EnqueueEvent(theEvent);
1169
1170} // TLSAPConn::PassRequestToLMP
1171
1172
1173//--------------------------------------------------------------------------------
1174//      DisconnectStart
1175//--------------------------------------------------------------------------------
1176void TLSAPConn::DisconnectStart(IrDAErr result, TIrDisconnectRequest* discRequest)
1177{
1178    // JDG: review review review.
1179    fPendConnLstn = nil;                        // jdg: TEMP TEMP TEMP TEMP
1180
1181    // Use current event block if no request block specified
1182    if (discRequest == nil) {
1183	discRequest = (TIrDisconnectRequest*)GetCurrentEvent();
1184    }
1185
1186    discRequest->fEvent = kIrDisconnectRequestEvent;
1187    discRequest->fResult = kIrDAErrCancel;
1188    discRequest->fLSAPConn = this;
1189
1190    // Save reason for disconnection for conn/lstn complete after disconnect reply
1191    fResult = result;
1192
1193    fState = kLSAPDisconnectPending;        // JDG: we're on the way out
1194
1195    GetLMP->EnqueueEvent(discRequest);
1196
1197} // TLSAPConn::DisconnectStart
1198
1199
1200//--------------------------------------------------------------------------------
1201//      GetControlFrame
1202//--------------------------------------------------------------------------------
1203void TLSAPConn::GetControlFrame()
1204{
1205    TIrGetRequest* getRequest = (TIrGetRequest*)GetCurrentEvent();
1206
1207    // Reset fConnLstnUserData (unhides all) to accept maximum conn user data
1208    if (fConnLstnUserData) {
1209	fConnLstnUserData->Reset();
1210    }
1211
1212    getRequest->fEvent = kIrGetDataRequestEvent;
1213    getRequest->fResult = noErr;
1214    getRequest->fData = fConnLstnUserData;
1215    getRequest->fOffset = 0;
1216    getRequest->fLength = fConnLstnUserData ? fConnLstnUserData->GetSize() : 0;
1217
1218    // Send get request to station control (LMP)
1219    PassRequestToLMP();
1220
1221} // TLSAPConn::GetControlFrame
1222
1223
1224//--------------------------------------------------------------------------------
1225//      PutControlFrame
1226//--------------------------------------------------------------------------------
1227void TLSAPConn::PutControlFrame(UByte opCode, UByte info)
1228{
1229    CBuffer* data = nil;    // Default if not connect or connect reply
1230    TIrPutRequest* putRequest = (TIrPutRequest*)GetCurrentEvent();
1231
1232    // Only send connect/accept userData if opCode is connect or connect reply.
1233    if ((opCode == kLMPDUConnectRequest) || (opCode == kLMPDUConnectReply)) {
1234	data = fConnLstnUserData;
1235    }
1236
1237    XASSERT(fPeerLSAPId <= kLastValidLSAPId);
1238
1239    putRequest->fEvent = kIrPutDataRequestEvent;
1240    putRequest->fResult = noErr;
1241    putRequest->fData = data;
1242    putRequest->fOffset = 0;
1243    putRequest->fLength = data ? data->GetSize() : 0;
1244    putRequest->fDstLSAPId = fPeerLSAPId;
1245    putRequest->fSrcLSAPId = fMyLSAPId;
1246    putRequest->fCtrlOpCode = opCode;
1247    putRequest->fCtrlInfo = info;
1248
1249    // Send put request to station control (IrLMP)
1250    PassRequestToLMP();
1251
1252} // TLSAPConn::PutControlFrame
1253
1254
1255//--------------------------------------------------------------------------------
1256//      GetDataFrame
1257//--------------------------------------------------------------------------------
1258void TLSAPConn::GetDataFrame(Boolean resend)
1259{
1260    TIrGetRequest* getRequest = (TIrGetRequest*)GetCurrentEvent();
1261
1262    if (resend) {
1263	// Reset the fields from the original requests data
1264	getRequest->fEvent = kIrGetDataRequestEvent;
1265	getRequest->fResult = noErr;
1266	getRequest->fData = fGetData;
1267	getRequest->fOffset = fGetOffset;
1268	getRequest->fLength = fGetLength;
1269    }
1270    else {
1271	// Save the info needed to recreate the request for resends
1272	fGetData = getRequest->fData;
1273	fGetOffset = getRequest->fOffset;
1274	fGetLength = getRequest->fLength;
1275    }
1276
1277    // Send get request to station control (LMP)
1278    PassRequestToLMP();
1279
1280} // TLSAPConn::GetDataFrame
1281
1282
1283//--------------------------------------------------------------------------------
1284//      PutDataFrame
1285//--------------------------------------------------------------------------------
1286void TLSAPConn::PutDataFrame()
1287{
1288    TIrPutRequest* putRequest = (TIrPutRequest*)GetCurrentEvent();
1289
1290    XASSERT(fPeerLSAPId <= kLastValidLSAPId);
1291
1292    putRequest->fDstLSAPId = fPeerLSAPId;
1293    putRequest->fSrcLSAPId = fMyLSAPId;
1294    putRequest->fCtrlOpCode = kLMPDUDataEvent;
1295    putRequest->fCtrlInfo = 0;
1296
1297    // Send put request to station control (IrLMP)
1298    PassRequestToLMP();
1299
1300} // TLSAPConn::PutDataFrame
1301
1302
1303//--------------------------------------------------------------------------------
1304//      ConnLstnComplete
1305//--------------------------------------------------------------------------------
1306void TLSAPConn::ConnLstnComplete(IrDAErr result)
1307{
1308    TIrConnLstnReply* reply = (TIrConnLstnReply*)GetCurrentEvent();
1309
1310#ifdef forDebug
1311    if ((reply->fPendEvent == kIrConnectRequestEvent) || (reply->fPendEvent == kIrListenRequestEvent)) {
1312	XASSERT(fPendConnLstn != nil);
1313    }
1314#endif
1315    fPendConnLstn = nil;
1316    if (reply->fPendEvent == kIrConnectRequestEvent)    // ONLY if connect response
1317	reply->fLSAPId = fLSAPId;                       // jdg: restore peer lsap id
1318	/// TODO review fLSAPID vs fPeerLSAPId
1319
1320    reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent);
1321    reply->fResult = result;
1322    reply->fDevAddr = fDevAddr;     // jdg: restore peer address
1323    //reply->fLSAPId = fLSAPId;     // jdg: restore peer lsap id
1324    fClient->EnqueueEvent(reply);
1325
1326} // TLSAPConn::ConnLstnComplete
1327
1328
1329//--------------------------------------------------------------------------------
1330//      YourData
1331//--------------------------------------------------------------------------------
1332Boolean TLSAPConn::YourData(TLMPDUHeader& header, Boolean justChecking)
1333{
1334    XTRACE( kMyData, header.fDstLSAPId, fMyLSAPId );
1335    if (header.fDstLSAPId == fMyLSAPId) {
1336	if (header.fSrcLSAPId == fPeerLSAPId) {
1337	    XTRACE( kDataForMe, header.fOpCode, header.fSrcLSAPId );
1338	    return true;
1339	}
1340	else if (fPeerLSAPId == kPendingConnectLSAPId) {
1341	    // Listen receives its connect request
1342	    // could be in listen or pending disconnect state ... jdg
1343	    XASSERT(fState == kLSAPConnListen || fState == kLSAPDisconnectPending);
1344	    //if (fState != kLSAPConnListen) {      // bogus,jdg:: could also be in disconnect pending or...
1345	    //  XTRACE(kLogRejectingMyData, 0, fState);
1346	    //  return false;                       // jdg: just drop it if we don't really want it
1347	    //}
1348	    XTRACE( kDataWaitingForMe, header.fOpCode,  header.fSrcLSAPId );
1349	    if (header.fOpCode == kLMPDUConnectRequest) {
1350		if (!justChecking) {
1351		    fPeerLSAPId = header.fSrcLSAPId;
1352		}
1353		return true;
1354	    }
1355	}
1356    }
1357
1358    return false;
1359
1360} // TLSAPConn::YourData
1361
1362
1363//--------------------------------------------------------------------------------
1364//      StartConnectTimer
1365//--------------------------------------------------------------------------------
1366void TLSAPConn::StartConnectTimer()
1367{
1368    fWatchdogTimerActive = true;
1369    fWatchdogTimerCount = 0;
1370    GetLMP->StartOneSecTicker();
1371
1372} // TLSAPConn::StartConnectTimer
1373
1374
1375//--------------------------------------------------------------------------------
1376//      StopConnectTimer
1377//--------------------------------------------------------------------------------
1378void TLSAPConn::StopConnectTimer()
1379{
1380    fWatchdogTimerActive = false;
1381    GetLMP->StopOneSecTicker();
1382
1383} // TLSAPConn::StopConnectTimer
1384
1385
1386//--------------------------------------------------------------------------------
1387//      OneSecTickerComplete
1388//--------------------------------------------------------------------------------
1389void TLSAPConn::OneSecTickerComplete()
1390{
1391    // Ignore the ticker complete if I'm not currently connecting
1392    if (!fWatchdogTimerActive) return;
1393
1394    // Shouldn't be active unless we're connecting
1395    XASSERT(fState == kLSAPConnConnect);
1396
1397    // Connect has timed out if reached the timeout count
1398    if (++fWatchdogTimerCount >= kWatchdogTimeoutCount) {
1399	NextState(kIrConnWatchdogExpiredEvent);
1400    }
1401
1402} // TLSAPConn::OneSecTickerComplete
1403
1404