1/*
2    File:       IrLAP.cpp
3
4    Contains:   Implementation of IrLAP
5
6
7*/
8
9#define IRDA_TEST_FRAME_SUPPORTED   1           // required I think
10
11
12#include "IrLAP.h"
13#include "IrLMP.h"
14#include "CList.h"
15#include "IrGlue.h"
16#include "CListIterator.h"
17#include "IrDscInfo.h"
18#include "IrQOS.h"
19#include "IrDiscovery.h"
20#include "IrLSAPConn.h"
21#include "CIrDevice.h"
22
23#define forMac 1    // TEMP TEMP TEMP -- clean up the code
24
25const UByte IrSlotCounts[4] = {1, 6, 8, 16};        // valid discovery slots
26
27
28#if (hasTracing > 0 && hasLAPTracing > 0)
29
30enum IrLAPTraceCodes
31{
32    kLogCreate = 1,
33    kLogFree,
34    kLogInit,
35    kLogInit2,
36
37    kUnexpectedEvent,
38    kLogStateEvent,
39
40    kNDMTimeoutEvent,
41    kNDMRecdInputEvent,
42    kNDMDiscoveryEvent,
43    kNDMConnectEvent,
44    kNDMListenEvent,
45    kNDMDisconnectEvent,
46
47    kQueryTimeoutEvent,
48    kQueryRecdInputEvent,
49    kQueryOutputDoneEvent,
50    kQueryDisconnectEvent,
51
52    kConnectBackoffTimeoutEvent,
53    kConnectFinalTimeoutEvent,
54    kConnectRecdInputEvent,
55    kConnectOutputDoneEvent,
56    kConnectDisconnectEvent,
57    kConnectChangeSpeed,            // jdg
58
59    kListenRecdInputEvent,
60    kListenOutputDoneEvent,
61    kListenDisconnectEvent,
62    kListenChangeSpeed,             // jdg
63    kOutputUACommandEvent,
64
65    kReplyTimeoutEvent,
66    kReplyRecdInputEvent,
67    kReplyOutputDoneEvent,
68    kReplyDisconnectEvent,
69    kReplyDiscoverRequestEvent,     // jdg
70    kReplyListenRequestEvent,       // jdg
71
72    kPriReceiveFinalTimeoutEvent,
73    kPriReceiveRecdInputEvent,
74    kPriReceiveOutputDoneEvent,
75    kPriReceivePutDataEvent,
76    kPriReceiveDisconnectEvent,
77    kPriReceiveClrLocBsyPendEvent,
78    kPriReceiveFRMREvent,
79
80    kPriTransmitEnterEvent,
81    kPriTransmitPollTimeoutEvent,
82    kPriTransmitOutputDoneEvent,
83    kPriTransmitPutDataEvent,
84    kPriTransmitDisconnectEvent,
85    kPriTransmitClrLocBsyPendEvent,
86
87    kPriCloseFinalTimeoutEvent,
88    kPriCloseRecdInputEvent,
89    kPriCloseOutputDoneEvent,
90    kPriCloseDisconnectRequest,
91
92    kSecReceiveWDTimeoutEvent,
93    kSecReceiveRecdInputEvent,
94    kSecReceiveOutputDoneEvent,
95    kSecReceivePutDataEvent,
96    kSecReceiveDisconnectEvent,
97    kSecReceiveClrLocBsyPendEvent,
98    kSecReceiveConnLstnRequest,         // jdg
99
100    kSecTransmitEnterEvent,
101    kSecTransmitOutputDoneEvent,
102    kSecTransmitPutDataEvent,
103    kSecTransmitDisconnectEvent,
104    kSecTransmitClrLocBsyPendEvent,
105    kSecTransmitConnLstnRequest,        // jdg
106
107    kSecCloseWDTimeoutEvent,
108    kSecCloseRecdInputEvent,
109    kSecCloseOutputDoneEvent,
110    kSecCloseDisconnectRequest,     // jdg
111
112    kDiscoveredDevice,
113    kDiscoverXIDCmdEvent,
114    kDiscoverXIDRspEvent,
115
116    kQOSSetBaudRateEvent,
117    kQOSBufferInfoEvent,
118    kQOSLeadInCountEvent,
119    kQOSMinTurnAroundEvent,
120    kQOSMaxTurnAroundEvent,
121
122    kSetLocalBusyPendingEvent,
123    kSetLocalBusyEvent,
124    kAbortLocalBusyPendingEvent,
125    kClrLocalBusyPendingEvent,
126    kClrLocalBusyEvent,
127
128    kNDMDisconnectFwdReply,
129    kNDMDisconnectReply,
130    kNRMDisconnectReply,
131    kNRMDisconnectAsyncReply,
132    kNRMDisconnectRequeue,
133
134    kTestFrameReceivedEvent,
135    kTestFrameOutputDoneEvent,
136
137    kValidPacketReceived,
138    kLogPacketDropped,
139    kPacketOutput,
140
141    kUnexpectedNr,              // jdg
142    kInvalidNr,
143    kUnexpectedNs,
144    kInvalidNs,
145    kIgnoringInvalidNrNs,
146    kOutputControlFrame,
147    kOutputControlFrameRR,
148    kOutputDataFrame,
149    kOutputDataFrameNotFinal,
150
151    kInputControlFrame,
152    kInputControlFrameRR,
153    kInputControlFrameNotFinal,
154    kInputDataFrame,
155    kInputDataFrameNotFinal,
156    kResendRejectedFrames,
157    kProcessISFrame,
158    kUpdateNrReceived,
159
160    kEnqueueEvent,              // cpd
161    kDequeueEventStart,
162    kDequeueEventEnd,
163
164    kReusingBuffer,
165    kUsingDefaultBuffer,
166    kLAPAddr,
167
168    kInputAborted,              // jdg performance hack
169    kConnLstnComplete,
170    kRejectRequest,             // jdg - send back a request,
171
172    kLogEnteringCloseState,
173
174    kLogStartTimer,
175    kLogStopTimer,
176    kLogTimerComplete,
177
178    kLogSuspend,
179    kLogResume,
180    kLogChangeSpeedCompleteIgnored,
181    kLogMyAddr,
182    kLogGotAddr,
183    kLogStartInput,
184    kLogStartInput2,
185    kLogStartInput3,
186
187    kLogGotData,
188    kLogFailedFirst,
189    kLogFailedSecond,
190    kLogFailedThird,
191
192    kLogReleaseInputBuffer,
193    kLogReleaseInputBuffer2,
194    kLogStartDataRcv1,
195    kLogStartDataRcv2,
196    kLogReset1,
197    kLogReset2,
198    kLogFreeGetBuffers1,
199    kLogFreeGetBuffers2,
200    kLogFreeGetBuffers3,
201    kLogFreeGetBuffers4
202};
203
204static
205EventTraceCauseDesc TraceEvents[] = {
206    {kLogCreate,                    "irlap: create obj="},
207    {kLogFree,                      "irlap: free obj="},
208    {kLogInit,                      "irlap: init, obj="},
209    {kLogInit2,                     "irlap: init, my dev addr="},
210
211    {kUnexpectedEvent,              "irlap: unexpected event"},
212    {kLogStateEvent,                "irlap: NextState, state=, event="},
213
214    {kNDMTimeoutEvent,              "irlap: NDM media busy timer"},
215    {kNDMRecdInputEvent,            "irlap: NDM recvd input"},
216    {kNDMDiscoveryEvent,            "irlap: NDM discovery"},
217    {kNDMConnectEvent,              "irlap: NDM connect"},
218    {kNDMListenEvent,               "irlap: NDM listen"},
219    {kNDMDisconnectEvent,           "irlap: NDM disconnect"},
220
221    {kQueryTimeoutEvent,            "irlap: Probe query timer"},
222    {kQueryRecdInputEvent,          "irlap: Probe query recvd input"},
223    {kQueryOutputDoneEvent,         "irlap: Probe query output done"},
224    {kQueryDisconnectEvent,         "irlap: Probe query disconnect"},
225
226    {kConnectBackoffTimeoutEvent,   "irlap: Connect backoff timer"},
227    {kConnectFinalTimeoutEvent,     "irlap: Connect F-timer"},
228    {kConnectRecdInputEvent,        "irlap: Connect recvd input"},
229    {kConnectOutputDoneEvent,       "irlap: Connect output done"},
230    {kConnectDisconnectEvent,       "irlap: Connect disconnect"},
231    {kConnectChangeSpeed,           "irlap: Connect changed speed"},
232
233    {kListenRecdInputEvent,         "irlap: Listen recvd input"},
234    {kListenOutputDoneEvent,        "irlap: Listen output done"},
235    {kListenDisconnectEvent,        "irlap: Listen disconnect"},
236    {kListenChangeSpeed,            "irlap: Listen changed spped"},
237    {kOutputUACommandEvent,         "irlap: OutputUAPacket"},
238
239    {kReplyTimeoutEvent,            "irlap: Probe reply timer"},
240    {kReplyRecdInputEvent,          "irlap: Probe reply recvd input"},
241    {kReplyOutputDoneEvent,         "irlap: Probe reply output done"},
242    {kReplyDisconnectEvent,         "irlap: Probe reply disconnect"},
243    {kReplyDiscoverRequestEvent,    "irlap: Probe reply, got discover request"},
244    {kReplyListenRequestEvent,      "irlap: Probe reply, got listen request"},
245
246    {kPriReceiveFinalTimeoutEvent,  "irlap: PRecv final timer"},
247    {kPriReceiveRecdInputEvent,     "irlap: PRecv recvd input, cmd, Ns|Nr"},
248    {kPriReceiveOutputDoneEvent,    "irlap: PRecv output done"},
249    {kPriReceivePutDataEvent,       "irlap: PRecv put data"},
250    {kPriReceiveDisconnectEvent,    "irlap: PRecv disconnect"},
251    {kPriReceiveClrLocBsyPendEvent, "irlap: PRecv clr local busy"},
252    {kPriReceiveFRMREvent,          "irlap: PRecv recvd FRMR"},
253
254    {kPriTransmitEnterEvent,        "irlap: PXmit enter"},
255    {kPriTransmitPollTimeoutEvent,  "irlap: PXmit poll timer"},
256    {kPriTransmitOutputDoneEvent,   "irlap: PXmit output done"},
257    {kPriTransmitPutDataEvent,      "irlap: PXmit put data"},
258    {kPriTransmitDisconnectEvent,   "irlap: PXmit disconnect"},
259    {kPriTransmitClrLocBsyPendEvent,"irlap: PXmit clr local busy"},
260
261    {kPriCloseFinalTimeoutEvent,    "irlap: PClose final timer"},
262    {kPriCloseRecdInputEvent,       "irlap: PClose recvd input"},
263    {kPriCloseOutputDoneEvent,      "irlap: PClose output done"},
264    {kPriCloseDisconnectRequest,    "irlap: PClose deferring disconnect request"},
265
266    {kSecReceiveWDTimeoutEvent,     "irlap: SRecv WD timer"},
267    {kSecReceiveRecdInputEvent,     "irlap: SRecv recvd input"},
268    {kSecReceiveOutputDoneEvent,    "irlap: SRecv output done"},
269    {kSecReceivePutDataEvent,       "irlap: SRecv put data"},
270    {kSecReceiveDisconnectEvent,    "irlap: SRecv disconnect"},
271    {kSecReceiveClrLocBsyPendEvent, "irlap: SRecv clr local busy"},
272    {kSecReceiveConnLstnRequest,    "irlap: SRecv conn/listen request"},
273
274    {kSecTransmitEnterEvent,        "irlap: SXmit enter"},
275    {kSecTransmitOutputDoneEvent,   "irlap: SXmit output done"},
276    {kSecTransmitPutDataEvent,      "irlap: SXmit put data"},
277    {kSecTransmitDisconnectEvent,   "irlap: SXmit disconnect"},
278    {kSecTransmitClrLocBsyPendEvent,"irlap: SXmit clr local busy"},
279    {kSecTransmitConnLstnRequest,   "irlap: SXmit conn/listen request"},
280
281    {kSecCloseWDTimeoutEvent,       "irlap: SClose WD timer"},
282    {kSecCloseRecdInputEvent,       "irlap: SClose recvd input"},
283    {kSecCloseOutputDoneEvent,      "irlap: SClose output done"},
284    {kSecCloseDisconnectRequest,    "irlap: SClose deferring disconnect request"},
285
286    {kDiscoveredDevice,             "irlap: discovered"},
287    {kDiscoverXIDCmdEvent,          "irlap: put XID command"},
288    {kDiscoverXIDRspEvent,          "irlap: put XID response"},
289
290    {kQOSSetBaudRateEvent,          "irlap: new baud rate"},
291    {kQOSBufferInfoEvent,           "irlap: buf cnt/size"},
292    {kQOSLeadInCountEvent,          "irlap: lead in count"},
293    {kQOSMinTurnAroundEvent,        "irlap: min turnaround"},
294    {kQOSMaxTurnAroundEvent,        "irlap: max turnaround"},
295
296    {kSetLocalBusyPendingEvent,     "irlap: set local busy pending"},
297    {kSetLocalBusyEvent,            "irlap: set local busy"},
298    {kAbortLocalBusyPendingEvent,   "irlap: set local busy pending aborted"},
299    {kClrLocalBusyPendingEvent,     "irlap: clr local busy pending"},
300    {kClrLocalBusyEvent,            "irlap: clr local busy"},
301
302    {kNDMDisconnectFwdReply,        "irlap: NDM disconnect forward reply"},
303    {kNDMDisconnectReply,           "irlap: NDM disconnect reply"},
304    {kNRMDisconnectReply,           "irlap: NRM disconnect reply"},
305    {kNRMDisconnectAsyncReply,      "irlap: NRM disconnect async reply"},
306    {kNRMDisconnectRequeue,         "irlap: NRM disconnect requeue event"},
307
308    {kTestFrameReceivedEvent,       "irlap: test frame received"},
309    {kTestFrameOutputDoneEvent,     "irlap: test frame response sent"},
310
311    {kValidPacketReceived,          "irlap: valid packet received"},
312    {kLogPacketDropped,             "irlap: packet dropped ** no read pending!"},
313    {kPacketOutput,                 "irlap: packet output"},
314
315
316    {kUnexpectedNr,                 "irlap: Unexpected NR"},        // jdg
317    {kInvalidNr,                    "irlap: Invalid NR"},
318    {kUnexpectedNs,                 "irlap: Unexpected NS"},
319    {kInvalidNs,                    "irlap: Invalid NS"},
320    {kIgnoringInvalidNrNs,          "irlap: IGNORING*** invalid NrNs"},
321    {kOutputControlFrame,           "irlap: output non-RR control frame, Cmd, Nr"},
322    {kOutputControlFrameRR,         "irlap: output RR control frame, 0, Nr"},
323    {kOutputDataFrame,              "irlap: output data frame (Ns, Nr)"},
324    {kOutputDataFrameNotFinal,      "irlap: output data frame, not final (Ns,Nr)"},
325
326    {kInputControlFrame,            "irlap: input NON-RR control frame, (CMD,Nr)"},
327    {kInputControlFrameRR,          "irlap: input RR control frame, (0, Nr)"},
328    {kInputControlFrameNotFinal,    "irlap: input control frame, NOT FINAL (cfield,Nr)"},
329    {kInputDataFrame,               "irlap: input data frame (Ns, Nr)"},
330    {kInputDataFrameNotFinal,       "irlap: input data frame, non-final (Ns, Nr)"},
331    {kResendRejectedFrames,         "irlap: inside resend rejected frames"},
332    {kProcessISFrame,               "irlap: process Info/Super frame"},
333    {kUpdateNrReceived,             "irlap: update Nr received"},
334
335    {kEnqueueEvent,                 "irlap: Event Queued"},
336    {kDequeueEventStart,            "irlap: Event Start"},
337    {kDequeueEventEnd,              "irlap: Event End"},
338
339    {kReusingBuffer,                "irlap: start data recv, reusing input buffer"},
340    {kUsingDefaultBuffer,           "irlap: start data recv, using DEFAULT input buffer"},
341
342    {kLAPAddr,                      "irlap: Peer Addr: My Addr:"},
343    {kInputAborted,                 "irlap: input abort - fast link turnaround after read err"},
344    {kConnLstnComplete,             "irlap: conn/lstn complete, peer dev addr="},
345    {kRejectRequest,                "irlap: rejecting request"},
346
347    {kLogEnteringCloseState,        "irlap: entering close state at #"},
348
349    {kLogStartTimer,                "irlap: start timer, (delay, event)"},
350    {kLogStopTimer,                 "irlap: stop timer"},
351    {kLogTimerComplete,             "irlap: timer complete, 0, event"},
352
353    {kLogSuspend,                   "irlap: sleep"},
354    {kLogResume,                    "irlap: wakeup"},
355    {kLogChangeSpeedCompleteIgnored,    "irlap: change speed complete ignored"},
356    {kLogMyAddr,                    "irlap: my addr"},
357    {kLogGotAddr,                   "irlap: rcvd addr"},
358    {kLogStartInput,                "irlap: start input, buf="},
359    {kLogStartInput2,               "irlap: start input, old buf="},
360    {kLogStartInput3,               "irlap: start input - keeping memory from leaking"},
361
362    {kLogGotData,                   "irlap: gotdata, wanted=, got="},
363    {kLogFailedFirst,               "irlap: ** failed ** 1st test"},
364    {kLogFailedSecond,              "irlap: ** failed ** second test"},
365    {kLogFailedThird,               "irlap: ** failed ** third test"},
366
367    {kLogReleaseInputBuffer,        "irlap: release input buffer, buffer="},
368    {kLogReleaseInputBuffer2,       "irlap: release input buffer, flags, index"},
369    {kLogStartDataRcv1,             "irlap: start data rcv alloc, buffer="},
370    {kLogStartDataRcv2,             "irlap: start data rcv alloc, flags, index"},
371    {kLogReset1,                    "irlap: reset, buffer alloc mask"},
372    {kLogReset2,                    "irlap: reset, states"},
373    {kLogFreeGetBuffers1,           "irlap: free get buffers, buffer="},
374    {kLogFreeGetBuffers2,           "irlap: free get buffers, flag, index"},
375    {kLogFreeGetBuffers3,           "irlap: free get buffers, mask="},
376    {kLogFreeGetBuffers4,           "irlap: free get buffers, found fInputBuffer"}
377
378};
379
380    #define XTRACE(x, y, z) IrDALogAdd ( x, y, (uintptr_t)z & 0xffff, TraceEvents, true )
381#else
382    #define XTRACE(x, y, z) ((void)0)
383#endif  // hasTracing && hasLAPTracing
384
385#define GetLMP          (fIrDA->GetLMP())
386#define GetDiscovery    (fIrDA->GetDiscovery())
387#define GetIrDevice     (fIrDA->GetIrDevice())
388
389void LAPTimerNotifier( UInt32 refCon, UInt32 sig );
390Boolean gLastWasFRMR = false;               // TESTING.  Try (once) to recover from rcvd FRMR (shouldn't happen)
391
392//============================ Initialization stuff ==============================
393
394#define super TIrStream
395    OSDefineMetaClassAndStructors(TIrLAP, TIrStream);
396
397//--------------------------------------------------------------------------------
398//      TIrLAP
399//--------------------------------------------------------------------------------
400/*static*/
401TIrLAP *
402TIrLAP::tIrLAP(TIrGlue *irda, TIrQOS *myQOS, TIrQOS* peerQOS)
403{
404    TIrLAP *obj = new TIrLAP;
405    XTRACE(kLogCreate, 0, obj);
406
407    if (obj && !obj->Init(irda, myQOS, peerQOS)) {
408	obj->release();
409	obj = nil;
410    }
411    return obj;
412}
413
414Boolean
415TIrLAP::Init(TIrGlue *irda, TIrQOS *myQOS, TIrQOS* peerQOS)
416{
417    XTRACE(kLogInit, 0, this);
418
419    fState = kIrLAPDisconnectedState;       // maybe should have an invalid state here
420    fConnAddr = 0;
421    fMyDevAddr = 0;
422    fDiscoverMaxSlots = 0;
423    fDiscoverSlot = 0;
424    fDiscoverFlags =0;
425    fDiscoverReplied = fDiscoverEnteredReplyState = false;
426    fConflictDevAddr = fReplacementDevAddr = fPeerDevAddr= 0;
427
428    fCurrentRequest = nil;
429    fPendingDisconnect = nil;
430    fPendingRequests = nil;
431
432    //fMyQOS = fPeerQOS = nil;
433    fMyQOS = myQOS;
434    fPeerQOS = peerQOS;
435
436    fVr = fVs = fNextToAck = fWindow = 0;
437    fConnected = fLocalBusy = fRemoteBusy = false;
438    fSetLocalBusyPending = fClrLocalBusyPending = fEnteringCloseState = fRespondingToDisconnect = false;
439
440    fWaitingForPollTimer = fHandlingTestFrame = false;
441    bzero(&fTestHeader, sizeof(fTestHeader));
442
443    fFRMRPending = false;
444    fFRMRRejCtrlField = fFRMRMyNrAndNs = fFRMRReasonFlags = 0;
445    fRetryCount = fDisconnectWarningLimit = fDisconnectLinkLimit = 0;
446    fInitialRetryTime = fDisconnectLinkLimitTime = fBusyCounter = 0;
447    fDataRetries = fProtocolErrs = 0;
448
449    fLocalBusyClearedEvent = nil;
450
451
452    fLeadInCount = fMyWindowSize = fPeerWindowSize  = 0;
453    fPollTimerTimeout = fFinalTimerTimeout = fWatchdogTimeout = fMinTurnAroundTimeout = 0;
454    fPrimary = fPutReqsPending  = false;
455    fNextCmdRspToSend = fLastCmdRsp = 0;
456
457
458    fRecdCtrl = fRecdCR = fRecdAddr  = 0;
459    fRecdPF = fRecdNr = fRecdNs = fRecdCmdRsp = 0;
460    fValidRecdNr = fValidRecdNs = fNrNsFlags  = 0;
461
462    fIOBufferItem = nil;
463
464    fInputInProgress = fOutputInProgress = fInBrokenBeam  = false;
465
466    fGetBufferAvail = fNumGetBuffers = 0;
467    bzero(fGetBuffers, sizeof(fGetBuffers));
468    fInputBuffer = nil;
469
470    bzero(fNickName, sizeof(fNickName));
471    fPendingPutRequests = nil;
472    fPutBuffer = nil;
473
474    bzero(fPutRequests, sizeof(fPutRequests));
475
476
477#if (hasTracing > 0 && hasLAPTracing > 0)
478	if (!super::Init(irda, TraceEvents, kEnqueueEvent)) return false;
479#else
480	if (!super::Init(irda)) return false;
481#endif
482
483    fLeadInCount = kIrDefaultLeadinCount;
484    //fNeedNewInputBuffer = true;
485
486    // Get a random device address for my address (range is 1 - FFFFFFFE)
487    fMyDevAddr = ( random() % 0xFFFFFFFE + 1 );
488
489    // Make it something different if it happens to be the sniff or probe addresses
490    if ((fMyDevAddr == kIrLAPSnifferDevAddr) || (fMyDevAddr == kIrLAPSniffeeDevAddr) || (fMyDevAddr == kIrLAPProbeDevAddr)) {
491	fMyDevAddr++;
492    }
493    XTRACE(kLogInit2, fMyDevAddr>>16, fMyDevAddr);
494    require(fMyDevAddr, Fail);          // should not be zero
495
496    fIOBufferItem = CBufferSegment::New(3000);  // Fix (size is ignored for now)
497    require(fIOBufferItem, Fail);
498
499    fPendingPutRequests = CList::cList();
500    require(fPendingPutRequests, Fail);
501
502    fPendingRequests = CList::cList();
503    require(fPendingRequests, Fail);
504
505    fLocalBusyClearedEvent = fIrDA->GrabEventBlock(kIrLocalBusyClearedEvent, sizeof(TIrEvent)); // review, needed?
506    require(fLocalBusyClearedEvent, Fail);
507
508    fPutBuffer = TIrLAPPutBuffer::tIrLAPPutBuffer();
509    require(fPutBuffer, Fail);
510
511    ResetStats();               // reset stats counters (needed?)
512
513    return true;
514
515Fail:
516
517    return false;
518
519} // TIrLAP::Init
520
521
522//--------------------------------------------------------------------------------
523//      free
524//--------------------------------------------------------------------------------
525void
526TIrLAP::free()
527{
528    XTRACE(kLogFree, 0, this);
529
530#define FREE(x) { if (x) { (x)->release(); x = nil; } }
531
532    // Free any buffer lists that have been allocated
533    FreeGetBuffers();
534
535    FREE(fPendingPutRequests);
536    FREE(fPendingRequests);
537    FREE(fIOBufferItem);
538    FREE(fPutBuffer);
539
540
541    if (fIrDA) {
542	//int Review_Event_Free;      // may be able to delete this
543	//if (fLocalBusyEvent) {
544	//  fIrDA->ReleaseEventBlock(fLocalBusyEvent);
545	//  fLocalBusyEvent = nil;
546	//}
547	if (fLocalBusyClearedEvent) {
548	    fIrDA->ReleaseEventBlock(fLocalBusyClearedEvent);
549	    fLocalBusyClearedEvent = nil;
550	}
551    }
552
553    super::free();
554
555} // TIrLAP::free
556
557
558
559//--------------------------------------------------------------------------------
560//      Reset
561//--------------------------------------------------------------------------------
562void TIrLAP::Reset()
563{
564    // called by our disconnect complete, and via the glue async disconnect
565    // and also by glue's stop code (so state can be other than disconnected)
566    XTRACE(kLogReset1, fGetBufferAvail >> 16, fGetBufferAvail);
567    XTRACE(kLogReset2, kIrLAPDisconnectedState, fState);
568    //check(fState == kIrLAPDisconnectedState);     // also kIrLAPPriCloseState and ??
569    fState = kIrLAPDisconnectedState;
570    FreeGetBuffers();
571
572} // TIrLAP::Reset
573
574// Sleep/wakeup support
575void
576TIrLAP::Suspend(void)
577{
578    XTRACE(kLogSuspend, 0, 0);
579    fRetryCount = fDisconnectLinkLimit;         // force disconnect on next timeout
580}
581
582void
583TIrLAP::Resume(void)
584{
585    XTRACE(kLogResume, 0, 0);
586}
587
588
589//--------------------------------------------------------------------------------
590//      GetNickName
591//--------------------------------------------------------------------------------
592void TIrLAP::GetNickName( UInt8 * nickName, int maxlen )
593{
594    if( fNickName[0] != 0 )
595	strlcpy( ( char * )nickName, ( const char * )fNickName, maxlen);
596    else
597	nickName[0] = 0;
598}
599
600
601//--------------------------------------------------------------------------------
602//      FreeGetBuffers
603//--------------------------------------------------------------------------------
604void TIrLAP::FreeGetBuffers()
605{
606    UInt32  flag, index;
607
608    XTRACE(kLogFreeGetBuffers3, fGetBufferAvail >> 16, fGetBufferAvail);
609
610    // Free the input buffers (allocated during connect with peer)
611    for (index = 0, flag=1; index < fNumGetBuffers; index++, flag <<= 1) {
612	XTRACE(kLogFreeGetBuffers1, 0, fGetBuffers[index]);
613	XTRACE(kLogFreeGetBuffers2, flag, index);
614
615	check(fGetBuffers[index]);
616	check((fGetBufferAvail & flag) ||                   // should be "available" OR
617		(fInputBuffer == fGetBuffers[index]));      // current fInputBuffer
618
619	if (fGetBuffers[index] && (fGetBufferAvail & flag)) {   // if ok to delete
620	    fGetBuffers[index]->Delete();                       // release the buffer
621	}
622	else {
623	    // if it's in use as fInputBuffer then it won't have it's avail flag set
624	    // but we can free it anyway since we own it (wasn't sent up the stack)
625	    if (fInputBuffer == fGetBuffers[index]) {
626		XTRACE(kLogFreeGetBuffers4, 0, fInputBuffer);
627		fInputBuffer = nil;
628		fGetBuffers[index]->Delete();               // release the buffer
629	    }
630	    else {      // memory leak, but let's not free it since it may be in use
631		DebugLog("memory leak! fInputBuffer=0x%lx\n", (uintptr_t)fInputBuffer);
632		DebugLog("buffer problem in free get buffers, index %ld, buffer 0x%lx\n",
633				(long int)index, (uintptr_t) fGetBuffers[index]);
634		//IrDALogTracingOff();
635	    }
636	}
637	fGetBuffers[index] =  nil;          // sanity
638    }
639    fNumGetBuffers = 0;         // no longer have any buffers available
640    fGetBufferAvail = 0;        // bitmask of available buffers is zero available now
641
642} // TIrLAP::FreeGetBuffers
643
644//
645// JDG: lapconn needs a way to abort a listen if a connect request comes in
646// while a listen is pending.  This will do it if we're still in NDM state
647// Could avoid this if we didn't use client event records for lapconn/lap interaction
648//
649TIrEvent *
650TIrLAP::CancelPendingListenRequest(void)        // return event if listen canceled
651{
652    TIrEvent *request = GetCurrentEvent();
653
654    StopInput();                                    // stop input, lapconn wants to stop the listen
655
656    if (fState == kIrLAPDisconnectedState && request && request->fEvent == kIrListenRequestEvent) {
657	//RejectRequest(request, kIRErrRetry);          // no, don't send it back
658	fCurrentRequest = nil;                          // no pending request now
659	return request;                                 // return 'ok'
660    }
661    return nil;
662}   // TIrLAP::CancelPendingListenRequest
663
664
665//--------------------------------------------------------------------------------
666//      NextState
667//--------------------------------------------------------------------------------
668void TIrLAP::NextState(ULong event)
669{
670    XTRACE(kLogStateEvent, fState, event);
671
672    switch (fState) {
673	case kIrLAPDisconnectedState:
674	    HandleDisconnectedStateEvent(event);
675	    break;
676
677	case kIrLAPQueryState:
678	    HandleQueryStateEvent(event);
679	    break;
680
681	case kIrLAPConnectState:
682	    HandleConnectStateEvent(event);
683	    break;
684
685	case kIrLAPListenState:
686	    HandleListenStateEvent(event);
687	    break;
688
689	case kIrLAPReplyState:
690	    HandleReplyStateEvent(event);
691	    break;
692
693	case kIrLAPPriReceiveState:
694	    HandlePriReceiveStateEvent(event);
695	    break;
696
697	case kIrLAPPriTransmitState:
698	    HandlePriTransmitStateEvent(event);
699	    break;
700
701	case kIrLAPPriCloseState:
702	    HandlePriCloseStateEvent(event);
703	    break;
704
705	case kIrLAPSecReceiveState:
706	    HandleSecReceiveStateEvent(event);
707	    break;
708
709	case kIrLAPSecTransmitState:
710	    HandleSecTransmitStateEvent(event);
711	    break;
712
713	case kIrLAPSecCloseState:
714	    HandleSecCloseStateEvent(event);
715	    break;
716
717	default:
718	    DebugLog("TIrLAP::NextState: bad fState");
719	    break;
720    }
721}
722
723
724//--------------------------------------------------------------------------------
725//      HandleDisconnectedStateEvent (fState == kIrLAPDisconnectedState) NDM
726//--------------------------------------------------------------------------------
727void TIrLAP::HandleDisconnectedStateEvent(ULong event)
728{
729#if forMac                          // Using a hammer for the problem, but if I am
730    fConnected = false;             // here, then I am disconnected.  Simple logic
731    fDiscoverActive = false;        // If I am discovering, then it will get set to
732    //gConnectionBroken = false;        // true before I exit.
733    fNickName[0] = 0;               // Clear out the connect name.
734
735#endif
736
737    switch (event) {
738	case kIrDiscoverRequestEvent:
739	    {
740		XTRACE(kNDMDiscoveryEvent, 0, 0);
741
742		fDiscoverActive = true;             // flag for status routines that we're discovering
743		// Save the request block - use it as the reply block later
744		//XASSERT(fCurrentRequest == nil);                  // jdg: maybe on the newton
745		if (fCurrentRequest != nil) {                       // JDG ADDED, can we do better?
746		    RejectRequest(fCurrentRequest, kIrDAErrRetry);  // dispose of previous request
747		}
748		fCurrentRequest = GetCurrentEvent();
749
750		// Start up the media busy timeout timer
751		GetIrDevice->ResetMediaBusy();
752		StartTimer(kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent);
753		fBusyCounter = 0;       // JDG: Try N times to discover
754    //          StartMediaBusyTimer( kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent );
755		// Wait for possible xid request from peer device
756		StartInput(fIOBufferItem);
757	    }
758	    break;
759
760	case kIrConnectRequestEvent:
761	    {
762		XTRACE(kNDMConnectEvent, 0, 0);
763
764		TIrConnLstnRequest* connectRequest = (TIrConnLstnRequest*)GetCurrentEvent();
765
766		// Save the request block - use it as the reply block later
767		//XASSERT(fCurrentRequest == nil);                  // jdg - maybe on a newton
768		if (fCurrentRequest != nil) {                       // JDG ADDED, can we do better?
769		    fDiscoverActive = false;                        // we're not discovering anymore
770		    StopTimer();                                    // stop media timer (if discovery req)
771		    RejectRequest(fCurrentRequest, kIrDAErrRetry);  // dispose of previous request
772		}
773		fCurrentRequest = GetCurrentEvent();
774
775		// Save myQOS parms and place to receive peerQOS parms
776		fMyQOS = connectRequest->fMyQOS;
777		fPeerQOS = connectRequest->fPeerQOS;
778
779		/*** TEMP DEBUGGING ***/
780		if (1) {
781		    // First my info
782		    XTRACE(kQOSBufferInfoEvent, fMyQOS->GetWindowSize(), fMyQOS->GetDataSize());
783		    XTRACE(kQOSLeadInCountEvent, 0, fMyQOS->GetExtraBOFs());
784		    XTRACE(kQOSMinTurnAroundEvent, 0, fMyQOS->GetMinTurnAroundTime());
785		    XTRACE(kQOSMaxTurnAroundEvent, 0, fMyQOS->GetMaxTurnAroundTime());
786
787		    // Then the peer device's info
788		    XTRACE(kQOSBufferInfoEvent, fPeerQOS->GetWindowSize(), fPeerQOS->GetDataSize());
789		    XTRACE(kQOSLeadInCountEvent, 1, fPeerQOS->GetExtraBOFs());
790		    XTRACE(kQOSMinTurnAroundEvent, 1, fPeerQOS->GetMinTurnAroundTime());
791		    XTRACE(kQOSMaxTurnAroundEvent, 1, fPeerQOS->GetMaxTurnAroundTime());
792		}
793		/**** TEMP DEBUGGING ****/
794
795		// Address of device to connect to
796		fPeerDevAddr = connectRequest->fDevAddr;
797
798		// Get a random connection address for the conn address to be used while in NRM mode
799		// The IrLAP spec reserves values 0 and 7F, but some errata have also implied
800		// that 1 and 7E are also invalid, so I'm leaving them out too to be safe.
801		fConnAddr = (UByte)random() % 0x7C + 2; // 0-7B plus 2 => 2-7D
802
803		// For efficiency, avoid conn addrs of 0x60 (which become 0xC0/0xC1 in A field)
804		// and 0x3E (which become 0x7D in A field).  Otherwise the A field would always
805		// have to be escaped.  This avoids it up front, since we have control in this case.
806		// NOTE: This is a SIR only issue, but doesn't hurt if also done for FIR.
807		if ((fConnAddr == 0x60) || (fConnAddr == 0x3E)) {
808		    // Now 0x60 => 0x61 (0xC2/0xC3) and 0x3E => 0x3F (0x7E); and no escaping needed.
809		    fConnAddr++;
810		}
811
812		XTRACE( kLAPAddr, fPeerDevAddr, fConnAddr );
813		check(fConnAddr);
814		GetIrDevice->SetLAPAddress( fConnAddr );
815
816		// Init some state
817		fRetryCount = 0;
818		fInitialRetryTime = 0;
819
820		// Change state to connect(ing)
821		fState = kIrLAPConnectState;
822
823		// Begin by sending the SNRM command
824		OutputSNRMCommand();
825	    }
826	    break;
827
828	case kIrListenRequestEvent:
829	    {
830		XTRACE(kNDMListenEvent, 0, 0);
831
832		TIrConnLstnRequest* listenRequest = (TIrConnLstnRequest*)GetCurrentEvent();
833
834		// Save the request block - use it as the reply block later
835		//XASSERT(fCurrentRequest == nil);                  // jdg: maybe on a newton
836		// Listen requests defer to pending discover, reject this one if we're not idle
837		if (fCurrentRequest != nil) {                       // Can we do better?
838		    //StopTimer();                                  // don't stop media timer
839		    //RejectRequest(fCurrentRequest, kIrDAErrCancel);   // dispose of previous request
840		    RejectRequest(GetCurrentEvent(), kIrDAErrRetry);    // reject the new LISTEN (discover in progress)
841		    return;                                         // and return!
842		}
843		fCurrentRequest = GetCurrentEvent();
844
845		// Save myQOS parms and place to receive peerQOS parms
846		fMyQOS = listenRequest->fMyQOS;
847		fPeerQOS = listenRequest->fPeerQOS;
848
849		///////////////////////////////////////////////////////////////////////
850		// TESTING ABORT ASYNC I/O HACK
851		///fDiscoverActive = false;     // we are not discovering, thank you
852		///StartTimer(5*1000, kIrMediaBusyTimerExpiredEvent);       // 5 seconds
853		///////////////////////////////////////////////////////////////////////
854		// Begin by waiting for initial XID command
855		// (to be followed by (optional addr resolutions) then a snrm)
856		StartInput(fIOBufferItem);
857	    }
858	    break;
859
860	case kIrInputCompleteEvent:
861	    {
862		XTRACE(kNDMRecdInputEvent, fRecdCmdRsp, fRecdAddr);
863
864		// Stop the media busy timer (if we are discovering)
865		StopTimer();
866
867		// Check for xid (peer device is discovering)
868		if (RecdPollCmd(kIrLAPCmdXID)) {
869		    fDiscoverEnteredReplyState = true;
870		    HandleReplyStateEvent(kIrInputCompleteEvent);
871		    // Note: input was reposted in HandleReplyStateEvent (if didn't change state)
872		}
873		// Check for snrm (peer device is connecting)
874		else if (RecdPollCmd(kIrLAPCmdSNRM)) {
875		    HandleListenStateEvent(kIrInputCompleteEvent);
876		    // Note: input was reposted by HandleListenStateEvent (if didn't change state)
877		}
878		// It was something else.  Ignore it, but repost the input
879		else {
880		    StartInput(fIOBufferItem);
881		}
882
883		// If we are still in the disconnected state (because the XID wasn't
884		// for us or the snrm wasn't for us) then restart/continue the requests
885		if (fState == kIrLAPDisconnectedState) {
886		    //XASSERT(fCurrentRequest != nil);
887		    // Note: If listen almost completed but failed with an out of memory
888		    // error then fCurrentRequest could legitimately be nil at this point.
889		    if (fCurrentRequest && fCurrentRequest->fEvent == kIrDiscoverRequestEvent) {
890			// Start up the media busy timeout timer
891			GetIrDevice->ResetMediaBusy();
892			StartTimer(kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent);
893    //                  StartMediaBusyTimer( kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent );
894		    }
895		}
896	    }
897	    break;
898
899	case kIrMediaBusyTimerExpiredEvent:
900	    {
901    //          DebugLog("LAP NDM kIrMediaBusyTimerExpiredEvent" );
902		XTRACE(kNDMTimeoutEvent, 0, 0);
903		//XASSERT((fCurrentRequest != nil) && (fCurrentRequest->fEvent == kIrDiscoverRequestEvent));
904
905
906		TIrDiscoverRequest* discoverRequest = (TIrDiscoverRequest*)fCurrentRequest;
907		fDiscoverActive = true;             // this should already be set!
908
909		// Check mediaBusy flag to really make sure that there was no "traffic"
910		if (GetIrDevice->GetMediaBusy()) {
911		    // Media is busy, wait some more before trying again
912		    // NOTE: This implementation currently tries forever.  If that is not the correct
913		    // model then need to use a retry count here and return error when retry is reached.
914		    /*** JDG: Let's stop the discover after one try. ... nope, now N tries ****/
915		    if (fBusyCounter++ < kMaxDiscoverRetries) {     // if ok to try again
916			//StopInput();                              // jdg: at least reset the busy flag!
917			//StartInput(fIOBufferItem);                    // jdg: by stopping & restarting read
918			GetIrDevice->ResetMediaBusy();              // reset busy flag directly now
919			StartTimer(kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent);
920			// StartMediaBusyTimer( kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent );
921		    } else {                                        // give up and reject the discover request
922			fDiscoverActive = false;                            // jdg: don't try again
923			discoverRequest->fPassiveDiscovery = false;         // probably not needed, but ...
924			RejectRequest(fCurrentRequest, kIrDAErrLinkBusy);       // return the request
925			fCurrentRequest = nil;
926		    }
927		}
928
929		// No other traffic - okay to begin a discover dialog
930		else {
931		    StopInput();
932
933		    // Default to 1 slot if invalid numSlots is passed in
934		    fDiscoverFlags = kIrLAPDiscoverFlags1Slot;
935		    fDiscoverMaxSlots = 0;  // Initially 1 - 1
936
937		    // Assign appropriate slot bit field
938		    UByte index;
939		    for (index = 0; index < sizeof(IrSlotCounts); index++) {
940			if (IrSlotCounts[index] == discoverRequest->fNumSlots) {
941			    fDiscoverFlags = index;
942			    fDiscoverMaxSlots = (UByte)discoverRequest->fNumSlots - 1;
943			    break;
944			}
945		    }
946
947		    // Set fConflictDevAddr (which may be kIrLAPBroadcastDevAddr) if discover vs addr conflict
948		    fConflictDevAddr = discoverRequest->fConflictDevAddr;
949		    if (fConflictDevAddr != kIrLAPBroadcastDevAddr) {
950			fDiscoverFlags |= kIrLAPDiscoverFlagsNewAddr;
951		    }
952
953		    // Start from the beginning
954		    fDiscoverSlot = 0;
955
956		    // Change state to discover(ing)
957		    fState = kIrLAPQueryState;
958
959		    // Begin by sending the initial XID command
960		    OutputXIDCommand();
961		}
962	    }
963	    break;
964
965	case kIrCancelPutRequestEvent:
966	    CancelPutRequest();
967	    break;
968
969	case kIrDisconnectRequestEvent:
970	    XTRACE(kNDMDisconnectEvent, 0, 0);
971	    HandleNDMDisconnectRequest();
972	    break;
973
974	case kIrPutDataRequestEvent:
975	    NotConnectedCompletion();                                   // jdg: yes!  send back to CIrLSAP
976	    //RejectRequest(GetCurrentEvent(), kCommErrNotConnected);   // jdg: send to lmp, not directly to lsapconn
977	    break;
978
979	case kIrLocalBusyClearedEvent:
980	    // Don't need to do anything here.
981	    // This is a side effect of releasing buffers at disconnect cleanup (see IrLAPConn).
982	    break;
983
984	case kIrOutputCompleteEvent:        // jdg added.  this can be safely ignored, we're on the way
985	    break;                          //   out ... I hope!
986
987	default:
988	    XTRACE(kUnexpectedEvent, fState, event);
989	    DebugLog("TIrLAP::HandleDisconnectedStateEvent: bad event");
990	    break;
991    }
992
993}   // TIrLAP::HandleDisconnectedStateEvent
994
995
996//--------------------------------------------------------------------------------
997//      HandleQueryStateEvent (fState == kIrLAPQueryState)
998//--------------------------------------------------------------------------------
999void TIrLAP::HandleQueryStateEvent(ULong event)
1000{
1001    fDiscoverActive = true;             // Always update date the globals.
1002
1003    switch (event) {
1004	case kIrInputCompleteEvent:
1005	    XTRACE(kQueryRecdInputEvent, fRecdCmdRsp, fRecdAddr);
1006	    // Only accept broadcast XID responses
1007	    if ((fRecdAddr == kIrLAPBroadcastAddr) && RecdFinalRsp(kIrLAPRspXID)) {
1008		TXIDPacket  xidRsp;
1009
1010		// Parse the received info
1011		if (GotData(&xidRsp.fFormatId, kTXIDPacketSize - 2)) {
1012		    // Only log it if dest address is mine
1013		    if (xidRsp.fDstDevAddr == fMyDevAddr) {
1014			XTRACE(kDiscoveredDevice, 0, (xidRsp.fSrcDevAddr >> 16));
1015			XTRACE(kDiscoveredDevice, 1, (xidRsp.fSrcDevAddr));
1016			// Log the discovered info (rev/addr/info)
1017			TIrDscInfo* discoveryInfo = TIrDscInfo::tIrDscInfo();
1018			if (discoveryInfo != nil) {
1019			    TIrDiscoverReply* discoverReply = (TIrDiscoverReply*)fCurrentRequest;
1020			    XASSERT(discoverReply != nil);
1021
1022			    // Fill in, extract info for discover info
1023			    discoveryInfo->SetVersion(xidRsp.fVersion);
1024			    discoveryInfo->SetDeviceAddr(xidRsp.fSrcDevAddr);
1025			    discoveryInfo->ExtractDevInfoFromBuffer(fInputBuffer);
1026
1027			    // Add it to the list of discovered devices
1028			    discoverReply->fDiscoveredDevices->InsertLast(discoveryInfo);
1029			}
1030		    }
1031		    else {
1032			XTRACE(kLogMyAddr, fMyDevAddr >> 16, fMyDevAddr);
1033			XTRACE(kLogGotAddr, xidRsp.fDstDevAddr >> 16, xidRsp.fDstDevAddr);
1034			XTRACE(kLogFailedThird, 0, 0);
1035			DebugLog(" failed 3rd");
1036		    }
1037		}
1038		else {
1039		    DebugLog(" failed 2nd");
1040		    XTRACE(kLogFailedSecond, 0, 0);
1041		}
1042	    }
1043	    else {
1044		XTRACE(kLogFailedFirst, 0, 0);
1045		DebugLog(" failed 1st");
1046	    }
1047
1048	    // Wait for input
1049	    StartInput(fIOBufferItem);
1050	    break;
1051
1052	case kIrOutputCompleteEvent:
1053	    XTRACE(kQueryOutputDoneEvent, fDiscoverSlot, fDiscoverMaxSlots);
1054	    XASSERT(fNextCmdRspToSend == kIrLAPCmdXID);
1055	    if (fDiscoverSlot != kIrLAPFinalSlot) {
1056		// Start the slot timer and wait for a reply
1057		StartTimer(kIrDiscoverSlotTimeout, kIrSlotTimerExpiredEvent);
1058//#if forMac
1059		StartInput(fIOBufferItem);          // issue read only if we're maybe expecting something
1060//#endif
1061	    }
1062	    else {
1063		// Let the initiator know that the discovery phase has completed
1064		TIrDiscoverReply* discoverReply = (TIrDiscoverReply*)fCurrentRequest;
1065		fCurrentRequest = nil;
1066		discoverReply->fEvent = kIrDiscoverReplyEvent;
1067		discoverReply->fPassiveDiscovery = false;
1068#if forMac
1069		fDiscoverActive = false;                // Update the globals.
1070		///////////////////////////////////////////////////////////////////////
1071		// TESTING ABORT ASYNC I/O HACK
1072		// no we're hanging a read here before going back to disconnect state
1073		//StartTimer(5*1000, kIrMediaBusyTimerExpiredEvent);        // 5 seconds
1074		///////////////////////////////////////////////////////////////////////
1075#endif
1076		// Discovery process complete
1077		fState = kIrLAPDisconnectedState;
1078		GetLMP->EnqueueEvent(discoverReply);
1079	    }
1080//#if forMac
1081//          StartInput(fIOBufferItem);      // don't do a read after the last XID, no reply coming
1082//#endif
1083	    break;
1084
1085	case kIrSlotTimerExpiredEvent:
1086	    XTRACE(kQueryTimeoutEvent, fDiscoverSlot, fDiscoverMaxSlots);
1087	    StopInput();
1088	    if (fDiscoverSlot < fDiscoverMaxSlots) {
1089		// Send out XID for next slot
1090		fDiscoverSlot++;
1091	    }
1092	    else {
1093		// Send out final XID
1094		fDiscoverSlot = kIrLAPFinalSlot;
1095	    }
1096	    OutputXIDCommand();
1097	    break;
1098
1099	case kIrDisconnectRequestEvent:
1100	    XTRACE(kQueryDisconnectEvent, 0, 0);
1101	    XASSERT(fCurrentRequest != nil);
1102#if forMac
1103	    fDiscoverActive = false;                // Update the globals.
1104#endif
1105	    HandleNDMDisconnectRequest();
1106	    break;
1107
1108	case kIrDiscoverRequestEvent:
1109	case kIrListenRequestEvent:
1110	case kIrConnectRequestEvent:
1111	    XTRACE(kUnexpectedEvent, fState, event);
1112	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
1113	    break;
1114
1115	default:
1116	    XTRACE(kUnexpectedEvent, fState, event);
1117	    DebugLog("TIrLAP::HandleQueryStateEvent: bad event");
1118	    break;
1119    }
1120
1121} // TIrLAP::HandleQueryStateEvent
1122
1123
1124//--------------------------------------------------------------------------------
1125//      HandleConnectStateEvent (fState == kIrLAPConnectState)
1126//--------------------------------------------------------------------------------
1127void TIrLAP::HandleConnectStateEvent(ULong event)
1128{
1129    switch (event) {
1130	case kIrChangeSpeedCompleteEvent:
1131	    XTRACE(kConnectChangeSpeed, 0, 0);  // log it
1132	    OutputControlFrame(kIrLAPFrameRR);  // Note: OutputControlFrame sets poll bit
1133	    break;
1134
1135	case kIrInputCompleteEvent:
1136	    {
1137		XTRACE(kConnectRecdInputEvent, fRecdCmdRsp, 0);
1138		Boolean repostInput = true;
1139
1140		if (RecdFinalRsp(kIrLAPRspUA)) {
1141		    TUAPacket uaRsp;
1142
1143		    // Parse the received ua response
1144		    if (GotData((UByte*)&uaRsp.fSrcDevAddr, kTUAPacketSize - 2)) {
1145			if ((uaRsp.fSrcDevAddr == fPeerDevAddr) && (uaRsp.fDstDevAddr == fMyDevAddr)) {
1146			    IrDAErr result;
1147
1148			    StopTimer();
1149			    // Parse, negotiate and init conn state (and apply time consuming QOS parms)
1150			    result = ParseNegotiateAndInitConnState(true /*primary*/);
1151			    // NOTE: If error, ConnLstnComplete has already been called and gone to NDM
1152			    if (result != noErr) break;
1153
1154			    // Change baud rate to the negotiated speed
1155			    GetIrDevice->ChangeSpeed(fMyQOS->GetBaudRate());
1156
1157			    // Note that leadInCount is not changed yet on purpose
1158			    // so there is a minimum turnaround before sending the RR
1159			    // MOVED next line to after change speed completes
1160			    //OutputControlFrame(kIrLAPFrameRR);    // Note: OutputControlFrame sets poll bit
1161			    repostInput = false;
1162    #if forMac                                                  // Report I are connected, though not
1163			    fConnected = true;                  // really until I receive an RR from
1164								// the other size.
1165			    GetDiscovery->GetRemoteDeviceName( fPeerDevAddr, fNickName, sizeof(fNickName));
1166    #endif
1167			}
1168		    }
1169		}
1170		else if (RecdPollCmd(kIrLAPCmdSNRM)) {
1171		    TSNRMPacket snrmCmd;
1172
1173		    // Parse the received snrm command
1174		    if (GotData((UByte*)&snrmCmd.fSrcDevAddr, kTSNRMPacketSize - 2)) {
1175			// NOTE: Only agree to be secondary if myDevAddr < peerDevAddr
1176			if ((snrmCmd.fDstDevAddr == fMyDevAddr) && (fMyDevAddr < snrmCmd.fSrcDevAddr)) {
1177			    IrDAErr result;
1178			    UByte connAddr = snrmCmd.fConnAddr >> 1;
1179
1180			    // Don't accept any wooden nickels (whatever that means)
1181			    if ((connAddr > 0) && (connAddr < kIrLAPBroadcastAddr)) {
1182				// Recd snrm while connecting and myDevAddr < peerDevAddr - so enter listen state
1183				fState = kIrLAPListenState;
1184
1185				// Save relevent info
1186				fConnAddr = connAddr;
1187				fPeerDevAddr = snrmCmd.fSrcDevAddr;
1188
1189				StopTimer();
1190
1191				//check(fPeerDevAddr);
1192				//fIrSIR->SetLAPAddress( fPeerDevAddr );
1193				check(connAddr);                    // JDG: let's use the right
1194				GetIrDevice->SetLAPAddress(connAddr);   // field, shall we?
1195
1196				// Parse, init conn state and apply time consuming QOS parms
1197				result = ParseNegotiateAndInitConnState(false /*primary*/);
1198				// NOTE: If error, ConnLstnComplete has already been called and gone to NDM
1199				if (result != noErr) break;
1200
1201				OutputUAResponse();
1202				repostInput = false;
1203			    }
1204			}
1205		    }
1206		}
1207		else if (RecdCmd(kIrLAPCmdDISC) || RecdRsp(kIrLAPRspDM)) {
1208		    // Let the initiator know that the connect failed - (was stopped by peer)
1209		    ConnLstnComplete(kIrDAErrCancel);
1210		    repostInput = false;
1211		}
1212		// Resume input if nothing recognizable was received
1213		if (repostInput) {
1214		    StartInput(fIOBufferItem);
1215		}
1216	    }
1217	    break;
1218
1219	case kIrOutputCompleteEvent:
1220	    XTRACE(kConnectOutputDoneEvent, fNextCmdRspToSend, fConnAddr);
1221	    switch (fNextCmdRspToSend) {
1222		case kIrLAPCmdSNRM:
1223		    fRetryCount++;
1224		    StartTimer(kIrConnectFinalTimerTimeout, kIrFinalTimerExpiredEvent);
1225		    StartInput(fIOBufferItem);
1226		    break;
1227
1228		case kIrLAPFrameRR:
1229		    // Start receiving at earliest possible point
1230		    //StartDataReceive();           // jdg: can't do this since read can call me back w/data
1231
1232		    // Set additional number of BOFs required
1233		    // NOTE: Done after sending RR so there is a min turnaround delay (w/BOFs)
1234		    fLeadInCount = (UByte)fPeerQOS->GetExtraBOFs();
1235
1236		    // Let the initiator know that the connect succeeded
1237		    ConnLstnComplete(noErr);
1238
1239		    StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
1240
1241		    fState = kIrLAPPriReceiveState;
1242		    StartDataReceive();         // now that state's changed, can do a read
1243		    break;
1244
1245		default:
1246		    DebugLog("TIrLAP::HandleConnectStateEvent: bad output state");
1247		    break;
1248	    }
1249	    break;
1250
1251	case kIrFinalTimerExpiredEvent:
1252	    XTRACE(kConnectFinalTimeoutEvent, 0, 0);
1253	    if (fRetryCount < kMaxConnectRetries) {
1254		// Delay random time before resending SNRM
1255		// Random delay x should be between .5 and 1.5 time to send SNRM request
1256		// Time to send SNRM is appx 50 mSecs, range of x is 25 <= x <= 75 mSecs
1257		StartTimer((25 + (random() % 50)) * kMilliseconds, kIrBackoffTimerExpiredEvent);
1258	    }
1259	    else {
1260		StopInput();
1261
1262		// Let the initiator know that the connect failed - no responder
1263		ConnLstnComplete(kIrDAErrTimeout);
1264	    }
1265	    break;
1266
1267	case kIrBackoffTimerExpiredEvent:
1268	    XTRACE(kConnectBackoffTimeoutEvent, 0, 0);
1269	    StopInput();
1270	    OutputSNRMCommand();
1271	    break;
1272
1273	case kIrDisconnectRequestEvent:
1274	    XTRACE(kConnectDisconnectEvent, 0, 0);
1275	    XASSERT(fCurrentRequest != nil);
1276	    HandleNDMDisconnectRequest();
1277	    break;
1278
1279	case kIrDiscoverRequestEvent:
1280	case kIrListenRequestEvent:
1281	case kIrConnectRequestEvent:
1282	    XTRACE(kUnexpectedEvent, fState, event);
1283	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
1284	    break;
1285
1286	default:
1287	    XTRACE(kUnexpectedEvent, fState, event);
1288	    DebugLog("TIrLAP::HandleConnectStateEvent: bad event");
1289	    break;
1290    }
1291
1292} // TIrLAP::HandleConnectStateEvent
1293
1294
1295//--------------------------------------------------------------------------------
1296//      HandleListenStateEvent (fState == kIrLAPListenState)
1297//--------------------------------------------------------------------------------
1298void TIrLAP::HandleListenStateEvent(ULong event)
1299{
1300    switch (event) {
1301	case kIrInputCompleteEvent:
1302	    {
1303		XTRACE(kListenRecdInputEvent, fRecdCmdRsp, 0);
1304		Boolean repostInput = true;
1305
1306		if (RecdPollCmd(kIrLAPCmdSNRM)) {
1307		    TSNRMPacket snrmCmd;
1308
1309		    // Parse the received snrm command
1310		    if (GotData((UByte*)&snrmCmd.fSrcDevAddr, kTSNRMPacketSize - 2)) {
1311			if (snrmCmd.fDstDevAddr == fMyDevAddr) {
1312			    IrDAErr result;
1313			    UByte connAddr = snrmCmd.fConnAddr >> 1;
1314
1315			    // Don't accept any wooden nickels (whatever that means)
1316			    if ((connAddr > 0) && (connAddr < kIrLAPBroadcastAddr)) {
1317				// Recd valid snrm for me - so enter listen state
1318				fState = kIrLAPListenState;
1319
1320				// Save relevent info
1321				fConnAddr = connAddr;
1322				fPeerDevAddr = snrmCmd.fSrcDevAddr;
1323
1324				//check(fPeerDevAddr);
1325				//fIrSIR->SetLAPAddress( fPeerDevAddr );
1326				check(connAddr);                    // JDG: let's use the right
1327				GetIrDevice->SetLAPAddress(connAddr);   // field, shall we?
1328
1329				// Parse, init conn state and apply time consuming QOS parms
1330				result = ParseNegotiateAndInitConnState(false /*primary*/);
1331				// NOTE: If error, ConnLstnComplete has already been called and gone to NDM
1332				if (result != noErr) break;
1333
1334				OutputUAResponse();
1335				repostInput = false;
1336			    }
1337			}
1338		    }
1339		}
1340		// Resume input if nothing recognizable was received
1341		if (repostInput) {
1342		    StartInput(fIOBufferItem);
1343		}
1344	    }
1345	    break;
1346
1347	case kIrOutputCompleteEvent:
1348	    XTRACE(kListenOutputDoneEvent, fNextCmdRspToSend, 0);
1349	    XASSERT(fNextCmdRspToSend == kIrLAPRspUA);
1350
1351	    // Change baud rate to the negotiated speed
1352	    GetIrDevice->ChangeSpeed(fMyQOS->GetBaudRate());
1353
1354	    // "falls through" after ChangeSpeed completes .. jdg 6/26/2000
1355	    break;
1356
1357	case kIrChangeSpeedCompleteEvent:
1358	    XTRACE(kListenChangeSpeed, 0, 0);
1359
1360	    // Start receiving at earliest possible point
1361	    //StartDataReceive();           // jdg: moved below
1362
1363	    // Set additional number of BOFs required
1364	    fLeadInCount = (UByte)fPeerQOS->GetExtraBOFs();
1365
1366	    // Let the initiator know that the listen has completed
1367	    ConnLstnComplete(noErr);
1368
1369	    // ***FIXME: Is this the right amount of time. Errata had some mention of this
1370	    StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
1371	    fState = kIrLAPSecReceiveState;
1372	    StartDataReceive();         // jdg: wait until new state before issuing read
1373	    break;
1374
1375	case kIrDisconnectRequestEvent:
1376	    XTRACE(kListenDisconnectEvent, 0, 0);
1377	    XASSERT(fCurrentRequest != nil);
1378	    HandleNDMDisconnectRequest();
1379	    break;
1380
1381	case kIrDiscoverRequestEvent:
1382	case kIrListenRequestEvent:             // REVIEW THIS ONE.  Unsolicited connect, listen?
1383	case kIrConnectRequestEvent:
1384	    XTRACE(kUnexpectedEvent, fState, event);
1385	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
1386	    break;
1387
1388	default:
1389	    XTRACE(kUnexpectedEvent, fState, event);
1390	    DebugLog("TIrLAP::HandleListenStateEvent: bad event");
1391	    break;
1392    }
1393
1394} // TIrLAP::HandleListenStateEvent
1395
1396
1397//--------------------------------------------------------------------------------
1398//      HandleReplyStateEvent (fState == kIrLAPReplyState)
1399//--------------------------------------------------------------------------------
1400void TIrLAP::HandleReplyStateEvent(ULong event)
1401{
1402    switch (event) {
1403	case kIrInputCompleteEvent:
1404	    {
1405		XTRACE(kReplyRecdInputEvent, fRecdCmdRsp, 0);
1406		Boolean repostInput = true;
1407
1408		if (RecdPollCmd(kIrLAPCmdXID)) {
1409		    TXIDPacket  xidCmd;
1410
1411		    // Parse the received XID command
1412		    if (GotData(&xidCmd.fFormatId, kTXIDPacketSize - 2)) {
1413			if (((xidCmd.fFormatId == kIrLAPDiscoveryXIDFormat)) &&
1414			    ((xidCmd.fSrcDevAddr != 0) && (xidCmd.fSrcDevAddr != kIrLAPBroadcastDevAddr)) &&
1415			    ((xidCmd.fDstDevAddr == kIrLAPBroadcastDevAddr) || ((xidCmd.fDstDevAddr == fMyDevAddr) && (xidCmd.fFlags & kIrLAPDiscoverFlagsNewAddr)))) {
1416			    if (xidCmd.fSlotNum != kIrLAPFinalSlot) {
1417				// Init some state first time through
1418				if (fDiscoverEnteredReplyState) {
1419				    // Recd bcast xid or xid for me and not just the final - so enter reply state
1420				    fState = kIrLAPReplyState;
1421
1422				    fDiscoverMaxSlots = IrSlotCounts[xidCmd.fFlags & kIrLAPDiscoverFlagsSlotMask];
1423				    fDiscoverSlot = random() % fDiscoverMaxSlots;
1424				    fDiscoverReplied = false;
1425				    fReplacementDevAddr = 0;
1426    #if forMac  // FIXME - XID slots are too long (w/ write completion proc).  I had to increase the time period
1427		//          for it to work.
1428				    StartTimer(fDiscoverMaxSlots * 140 * kMilliseconds, kIrQueryTimerExpiredEvent);
1429    #else
1430				    StartTimer(fDiscoverMaxSlots * 100 * kMilliseconds, kIrQueryTimerExpiredEvent);
1431    #endif
1432				    fDiscoverEnteredReplyState = false;
1433				}
1434
1435				// Respond to the XID query if haven't yet and its my slot
1436				if (!fDiscoverReplied && (xidCmd.fSlotNum >= fDiscoverSlot)) {
1437				    OutputXIDResponse(xidCmd);
1438				    fDiscoverReplied = true;
1439				    repostInput = false;
1440				}
1441			    }
1442			    else {
1443				// Final slot - all done with the XID game for now
1444				StopTimer();
1445
1446				if (fReplacementDevAddr) fMyDevAddr = fReplacementDevAddr;
1447
1448				// Discovery reply complete
1449				fState = kIrLAPDisconnectedState;
1450
1451				// ***MINIMUM: If this were a full implementation then the
1452				// listener (one who made a listen request) would receive some
1453				// sort of interim discovery indication.  But for now only the
1454				// discoverer (one who made a discover request) is notified.
1455
1456				//XASSERT(fCurrentRequest != nil);
1457				// JDG -- it *can* be nil when we're not doing much and get probed.
1458
1459				if (fCurrentRequest && fCurrentRequest->fEvent == kIrDiscoverRequestEvent) {
1460				    // Let the initiator know that the discovery phase has completed
1461				    TIrDscInfo* discoveryInfo = TIrDscInfo::tIrDscInfo();
1462				    TIrDiscoverReply* discoverReply = (TIrDiscoverReply*)fCurrentRequest;
1463				    fCurrentRequest = nil;
1464				    discoverReply->fEvent = kIrDiscoverReplyEvent;
1465				    if (discoveryInfo == nil) {
1466					discoverReply->fResult = kIrDAErrNoMemory;
1467				    }
1468				    else {
1469					// Fill in, extract info for discover info
1470					discoveryInfo->SetVersion(xidCmd.fVersion);
1471					discoveryInfo->SetDeviceAddr(xidCmd.fSrcDevAddr);
1472					discoveryInfo->ExtractDevInfoFromBuffer(fInputBuffer);
1473
1474					// Add it to the list of discovered devices
1475					discoverReply->fDiscoveredDevices->InsertLast(discoveryInfo);
1476					discoverReply->fResult = noErr;
1477					discoverReply->fPassiveDiscovery = true;
1478				    }
1479				    // In the case where we are replying to an XID cmd while
1480				    // discovering and are now finished with the discovering
1481				    // then we do not want to input again.
1482				    repostInput = false;
1483
1484				    GetLMP->EnqueueEvent(discoverReply);
1485				}
1486				else {
1487				    CIrDiscovery *  discObj = GetDiscovery;
1488
1489				    if( discObj ) {
1490					TIrDscInfo* discoveryInfo = TIrDscInfo::tIrDscInfo();
1491					//TIrDiscoverReply* discoverReply = (TIrDiscoverReply*)fCurrentRequest;   // ?
1492					if (discoveryInfo ) {
1493					    // Fill in, extract info for discover info
1494					    discoveryInfo->SetVersion(xidCmd.fVersion);
1495					    discoveryInfo->SetDeviceAddr(xidCmd.fSrcDevAddr);
1496					    discoveryInfo->ExtractDevInfoFromBuffer(fInputBuffer);
1497
1498					    discObj->PassiveDiscovery( discoveryInfo );
1499					}
1500				    }
1501				}
1502			    }
1503			}
1504		    }
1505		}
1506		// If we sent an XID response (or perhaps we were responding because we were
1507		// discovered while discovering) then don't fall thru, wait for output to complete
1508		if (!repostInput) break;
1509	    }
1510	    // Fall thru to OutputComplete event to re-post input
1511
1512	case kIrOutputCompleteEvent:
1513	    XTRACE(kReplyOutputDoneEvent, fNextCmdRspToSend, fDiscoverSlot);
1514	    StartInput(fIOBufferItem);
1515	    break;
1516
1517	case kIrQueryTimerExpiredEvent:
1518	    XTRACE(kReplyTimeoutEvent, 0, 0);
1519	    // ***FIXME: I got here because I missed the final slot query - if I responded
1520	    // to the query for my slot then everything should be ok; however, if I did not
1521	    // respond to a query for my slot then the other side doesn't know about me and
1522	    // listen should probably terminate with some error.
1523	    // ***I think that StopInput needs to be called here too.
1524	    if (fReplacementDevAddr) fMyDevAddr = fReplacementDevAddr;
1525	    fState = kIrLAPDisconnectedState;
1526	    DebugLog("Missed final packet of peer discovery;g");
1527	    //StopInput();                      // scc (?) was hanging here, let's reset it
1528	    //StartTimer(5*1000, kIrMediaBusyTimerExpiredEvent);        // 5 seconds abort read hack
1529	    //StartInput(fIOBufferItem);            // hang a read out
1530	    // TODO - review this again
1531	    break;
1532
1533	case kIrDisconnectRequestEvent:
1534	    XTRACE(kReplyDisconnectEvent, 0, 0);
1535	    XASSERT(fCurrentRequest != nil);
1536	    HandleNDMDisconnectRequest();
1537	    break;
1538
1539	case kIrListenRequestEvent:     // jdg hacking - just send the listen back to caller w/error
1540	    {
1541		XTRACE(kReplyListenRequestEvent, 0, 0);
1542		TIrConnLstnReply* connLstnReply = (TIrConnLstnReply*)GetCurrentEvent();
1543		connLstnReply->fEvent = kIrListenReplyEvent;
1544		connLstnReply->fResult = kIrDAErrToolBusy;
1545		GetLMP->EnqueueEvent(connLstnReply);
1546	    }
1547	    break;
1548
1549	case kIrDiscoverRequestEvent:
1550	    XTRACE(kUnexpectedEvent, fState, event);
1551	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
1552	    break;
1553
1554	default:
1555	    XTRACE(kUnexpectedEvent, fState, event);
1556	    DebugLog("TIrLAP::HandleReplyStateEvent: bad event");
1557	    break;
1558    }
1559
1560} // TIrLAP:: HandleReplyStateEvent
1561
1562
1563//--------------------------------------------------------------------------------
1564//      HandleNDMDisconnectRequest
1565//--------------------------------------------------------------------------------
1566void TIrLAP::HandleNDMDisconnectRequest()
1567{
1568    // Stop any pending input, output and timers
1569    StopInput();
1570    StopOutput();
1571    StopTimer();
1572
1573    fDiscoverActive = false;        // we are not discovering anymore
1574
1575
1576    // If a request is pending (discover, listen, connect) reply to it.
1577    if (fCurrentRequest != nil) {
1578	TIrEvent* reply = (TIrEvent*)fCurrentRequest;
1579	fCurrentRequest = nil;
1580	reply->fEvent = (UByte)RequestIdToReplyId(reply->fEvent);
1581	reply->fResult = kIrDAErrCancel;
1582	XTRACE(kNDMDisconnectFwdReply, fState, reply->fEvent);
1583	GetLMP->EnqueueEvent(reply);
1584    }
1585
1586    // Reply to the disconnect request
1587    TIrDisconnectReply* discReply = (TIrDisconnectReply*)GetCurrentEvent();
1588    discReply->fEvent = kIrDisconnectReplyEvent;
1589    discReply->fResult = kIrDAErrCancel;
1590    XTRACE(kNDMDisconnectReply, fState, 0);
1591
1592    // Change state to disconnected
1593    fState = kIrLAPDisconnectedState;
1594
1595    GetLMP->EnqueueEvent(discReply);
1596
1597} // HandleNDMDisconnectRequest
1598
1599
1600//--------------------------------------------------------------------------------
1601//      HandlePriReceiveStateEvent (fState == kIrLAPPriReceiveState)
1602//--------------------------------------------------------------------------------
1603void TIrLAP::HandlePriReceiveStateEvent(ULong event)
1604{
1605
1606    switch (event) {
1607	case kIrFinalTimerExpiredEvent:
1608	    GetIrDevice->Stats_ReceiveTimeout();
1609	    XTRACE(kPriReceiveFinalTimeoutEvent, 0, 0);
1610	    //DebugLog(" precv final timer");
1611	    StopInput();
1612
1613	    if (fRetryCount >= fDisconnectLinkLimit) {
1614		// Apply default conn parms, send disconnect indication, state = NDM
1615		DisconnectComplete(kIrDAErrTimeout);
1616	    }
1617	    else {
1618		if (fRetryCount == fDisconnectWarningLimit) {
1619		    fInBrokenBeam = true;
1620		    //gConnectionBroken = true;
1621		}
1622
1623	//      if( fRetryCount == 0 ) {                // Remember time of first retry
1624	//          fInitialRetryTime = TickCount();    // and smack the hardware
1625	//      }
1626
1627		fRetryCount++;
1628		// Output RR/RNR depending on whether local is busy or not
1629		OutputControlFrame(fLocalBusy ? kIrLAPFrameRNR : kIrLAPFrameRR);
1630	    }
1631	    break;
1632
1633	case kIrTurnaroundTimerExpiredEvent:
1634	    // Check for pending disconnect
1635	    if (fEnteringCloseState) {
1636		fNextCmdRspToSend = kIrLAPCmdDISC;
1637		fState = kIrLAPPriCloseState;
1638	    }
1639
1640	    // Check for set localBusy pending and set it and notify peer device
1641	    else if (fSetLocalBusyPending) {
1642		XTRACE(kSetLocalBusyEvent, 0, 0);
1643		fNextCmdRspToSend = kIrLAPFrameRNR;
1644		fLocalBusy = true;
1645		fSetLocalBusyPending = false;
1646	    }
1647
1648	    // Check for clr localBusy pending and clear it and notify peer device
1649	    else if (fClrLocalBusyPending) {
1650		XTRACE(kClrLocalBusyEvent, 0, 0);
1651		fNextCmdRspToSend = kIrLAPFrameRR;
1652		fLocalBusy = false;
1653		fClrLocalBusyPending = false;
1654	    }
1655
1656	    // Can we begin transmitting now?
1657	    else if (fNextCmdRspToSend == kIrLAPFrameINFO) {
1658		// NOTE: This is different from the secondary and also different
1659		// from the IrLAP spec.  The secondary will only enter XMIT if both
1660		// remoteBusy is false and there are pending requests.  The IrLAP spec
1661		// allows primary to enter XMIT no matter what.  But, this doesn't make
1662		// sense if the secondary is busy (i.e. remoteBusy is true), because
1663		// then there will be an entire P-timer timeout before the primary
1664		// receives again to find out if the secondary is no longer busy.  So,
1665		// in this case I only enter XMIT if fRemoteBusy is false.
1666//              if (fRemoteBusy) {
1667//                  fNextCmdRspToSend = fLocalBusy ? kIrLAPFrameRNR : kIrLAPFrameRR;
1668//              }
1669//              else {                                                          //CPD moved into Pri
1670//                  StartTimer(fPollTimerTimeout, kIrPollTimerExpiredEvent);    // XMIT state
1671		    fValidRecdNr = 0;
1672		    fState = kIrLAPPriTransmitState;
1673		    NextState(kIrTurnaroundTimerExpiredEvent);
1674		    break;
1675//              }
1676	    }
1677	    OutputControlFrame(fNextCmdRspToSend);  // Note: OutputControlFrame sets poll bit
1678	    break;
1679
1680	case kIrOutputCompleteEvent:
1681	    XTRACE(kPriReceiveOutputDoneEvent, fNextCmdRspToSend, 0);
1682	    switch (fNextCmdRspToSend) {
1683		case kIrLAPFrameRR:
1684		case kIrLAPFrameRNR:
1685		    // Finish up after sending RR/RNR
1686		    StartDataReceive();
1687		    StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
1688		    break;
1689
1690		default:
1691		    DebugLog("TIrLAP::HandlePriReceiveStateEvent: bad output state");
1692		    break;
1693	    }
1694	    break;
1695
1696	case kIrInputCompleteEvent:
1697	    XTRACE(kPriReceiveRecdInputEvent, fRecdCmdRsp, (fRecdNs << 8) | fRecdNr);
1698
1699	    // Stop the F-timer if received frame with Final bit set
1700	    if (RecdFinal()) {
1701		StopTimer();
1702	    }
1703
1704	    // We received some input so reset the retry count that is used for the
1705	    // disconnect warning or disconnect link actions in final timer timeout.
1706	    fRetryCount = 0;
1707#if forMac
1708	    fInitialRetryTime   = 0;
1709	    fInBrokenBeam       = false;
1710	    //gConnectionBroken     = false;
1711#endif
1712	    // Init most common cases for responses
1713	    fNextCmdRspToSend = kIrLAPFrameINFO;
1714
1715	    // TESTING
1716	    if (!RecdFinalRsp(kIrLAPRspFRMR))   // if anything other than FRMR
1717		    gLastWasFRMR = false;       // then reset the flag
1718
1719	    // Handle received data frames and supervisor commands
1720	    if (!RecdUFrame() || RecdRsp(kIrLAPRspUI)) {
1721		if (RecdInvalidNrOrNs()) {
1722		    // Record this as a protocol error
1723		    fProtocolErrs++;
1724		    // Disconnect if received invalid Nr or Ns
1725		    // NOTE: The upper layers do not support reset so just disconnect now
1726		    if (0) {            // jdg.  hit with hammer
1727			fEnteringCloseState = true;
1728			//DebugLog("fEnteringCloseState setting true #1");  // jdg
1729		    }
1730		    XTRACE(kIgnoringInvalidNrNs, 0, 0);     // jdg
1731		    /**if (1) {     // TEMP TEMP TEMP TEMP
1732			extern struct IrDALogHdr gIrDALog;
1733			gIrDALog.fTracingOn = false;        // HACK turn off tracing so we can dump w/tool
1734			DebugLog("lap: invalid ns/nr. logging stopped");    // temp
1735			fEnteringCloseState = true;         // TEMP TEMP TEMP TEMP
1736		    }***/
1737		}
1738		else {
1739		    ProcessRecdInfoOrSuperFrame();
1740		}
1741	    }
1742	    //
1743	    else if (RecdFinalRsp(kIrLAPRspFRMR)) {
1744		UInt8   frmrInfo[3];
1745		fInputBuffer->Getn( ( UInt8 * )&frmrInfo, 3 );  // format XA, BC
1746		XTRACE(kPriReceiveFRMREvent, frmrInfo[0], *( UInt16 *)&frmrInfo[1] );
1747    /*******/   GetIrDevice->Stats_TransmitTimeout();   /**** TEMP *** LOG FRMR RCVD *****/
1748		// Close down the link
1749		// JDG: but only if we've gotten more than one of these in a row!!!
1750		if (gLastWasFRMR) {
1751		    fEnteringCloseState = true;
1752	//          DebugLog("fEnteringCloseState setting true #2");
1753		    XTRACE(kLogEnteringCloseState, 2, 2);
1754		}
1755		else
1756		    gLastWasFRMR = true;        // if get another one, shut down the link
1757	    }
1758	    //
1759	    else if (RecdFinalRsp(kIrLAPRspRD) || RecdFinalRsp(kIrLAPRspRNRM)) {
1760		// Close down the link
1761		fEnteringCloseState = true;
1762		XTRACE(kLogEnteringCloseState, 3, 3);
1763		//DebugLog("fEnteringCloseState setting true #3");
1764	    }
1765	    // Received some other response w/final bit on - go to xmit state
1766	    else if (RecdFinal()) {
1767		// Record this as a protocol error
1768		fProtocolErrs++;
1769		// Handled below
1770	    }
1771	    // Received some other response w/final bit off - continue receiving
1772	    else {
1773		// Record this as a protocol error
1774		fProtocolErrs++;
1775		// Handled below
1776	    }
1777
1778	    // If didn't disconnect for some reason above, receive again or xmit after delay
1779	    if (fState == kIrLAPPriReceiveState) {
1780		if (RecdFinal()) {
1781		    // If received final, transmitting next (after min turnaround delay)
1782		    if( fRecdCmdRsp == kIrLAPFrameRNR ) {
1783			StartTimer(fPollTimerTimeout>>2, kIrTurnaroundTimerExpiredEvent);
1784		    }
1785		    else
1786			StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
1787//                  StartMinTurnAroundTimer( fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
1788		}
1789		else {
1790		    // If didn't receive final, receive again
1791		    StartDataReceive();
1792		}
1793	    }
1794	    break;
1795
1796	case kIrPutDataRequestEvent:
1797	    XTRACE(kPriReceivePutDataEvent, 0, 0);
1798	    PostponePutRequest();
1799	    break;
1800
1801	case kIrCancelPutRequestEvent:
1802	    CancelPutRequest();
1803	    break;
1804
1805	case kIrDisconnectRequestEvent:
1806	    XTRACE(kPriReceiveDisconnectEvent, 0, 0);
1807	    XASSERT(fPendingDisconnect == nil);
1808	    fPendingDisconnect = GetCurrentEvent();
1809	    fEnteringCloseState = true;
1810	    XTRACE(kLogEnteringCloseState, 4, 4);
1811	    //DebugLog("fEnteringCloseState setting true #4");
1812	    break;
1813
1814	case kIrLocalBusyClearedEvent:
1815	    // Don't need to do anything special here - handled above
1816	    XTRACE(kPriReceiveClrLocBsyPendEvent, 0, 0);
1817	    // XASSERT(fClrLocalBusyPending);   -- now bogus ... jdg
1818	    break;
1819
1820	case kIrDiscoverRequestEvent:
1821	case kIrListenRequestEvent:
1822	case kIrConnectRequestEvent:
1823	    XTRACE(kUnexpectedEvent, fState, event);
1824	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
1825	    break;
1826
1827	default:
1828	    XTRACE(kUnexpectedEvent, fState, event);
1829	    DebugLog("TIrLAP::HandlePriReceiveStateEvent: bad event");
1830	    break;
1831    }
1832
1833} // TIrLAP::HandlePriReceiveStateEvent
1834
1835
1836//--------------------------------------------------------------------------------
1837//      HandlePriTransmitStateEvent (fState == kIrLAPPriTransmitState)
1838//--------------------------------------------------------------------------------
1839void TIrLAP::HandlePriTransmitStateEvent(ULong event)
1840{
1841    switch (event) {
1842	case kIrPollTimerExpiredEvent:
1843#if forMac
1844	    //fIrSIR->TransmitTimeout();        // jdg - bogus, normal turnaround, not timeout
1845#endif
1846	    XTRACE(kPriTransmitPollTimeoutEvent, 0, 0);
1847	    fWaitingForPollTimer = false;
1848	    StopInput();
1849	    OutputControlFrame(kIrLAPFrameRR);  // Note: OutputControlFrame sets poll bit
1850	    break;
1851
1852	case kIrTurnaroundTimerExpiredEvent:
1853	    XTRACE(kPriTransmitEnterEvent, 0, 0);
1854	    if (!fPendingPutRequests->IsEmpty() && ! fRemoteBusy) {
1855		// There is something waiting to be sent.
1856		TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
1857		XASSERT(putRequest != nil);
1858		fPendingPutRequests->RemoveLast();
1859
1860		// Check if there are more put pending.  If not, then I can set p/f and turn the link
1861		fPutReqsPending = !fPendingPutRequests->IsEmpty();
1862
1863		// Only start the poll timer if there are multiple frames to send
1864		if( ( fWindow > 1 ) && fPutReqsPending ) {
1865		    StartTimer(fPollTimerTimeout, kIrPollTimerExpiredEvent);
1866		}
1867
1868		OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
1869	    }
1870	    else {
1871/*              // We have nothing to send and the remote is still busy or we are trading RR's.
1872		// Delay a bit to let the remote process its buffers (1/4 turn around time).  If
1873		// something else turned the link then just turn it back with a RR.
1874		if(     fRemoteBusy ||
1875		    (   fLastCmdRsp == kIrLAPFrameRR && fRecdCmdRsp == kIrLAPFrameRR ) ) {
1876		    fWaitingForPollTimer = true;
1877		    StartTimer( fPollTimerTimeout >> 2, kIrPollTimerExpiredEvent );
1878		}
1879		else {
1880*/                  NextState( kIrPollTimerExpiredEvent );  // so exit state with a RR
1881
1882/*                  // I received a full window of data last time, so chances are there is more
1883		    // to come.  Release the link immediately.
1884		    if( fRecdCmdRsp == kIrLAPFrameINFO )
1885			NextState( kIrPollTimerExpiredEvent );  // so exit state with a RR
1886		    else
1887		    // This gives the client time to process any data received, instead of
1888		    // spending all the time trading RRs back and forth.
1889			StartTimer( fPollTimerTimeout >> 2, kIrPollTimerExpiredEvent );
1890		}
1891*/          }
1892	    break;
1893
1894	case kIrOutputCompleteEvent:
1895	    XTRACE(kPriTransmitOutputDoneEvent, fNextCmdRspToSend, 0);
1896	    switch (fNextCmdRspToSend) {    // this is really the last cmd sent!
1897		case kIrLAPFrameINFO:
1898		    if (--fWindow > 0 && fPutReqsPending) {
1899			// Continue sending requests (if any and until P-timer expires)
1900			if (!fPendingPutRequests->IsEmpty()) {
1901			    TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
1902			    XASSERT(putRequest != nil);
1903			    fPendingPutRequests->RemoveLast();
1904
1905			    // Take note of whether additional put requests are pending now
1906			    fPutReqsPending = !fPendingPutRequests->IsEmpty();
1907
1908			    // Stop the timer if this is the last frame to send
1909			    if ( ( fWindow == 1 ) || !fPutReqsPending )  {
1910				StopTimer();
1911			    }
1912			    OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
1913			}
1914			break;
1915		    }
1916		    else {
1917			// Reset window
1918			fWindow = fPeerWindowSize;
1919
1920			if (fLocalBusy) {
1921			    // Send RNR if local busy
1922			    OutputControlFrame(kIrLAPFrameRNR); // Note: OutputControlFrame sets poll bit
1923			    break;
1924			}
1925
1926			else {
1927			    // fall thru and switch to RECV
1928			}
1929		    }
1930
1931		case kIrLAPFrameRR:
1932		case kIrLAPFrameRNR:
1933		    //StartDataReceive();                           // Post the read as soon as possible
1934		    StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
1935		    fState = kIrLAPPriReceiveState;
1936		    StartDataReceive();             // jdg: wait until state change to do read
1937		    break;
1938
1939		default:
1940		    DebugLog("TIrLAP::HandlePriTransmitStateEvent: bad output state");
1941		    break;
1942	    }
1943	    break;
1944
1945	case kIrPutDataRequestEvent:
1946	    XTRACE(kPriTransmitPutDataEvent, 0, 0);
1947	    // Only one choice for primary (now):
1948	    // If output in progress, queue the request.
1949	    // If other requests in queue, queue the request.
1950	    // And if no requests pending we already gave control back to primary, queue the request.
1951	    // If the p/f isn't set (fPutReqsPending), it may make it out this time around
1952	    if (fWaitingForPollTimer && !fRemoteBusy) {     // performance hack
1953		fWaitingForPollTimer = false;               // don't send out an RR
1954		StopTimer();
1955		OutputDataFrame((TIrPutRequest*)GetCurrentEvent(), true);       // always set final bit
1956	    }
1957	    else
1958	    PostponePutRequest();
1959
1960/*          // Queue up the request if outputting now or other requests in queue (to maintain order)
1961	    if (fOutputInProgress || !fPendingPutRequests->IsEmpty()) {
1962		XTRACE(kPriTransmitPutDataEvent, 0, 0);
1963		PostponePutRequest();
1964	    }
1965	    // No requests currently active or pending.  Send this one out.
1966	    else {
1967		XTRACE(kPriTransmitPutDataEvent, 1, 0);
1968		if (fWindow == 1) {
1969		    StopTimer();
1970		}
1971		OutputDataFrame((TIrPutRequest*)GetCurrentEvent(), !fLocalBusy && (fWindow == 1));
1972	    }
1973*/          break;
1974
1975	case kIrCancelPutRequestEvent:
1976	    CancelPutRequest();
1977	    break;
1978
1979	case kIrDisconnectRequestEvent:
1980	    XTRACE(kPriTransmitDisconnectEvent, 0, 0);
1981	    XASSERT(fPendingDisconnect == nil);
1982	    fPendingDisconnect = GetCurrentEvent();
1983	    fEnteringCloseState = true;
1984	    XTRACE(kLogEnteringCloseState, 5, 5);
1985	    //DebugLog("fEnteringCloseState setting true #5");
1986	    break;
1987
1988	case kIrLocalBusyClearedEvent:
1989	    // Don't need to do anything special here - handled in secondary receive
1990	    // ***FIXME: Could fLocalBusy be cleared here sometimes?  Would it improve performance any?
1991	    XTRACE(kPriReceiveClrLocBsyPendEvent, 0, 0);
1992	    XASSERT(fClrLocalBusyPending);
1993	    break;
1994
1995	case kIrDiscoverRequestEvent:
1996	case kIrListenRequestEvent:
1997	case kIrConnectRequestEvent:
1998	    XTRACE(kUnexpectedEvent, fState, event);
1999	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
2000	    break;
2001
2002	default:
2003	    XTRACE(kUnexpectedEvent, fState, event);
2004	    //DebugLog("TIrLAP::HandlePriTransmitStateEvent: bad event");
2005//          fIrDA->ReleaseEventBlock(GetCurrentEvent());    // jdg: free the event
2006	    break;
2007    }
2008
2009} // TIrLAP::HandlePriTransmitStateEvent
2010
2011
2012//--------------------------------------------------------------------------------
2013//      HandlePriCloseStateEvent (fState == kIrLAPPriCloseState)
2014//--------------------------------------------------------------------------------
2015void TIrLAP::HandlePriCloseStateEvent(ULong event)
2016{
2017    switch (event) {
2018	case kIrFinalTimerExpiredEvent:
2019	    XTRACE(kPriCloseFinalTimeoutEvent, 0, 0);
2020	    StopInput();
2021	    if (++fRetryCount >= kMaxDisconnectRetries) {
2022		// Apply default conn parms, send disconnect indication, state = NDM
2023		DisconnectComplete(kIrDAErrTimeout);
2024	    }
2025	    else {
2026		// Resend the disconnect
2027		OutputControlFrame(kIrLAPCmdDISC);  // Note: OutputControlFrame sets poll bit
2028	    }
2029	    break;
2030
2031	case kIrOutputCompleteEvent:
2032	    XTRACE(kPriCloseOutputDoneEvent, fNextCmdRspToSend, 0);
2033	    switch (fNextCmdRspToSend) {
2034		case kIrLAPCmdDISC:
2035		    if (fEnteringCloseState) {
2036			fEnteringCloseState = false;
2037			fRetryCount = 0;
2038		    }
2039		    StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
2040		    StartInput(fIOBufferItem);
2041		    break;
2042
2043		default:
2044		    DebugLog("TIrLAP::HandlePriCloseStateEvent: bad output state");
2045		    break;
2046	    }
2047	    break;
2048
2049	case kIrInputCompleteEvent:
2050	    XTRACE(kPriCloseRecdInputEvent, fRecdCmdRsp, (fRecdNs << 8) | fRecdNr);
2051	    if (RecdFinalRsp(kIrLAPRspUA) || RecdFinalRsp(kIrLAPRspDM)) {
2052		// Stop timer, apply default conn parms, send disconnect indication, state = NDM
2053		DisconnectComplete(kIrDAErrCancel);
2054	    }
2055	    else {
2056		// Continue waiting for the UA/DM response
2057		StartInput(fIOBufferItem);
2058	    }
2059	    break;
2060
2061	case kIrCancelPutRequestEvent:
2062	    CancelPutRequest();
2063	    break;
2064
2065	case kIrPutDataRequestEvent:
2066	    NotConnectedCompletion();                               // jdg: Yes, send to CIrLSAP, lmp doesn't handle this
2067	    //RejectRequest(GetCurrentEvent(), kCommErrNotConnected);   // jdg: send to lmp, not directly to lsapconn
2068	    break;
2069
2070	case kIrDiscoverRequestEvent:
2071	case kIrListenRequestEvent:
2072	case kIrConnectRequestEvent:
2073	    XTRACE(kUnexpectedEvent, fState, event);
2074	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
2075	    break;
2076
2077	case kIrDisconnectRequestEvent:                     // jdg: hold this until close is done
2078	    XTRACE(kPriCloseDisconnectRequest, 0, 0);
2079	    fPendingRequests->InsertLast(GetCurrentEvent());
2080	    break;
2081
2082	default:
2083	    XTRACE(kUnexpectedEvent, fState, event);
2084	    DebugLog("TIrLAP::HandlePriCloseStateEvent: bad event");
2085	    break;
2086    }
2087
2088} // TIrLAP::HandlePriCloseStateEvent
2089
2090
2091//--------------------------------------------------------------------------------
2092//      HandleSecReceiveStateEvent (fState == kIrLAPSecReceiveState)
2093//--------------------------------------------------------------------------------
2094void TIrLAP::HandleSecReceiveStateEvent(ULong event)
2095{
2096    switch (event) {
2097	case kIrWatchdogTimerExpiredEvent:
2098	    GetIrDevice->Stats_ReceiveTimeout();
2099	    XTRACE(kSecReceiveWDTimeoutEvent, 0, 0);
2100	    if (fRetryCount >= fDisconnectLinkLimit) {
2101		// Apply default conn parms, send disconnect indication, state = NDM
2102		StopInput();
2103		DisconnectComplete(kIrDAErrTimeout);
2104	    }
2105	    else {
2106		if (fRetryCount == fDisconnectWarningLimit) {
2107		    fInBrokenBeam = true;
2108		    //gConnectionBroken = true;
2109
2110		    //if( gIrDAPrefs.DoBrokenBeamWarning() )
2111		    //  BrokenBeamNotification( this );
2112		}
2113		//if( fRetryCount == 0 ) {              // Remember time of first retry
2114		//  fInitialRetryTime = TickCount();    // and smack the hardware
2115		//  fNextKickScc = fInitialRetryTime + 60 * 4;  // in 4 seconds if still deaf
2116		//}
2117		fRetryCount++;
2118		StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
2119	    }
2120	    break;
2121
2122	case kIrTurnaroundTimerExpiredEvent:
2123	    // Check for pending disconnect
2124	    if (fEnteringCloseState) {
2125		fNextCmdRspToSend = fRespondingToDisconnect ? kIrLAPRspUA : kIrLAPRspRD;
2126		fState = kIrLAPSecCloseState;
2127	    }
2128
2129	    // Check for pending FRMR response
2130	    else if (fFRMRPending) {
2131		OutputFRMRResponse();
2132		fFRMRPending = false;
2133		break;
2134	    }
2135
2136	    // Check for set localBusy pending and set it and notify peer device
2137	    else if (fSetLocalBusyPending) {
2138		XTRACE(kSetLocalBusyEvent, 0, 0);
2139		fNextCmdRspToSend = kIrLAPFrameRNR;
2140		fLocalBusy = true;
2141		fSetLocalBusyPending = false;
2142	    }
2143
2144	    // Check for clr localBusy pending and clear it and notify peer device
2145	    else if (fClrLocalBusyPending) {
2146		XTRACE(kClrLocalBusyEvent, 0, 0);
2147		fNextCmdRspToSend = kIrLAPFrameRR;
2148		fLocalBusy = false;
2149		fClrLocalBusyPending = false;
2150	    }
2151
2152	    // Can we begin transmitting now?
2153	    else if (fNextCmdRspToSend == kIrLAPFrameINFO) {
2154		if (fRemoteBusy || fPendingPutRequests->IsEmpty()) {
2155		    fNextCmdRspToSend = fLocalBusy ? kIrLAPFrameRNR : kIrLAPFrameRR;
2156		}
2157		else {
2158		    fValidRecdNr = 0;
2159		    fState = kIrLAPSecTransmitState;
2160		    NextState(kIrTurnaroundTimerExpiredEvent);
2161		    break;
2162		}
2163	    }
2164	    OutputControlFrame(fNextCmdRspToSend);  // Note: OutputControlFrame sets final bit
2165	    break;
2166
2167	case kIrOutputCompleteEvent:
2168	    XTRACE(kSecReceiveOutputDoneEvent, fNextCmdRspToSend, 0);
2169	    switch (fNextCmdRspToSend) {
2170		case kIrLAPFrameRR:
2171		case kIrLAPFrameRNR:
2172		case kIrLAPRspFRMR:
2173		    // Finish up after sending RR/RNR/FRMR
2174		    StartDataReceive();
2175		    StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
2176		    break;
2177
2178		default:
2179		    DebugLog("TIrLAP::HandleSecReceiveStateEvent: bad output state");
2180		    break;
2181	    }
2182	    break;
2183
2184	case kIrInputCompleteEvent:
2185	    XTRACE(kSecReceiveRecdInputEvent, fRecdCmdRsp, (fRecdNs << 8) | fRecdNr);
2186
2187	    // Stop the Watchdog-timer if received frame with Poll bit set
2188	    if (RecdPoll()) {
2189		StopTimer();
2190	    }
2191
2192	    // We received some input so reset the retry count that is used for the
2193	    // disconnect warning or disconnect link actions in watchdog timeout.
2194	    fRetryCount = 0;
2195
2196#if forMac
2197	    fInitialRetryTime   = 0;
2198	    //fNextKickScc      = 0;
2199	    fInBrokenBeam       = false;
2200	    //gConnectionBroken     = false;
2201#endif
2202	    // Init most common cases for responses
2203	    fNextCmdRspToSend = kIrLAPFrameINFO;
2204
2205	    // Ignore any non-poll bit set frames if in "error state" (waiting to send FRMR)
2206	    if (fFRMRPending && !RecdPoll()) {
2207		// Just ignore it
2208	    }
2209
2210	    // Handle received data frames and supervisor commands
2211	    else if (!RecdUFrame() || RecdCmd(kIrLAPRspUI)) {
2212		if (RecdInvalidNrOrNs()) {
2213		    // Record this as a protocol error
2214		    fProtocolErrs++;
2215		    // Prepare FRMR response - send it when we receive poll bit
2216		    PrepareFRMRResponse();
2217		}
2218		else {
2219		    ProcessRecdInfoOrSuperFrame();
2220		}
2221	    }
2222	    //
2223	    else if (RecdPollCmd(kIrLAPCmdDISC)) {
2224		// Reply to the disconnect
2225		fEnteringCloseState = true;
2226		XTRACE(kLogEnteringCloseState, 6, 6);
2227		//DebugLog("fEnteringCloseState setting true #6");
2228		fRespondingToDisconnect = true;
2229	    }
2230	    //
2231	    else if (RecdPollCmd(kIrLAPCmdSNRM)) {
2232		if (fRecdAddr == fConnAddr) {
2233		    // Reject the SNRM (reset not supported by IrLAPConn)
2234		    fEnteringCloseState = true;
2235		    XTRACE(kLogEnteringCloseState, 7, 7);
2236		    //DebugLog("fEnteringCloseState setting true #7");
2237		    fRespondingToDisconnect = false;
2238		}
2239		else {
2240		    // Ignore connection SNRMs from other sources
2241		    // Kind of a hack forcing poll bit off so StartDataReceive is called below
2242		    fRecdPF = 0;
2243		}
2244	    }
2245	    //
2246	    else if (RecdFinalRsp(kIrLAPRspDM)) {
2247		// Apply default conn parms, send disconnect indication, state = NDM
2248		DisconnectComplete(kIrDAErrCancel);
2249	    }
2250	    // Received some other unrecognized command - send FRMR
2251	    else {
2252		// Record this as a protocol error
2253		fProtocolErrs++;
2254		// Send FRMR
2255		PrepareFRMRResponse();
2256	    }
2257
2258	    // If didn't disconnect for some reason above, receive again or xmit after delay
2259	    if (fState == kIrLAPSecReceiveState) {
2260		if (RecdPoll()) {
2261		    // If received poll, transmitting next (after min turnaround delay)
2262		    StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
2263//                  StartMinTurnAroundTimer( fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
2264		}
2265		else {
2266		    // If didn't receive poll, receive again
2267		    StartDataReceive();
2268		}
2269	    }
2270	    break;
2271
2272	case kIrPutDataRequestEvent:
2273	    XTRACE(kSecReceivePutDataEvent, 0, 0);
2274	    PostponePutRequest();
2275	    break;
2276
2277	case kIrCancelPutRequestEvent:
2278	    CancelPutRequest();
2279	    break;
2280
2281	case kIrDisconnectRequestEvent:
2282	    XTRACE(kSecReceiveDisconnectEvent, 0, 0);
2283	    XASSERT(fPendingDisconnect == nil);
2284	    fPendingDisconnect = GetCurrentEvent();
2285	    fEnteringCloseState = true;
2286	    //DebugLog("fEnteringCloseState setting true #8");
2287	    XTRACE(kLogEnteringCloseState, 8, 8);
2288	    fRespondingToDisconnect = false;
2289	    break;
2290
2291	case kIrLocalBusyClearedEvent:
2292	    // Don't need to do anything special here - handled above
2293	    XTRACE(kSecReceiveClrLocBsyPendEvent, 0, 0);
2294	    XASSERT(fClrLocalBusyPending);
2295	    break;
2296
2297	case kIrConnectRequestEvent:                                    // jdg added
2298	case kIrListenRequestEvent:                                     // jdg added
2299	    XTRACE(kSecReceiveConnLstnRequest, 0, 0);
2300	    check(fCurrentRequest == nil);
2301	    fCurrentRequest = GetCurrentEvent();                    // hack so we can use ConnLstnComplete
2302	    ConnLstnComplete(noErr);
2303	    break;
2304
2305	case kIrDiscoverRequestEvent:
2306	    XTRACE(kUnexpectedEvent, fState, event);
2307	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
2308	    break;
2309
2310	default:
2311	    XTRACE(kUnexpectedEvent, fState, event);
2312	    DebugLog("TIrLAP::HandleSecReceiveStateEvent: bad event");
2313	    break;
2314    }
2315
2316} // TIrLAP::HandleSecReceiveStateEvent
2317
2318
2319//--------------------------------------------------------------------------------
2320//      HandleSecTransmitStateEvent (fState == kIrLAPSecTransmitState)
2321//--------------------------------------------------------------------------------
2322void TIrLAP::HandleSecTransmitStateEvent(ULong event)
2323{
2324    switch (event) {
2325	case kIrTurnaroundTimerExpiredEvent:
2326	    {
2327		XTRACE(kSecTransmitEnterEvent, 0, 0);
2328		// We just entered the transmit state
2329		// Should only be here if there are pending put requests and remote is not busy
2330		XASSERT(!fPendingPutRequests->IsEmpty() && !fRemoteBusy);
2331		TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
2332		XASSERT(putRequest != nil);
2333		fPendingPutRequests->RemoveLast();
2334		// Take note of whether additional put requests are pending now, because there
2335		// may not be any now, but a request might come in while the data is being
2336		// output, but we're locked in now and need to finish what we started after the
2337		// output completes (in other words, if we set poll bit here because no more
2338		// reqs pending (vs window == 1), then we have to give control to secondary after
2339		// the output whether another request comes in or not).
2340		fPutReqsPending = !fPendingPutRequests->IsEmpty();
2341		OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
2342	    }
2343	    break;
2344
2345	case kIrOutputCompleteEvent:
2346	    XTRACE(kSecTransmitOutputDoneEvent, fNextCmdRspToSend, 0);
2347	    switch (fNextCmdRspToSend) {
2348		case kIrLAPFrameINFO:
2349		    if ((--fWindow > 0) && fPutReqsPending) {
2350			// Continue sending requests (if pending and peer device has room)
2351			TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
2352			XASSERT(putRequest != nil);
2353			fPendingPutRequests->RemoveLast();
2354			// Take note of whether additional put requests are pending now (see note above)
2355			fPutReqsPending = !fPendingPutRequests->IsEmpty();
2356			OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
2357			break;
2358		    }
2359		    else {
2360			// Reset window
2361			fWindow = fPeerWindowSize;
2362
2363			if (fLocalBusy) {
2364			    // Send RNR if local busy
2365			    OutputControlFrame(kIrLAPFrameRNR); // Note: OutputControlFrame sets final bit
2366			    break;
2367			}
2368
2369			else {
2370			    // fall thru and switch to RECV
2371			}
2372		    }
2373
2374		case kIrLAPFrameRR:
2375		case kIrLAPFrameRNR:
2376		    StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
2377		    fState = kIrLAPSecReceiveState;
2378		    StartDataReceive();         // jdg: change state before issuing read - can come right back
2379						// with some data ... before I get a chance to changestate!
2380		    break;
2381
2382		default:
2383		    DebugLog("TIrLAP::HandleSecTransmitStateEvent: bad output state");
2384		    break;
2385	    }
2386	    break;
2387
2388	case kIrPutDataRequestEvent:
2389	    XTRACE(kSecTransmitPutDataEvent, 0, 0);
2390	    // Only one choice for secondary:
2391	    // If output in progress, queue the request.
2392	    // If other requests in queue, queue the request.
2393	    // And if no requests pending we already gave control back to primary, queue the request.
2394	    PostponePutRequest();
2395	    break;
2396
2397	case kIrCancelPutRequestEvent:
2398	    CancelPutRequest();
2399	    break;
2400
2401	case kIrDisconnectRequestEvent:
2402	    XTRACE(kSecTransmitDisconnectEvent, 0, 0);
2403	    XASSERT(fPendingDisconnect == nil);
2404	    fPendingDisconnect = GetCurrentEvent();
2405	    fEnteringCloseState = true;
2406	    //DebugLog("fEnteringCloseState setting true #9");
2407	    XTRACE(kLogEnteringCloseState, 9, 9);
2408	    break;
2409
2410	case kIrLocalBusyClearedEvent:
2411	    // Don't need to do anything special here - handled in secondary receive
2412	    // ***FIXME: Could fLocalBusy be cleared here sometimes?  Would it improve performance any?
2413	    XTRACE(kSecTransmitClrLocBsyPendEvent, 0, 0);
2414	    XASSERT(fClrLocalBusyPending);
2415	    break;
2416
2417	case kIrConnectRequestEvent:                                    // jdg added
2418	case kIrListenRequestEvent:                                     // jdg added
2419	    XTRACE(kSecTransmitConnLstnRequest, 0, 0);
2420	    check(fCurrentRequest == nil);
2421	    fCurrentRequest = GetCurrentEvent();                    // hack so we can use ConnLstnComplete
2422	    ConnLstnComplete(noErr);
2423	    break;
2424
2425	case kIrDiscoverRequestEvent:
2426	    XTRACE(kUnexpectedEvent, fState, event);
2427	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
2428	    break;
2429
2430	default:
2431	    XTRACE(kUnexpectedEvent, fState, event);
2432	    DebugLog("TIrLAP::HandleSecTransmitStateEvent: bad event");
2433	    break;
2434    }
2435
2436} // TIrLAP::HandleSecTransmitStateEvent
2437
2438
2439//--------------------------------------------------------------------------------
2440//      HandleSecCloseStateEvent (fState == kIrLAPSecCloseState)
2441//--------------------------------------------------------------------------------
2442void TIrLAP::HandleSecCloseStateEvent(ULong event)
2443{
2444    switch (event) {
2445	case kIrWatchdogTimerExpiredEvent:
2446	    XTRACE(kSecCloseWDTimeoutEvent, 0, 0);
2447	    StopInput();
2448	    // Apply default conn parms, send disconnect indication, state = NDM
2449	    DisconnectComplete(kIrDAErrTimeout);
2450	    break;
2451
2452	case kIrTurnaroundTimerExpiredEvent:
2453	    OutputControlFrame(fNextCmdRspToSend);  // Note: OutputControlFrame sets final bit
2454	    break;
2455
2456	case kIrOutputCompleteEvent:
2457	    XTRACE(kSecCloseOutputDoneEvent, fNextCmdRspToSend, 0);
2458	    switch (fNextCmdRspToSend) {
2459		case kIrLAPRspRD:
2460		    fEnteringCloseState = false;
2461		    StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
2462		    StartInput(fIOBufferItem);
2463		    break;
2464
2465		case kIrLAPRspUA:
2466		    // Apply default conn parms, send disconnect indication, state = NDM
2467		    DisconnectComplete(kIrDAErrCancel);
2468		    break;
2469
2470		default:
2471		    DebugLog("TIrLAP::HandleSecCloseStateEvent: bad output state");
2472		    break;
2473	    }
2474	    break;
2475
2476	case kIrInputCompleteEvent:
2477	    XTRACE(kSecCloseRecdInputEvent, fRecdCmdRsp, 0);
2478	    // Stop the watchdog timer
2479	    StopTimer();
2480
2481	    if (RecdPollCmd(kIrLAPCmdDISC)) {
2482		// Acknowledge the disconnect (after min turnaround delay)
2483		fNextCmdRspToSend = kIrLAPRspUA;
2484		StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
2485//              StartMinTurnAroundTimer( fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
2486	    }
2487	    else if (RecdFinalRsp(kIrLAPRspDM)) {
2488		// Stop timer, apply default conn parms, send disconnect indication, state = NDM
2489		DisconnectComplete(kIrDAErrCancel);
2490	    }
2491	    else if (RecdPoll()) {
2492		// Resend the RD (after min turnaround delay)
2493		fNextCmdRspToSend = kIrLAPRspRD;
2494		StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
2495//              StartMinTurnAroundTimer( fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
2496	    }
2497	    else {
2498		// Continue waiting for the DISC/DM response
2499		StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
2500		StartInput(fIOBufferItem);
2501	    }
2502	    break;
2503
2504	case kIrCancelPutRequestEvent:
2505	    CancelPutRequest();
2506	    break;
2507
2508	case kIrPutDataRequestEvent:
2509	    NotConnectedCompletion();               // jdg - yes, pls do send back to CIrLSAP, not to lmp which drops it
2510	    //RejectRequest(GetCurrentEvent(), kCommErrNotConnected);   // jdg: send to lmp, not directly to lsapconn
2511	    break;
2512
2513	case kIrDiscoverRequestEvent:
2514	case kIrListenRequestEvent:
2515	case kIrConnectRequestEvent:
2516	    XTRACE(kUnexpectedEvent, fState, event);
2517	    RejectRequest(GetCurrentEvent(), kIrDAErrWrongState);   // don't do it, don't crash
2518	    break;
2519
2520	case kIrDisconnectRequestEvent:                     // jdg: hold this until close is done
2521	    XTRACE(kSecCloseDisconnectRequest, 0, 0);
2522	    fPendingRequests->InsertLast(GetCurrentEvent());
2523	    break;
2524
2525	default:
2526	    XTRACE(kUnexpectedEvent, fState, event);
2527	    DebugLog("TIrLAP::HandleSecCloseStateEvent: bad event");
2528	    break;
2529    }
2530
2531} // TIrLAP::HandleSecCloseStateEvent
2532
2533
2534//--------------------------------------------------------------------------------
2535//      UpdateNrReceived
2536//--------------------------------------------------------------------------------
2537void TIrLAP::UpdateNrReceived()
2538{
2539    XTRACE(kUpdateNrReceived, fNextToAck, fRecdNr);
2540
2541    while (fNextToAck != fRecdNr) {
2542	TIrPutReply* putReply = (TIrPutReply*)fPutRequests[fNextToAck];
2543	fPutRequests[fNextToAck] = nil;
2544
2545	// Send back reply (or in some cases free up the request block)
2546	PutComplete(putReply, noErr);
2547
2548	// Clear the fValidRecdNr bit that corresponds to the "ack'd"
2549	fValidRecdNr &= ~(1 << fNextToAck);
2550
2551	// Check next to ack (taking wrapping into account)
2552	fNextToAck = (fNextToAck + 1) & 0x7;
2553    }
2554
2555} // TIrLAP::UpdateNrReceived
2556
2557
2558//--------------------------------------------------------------------------------
2559//      ResendRejectedFrames
2560//--------------------------------------------------------------------------------
2561void TIrLAP::ResendRejectedFrames()
2562{
2563    // ***FIXME: Should the fValidRecdNr bits be "reduced" by the amount resent
2564    // And if not, should the fPutRequests be nil'd out or left alone?
2565
2566    ULong index = (fVs - 1) & 0x7;
2567
2568    XTRACE(kResendRejectedFrames, 0, index);        // debug
2569
2570    // Go thru the list backwards so frames are resent in the correct order
2571    while (true) {
2572	TIrPutRequest* putRequest = fPutRequests[index];
2573	XASSERT(putRequest != nil);
2574	if (putRequest == nil) {
2575	    // Client must have cancelled put and peer device is asking for resend
2576	    // Just get out of here, because things will be shut down soon anyway.
2577	    break;
2578	}
2579	XTRACE(kResendRejectedFrames, 1, index);        // jdg
2580
2581	fPendingPutRequests->InsertLast(putRequest);
2582
2583	fPutRequests[index] = nil;
2584	fDataRetries++;
2585#if forMac
2586	GetIrDevice->Stats_PacketResent();
2587	// testing TEMP TEMP TEMP TEMP TEMP
2588	//if (fIrSIR->fIRStats.resent == 100) { // if hit 100 resends
2589	//  extern struct IrDALogHdr gIrDALog;
2590	//  gIrDALog.fTracingOn = false;        // HACK turn off tracing so we can dump w/tool
2591	//  DebugLog("Ok, 100 resends. logging turned off, dump the log");
2592	//}
2593#endif
2594	if (index == fRecdNr) {
2595	    break;
2596	} else {
2597	    index = (index - 1) & 0x7;
2598	}
2599    }
2600
2601    // Back up Vs, ready for the first resend
2602    fVs = fRecdNr;
2603
2604    XTRACE(kResendRejectedFrames, 2, fVs);          // jdg
2605
2606} // TIrLAP::ResendRejectedFrames
2607
2608
2609//--------------------------------------------------------------------------------
2610//      ProcessRecdInfoOrSuperFrame
2611//--------------------------------------------------------------------------------
2612void TIrLAP::ProcessRecdInfoOrSuperFrame()
2613{
2614    // This is a common routine used by both primary and secondary receive states
2615    // It should only be called for information/supervisory frames or the UI frame.
2616    // It is assumed that the invalid Ns/Nr case has already been checked for.
2617    // Also if the F/P bit was received the caller should have already stopped the timer.
2618    // And on entry, fNextCmdRspToSend is defaulted (preset) to kIrLAPFrameINFO.
2619
2620    XTRACE(kProcessISFrame, RecdCmd(), RecdRsp());
2621
2622    if (!Recd(kIrLAPRspUI)) {
2623	// Primary should only receive responses, secondary should only receive commands
2624	if ((fPrimary && RecdCmd()) || (!fPrimary && RecdRsp())) {
2625	    // Record this as a protocol error
2626	    fProtocolErrs++;
2627	    // Stop timer, apply default conn parms, send disconnect indication, state = NDM
2628	    DisconnectComplete(kIrDAErrPacket);
2629	    return;
2630	}
2631	// Update Nr received - i.e. reply to put requests, remove buffers from list
2632	UpdateNrReceived();
2633    }
2634
2635    switch(fRecdCmdRsp) {
2636	case kIrLAPFrameINFO:
2637	    // Process received data if not fLocalBusy (or local busy pending)
2638	    if (!fLocalBusy && !fSetLocalBusyPending) {
2639		if (RecdUnexpectedNs()) {
2640		    // Not used if not final/poll frame but doesn't hurt to set it
2641		    fNextCmdRspToSend = kIrLAPFrameRR;
2642#if forMac
2643		    GetIrDevice->Stats_PacketDropped();
2644#endif
2645		}
2646		else {
2647		    // This should never happen!
2648		    XASSERT(fInputBuffer != fIOBufferItem);
2649		    if (fInputBuffer == fIOBufferItem) {    // Debugging
2650			DebugLog("oops, fInputbuffer == fIObufferItem 0x%lx", (uintptr_t) fInputBuffer);
2651			//IrDALogTracingOff();              // Debugging!
2652		    }
2653
2654		    // Let the demultipexor know that a buffer has arrived
2655		    GetLMP->Demultiplexor(fInputBuffer);
2656
2657		    // Clear the fValidRecdNs bit that corresponds to current fVr
2658		    fValidRecdNs &= ~(1 << fVr);
2659
2660		    // Update fValidRecdNs to include next maximum allowed received Ns
2661		    fValidRecdNs |= 1 << ((fVr + fMyWindowSize) & 0x7);
2662
2663		    // Record that I received/accepted a frame
2664		    fVr = (fVr + 1) & 0x7;
2665
2666		    // Next receive requires new buffer
2667		    //fNeedNewInputBuffer = true;
2668		    fInputBuffer = nil;
2669
2670		    // If we just passed a buffer to the demultiplexor and there was not
2671		    // a "get" request pending to consume the data immediately and there
2672		    // are no more buffers then we are entering a local busy condition.
2673		    if (fGetBufferAvail == 0) {
2674			XTRACE(kSetLocalBusyPendingEvent, 0, 0);
2675			fSetLocalBusyPending = true;
2676		    }
2677
2678		    if (RecdUnexpectedNr()) {
2679			ResendRejectedFrames();
2680		    }
2681		}
2682	    }
2683#if forMac
2684	    else
2685		GetIrDevice->Stats_PacketDropped();         // Packet was dropped due to flow control
2686#endif
2687	    break;
2688
2689	case kIrLAPFrameRR:
2690	    fRemoteBusy = false;
2691	    if (RecdUnexpectedNr() && !fLocalBusy) {
2692		ResendRejectedFrames();
2693	    }
2694#if forMac
2695	    GetIrDevice->Stats_RRRec();
2696#endif
2697	    break;
2698
2699	case kIrLAPFrameREJ:
2700	    ResendRejectedFrames();
2701#if forMac
2702	    GetIrDevice->Stats_REJRec();
2703#endif
2704	    break;
2705
2706	case kIrLAPFrameSREJ:
2707	    ResendRejectedFrames();
2708#if forMac
2709	    GetIrDevice->Stats_SREJRec();
2710#endif
2711	    break;
2712
2713	case kIrLAPFrameRNR:
2714	    fRemoteBusy = true;
2715	    fNextCmdRspToSend = fLocalBusy ? kIrLAPFrameRNR : kIrLAPFrameRR;
2716#if forMac
2717	    GetIrDevice->Stats_RNRRec();                // Remote is in flow control
2718#endif
2719	    break;
2720
2721	default:
2722	    XASSERT(fRecdCmdRsp == kIrLAPRspUI);
2723	    if (!fLocalBusy) {
2724		// ***FUTURE: Handle ui here
2725
2726		// Next receive requires new buffer
2727		// ***FUTURE: Put back next line when/if actual ui receiver implemented
2728		// fNeedNewInputBuffer = true;
2729	    }
2730	    break;
2731    }
2732
2733} // TIrLAP::ProcessRecdInfoOrSuperFrame
2734
2735
2736//--------------------------------------------------------------------------------
2737//      CopyStatsTo
2738//--------------------------------------------------------------------------------
2739void TIrLAP::CopyStatsTo(TCMOSlowIRStats* irStats)
2740{
2741#if forMac
2742#pragma unused(irStats)
2743#else
2744    // Just copy the stats that IrLAP modifies
2745    irStats->dataRetries = fDataRetries;
2746    irStats->protocolErrs = fProtocolErrs;
2747#endif
2748
2749} // TIrLAP::CopyStatsTo
2750
2751
2752//--------------------------------------------------------------------------------
2753//      ResetStats
2754//--------------------------------------------------------------------------------
2755void TIrLAP::ResetStats()
2756{
2757    // Just clear the fields that IrLAP modifies
2758    fDataRetries = 0;
2759    fProtocolErrs = 0;
2760
2761} // TIrLAP::ResetStats
2762
2763
2764//=============================== Utility methods ================================
2765
2766
2767//--------------------------------------------------------------------------------
2768//      ParseNegotiateAndInitConnState
2769//--------------------------------------------------------------------------------
2770IrDAErr TIrLAP::ParseNegotiateAndInitConnState(Boolean primary)
2771{
2772    // **FIXME: Should this be broken up a bit to make patching easier?
2773
2774    IrDAErr result;
2775    ULong numBuffers;
2776    ULong bufferSize;
2777    CBufferSegment* bufferItem;
2778    TTimeout retryTimeUnit;
2779    TTimeout disconnectLinkTime;
2780
2781    fPrimary = primary;
2782
2783    // Parse negotiation parms passed (may not be any, don't panic - use defaults)
2784    result = fPeerQOS->ExtractInfoFromBuffer(fInputBuffer);
2785    XREQUIRENOT(result, Fail_QOS_ExtractInfo);
2786
2787    // Negotiate conn parms
2788    result = fMyQOS->NegotiateWith(fPeerQOS);
2789    XREQUIRENOT(result, Fail_QOS_NegotiateMe);
2790    result = fPeerQOS->NegotiateWith(fMyQOS);
2791    XREQUIRENOT(result, Fail_QOS_NegotiatePeer);
2792
2793    // Apply conn parms (that can be) ahead of time
2794
2795    // Note: DON'T change baud rate yet
2796    XASSERT(fMyQOS->GetBaudRate() == fPeerQOS->GetBaudRate());
2797    XTRACE(kQOSSetBaudRateEvent, 0, fMyQOS->GetBaudRate());
2798
2799    // Set various timeout values (Note: WD timeout is 1.25x time primary can hold link)
2800    fPollTimerTimeout = fMyQOS->GetMaxTurnAroundTime();
2801    fFinalTimerTimeout = fPeerQOS->GetMaxTurnAroundTime();
2802
2803    // HACK -- since we don't really wait for our transmit queue to empty before
2804    // turning the link around, we have to bump up the time we wait for our peer's
2805    // response by the time we could be spending transmitting.
2806    // TEST == incr finaltimer (and polltimer) by our max time
2807    //fPollTimerTimeout  += fMyQOS->GetMaxTurnAroundTime();
2808    //fFinalTimerTimeout += fMyQOS->GetMaxTurnAroundTime();
2809    // TEMP TEMP.  TODO: impl real output complete so the timer is correct?
2810
2811    //fPollTimerTimeout = fPeerQOS->GetMaxTurnAroundTime();
2812    //fFinalTimerTimeout = fMyQOS->GetMaxTurnAroundTime();
2813    //fFinalTimerTimeout += fPollTimerTimeout;      // JDG HACKING
2814
2815    fWatchdogTimeout = fPeerQOS->GetMaxTurnAroundTime() + (fPeerQOS->GetMaxTurnAroundTime() >> 2);
2816    fMinTurnAroundTimeout = fPeerQOS->GetMinTurnAroundTime();
2817    //DebugLog(" test - setting peer min ttime to 10 ms;g");
2818    //fMinTurnAroundTimeout = 10;       // TEST TEST TEST new hardware
2819
2820    // Set link disconnect warning/limit times
2821    retryTimeUnit = primary ? fFinalTimerTimeout : fWatchdogTimeout;
2822
2823    // Note: addition of (retryTimeUnit / 2) is to round up for better accuracy
2824    disconnectLinkTime = fMyQOS->GetLinkDiscThresholdTime();
2825    fDisconnectLinkLimit = (disconnectLinkTime + (retryTimeUnit >> 1)) / retryTimeUnit;
2826    // Calculate the BB duration time.  Adjust for one retry at the beginning.
2827    fDisconnectLinkLimitTime = fDisconnectLinkLimit * retryTimeUnit - retryTimeUnit;
2828
2829    if (disconnectLinkTime == kIrDisconnectWarningTimeout) {
2830	// Special case: warning time is 0 seconds if link disconnect at 3 seconds
2831	fDisconnectWarningLimit = 0;
2832    }
2833    else {
2834	// Note: addition of (retryTimeUnit / 2) is to round up for better accuracy
2835	fDisconnectWarningLimit = ((kIrDisconnectWarningTimeout + (retryTimeUnit >> 1)) / retryTimeUnit) - 1;
2836    }
2837
2838    // Set number of frames that can be sent to peer before giving up link
2839    fPeerWindowSize = (UByte)fPeerQOS->GetWindowSize();
2840
2841    // Set number of frames that peer can send to me before giving up link
2842    fMyWindowSize = (UByte)fMyQOS->GetWindowSize();
2843
2844    // Allocate receive buffers
2845    numBuffers = fMyQOS->GetWindowSize() * 2;   // FIXME - post alpha allocate extra to avoid assert
2846    bufferSize = fMyQOS->GetDataSize()+5;       // Add room for Addr, CNTL, CRC and 1 for DMA
2847
2848    check(numBuffers <= (sizeof(fGetBuffers) / sizeof(fGetBuffers[0])));    // sanity
2849    check(numBuffers < 32);                                                 // bitmask allocation
2850    // Allocate buffers for receiving data
2851    for (fGetBufferAvail = 0, fNumGetBuffers = 0; fNumGetBuffers < numBuffers; fNumGetBuffers++) {
2852	// Allocate, init buffer segment and check for errors
2853	result = kIrDAErrNoMemory;
2854	bufferItem = CBufferSegment::New( bufferSize );
2855	XREQUIRE(bufferItem, Fail_BufferItem_New);
2856
2857	// Add next buffer list
2858	fGetBuffers[fNumGetBuffers] = bufferItem;
2859	fGetBufferAvail |= (ULong) (1 << fNumGetBuffers);
2860    }
2861
2862    // First my info
2863    XTRACE(kQOSBufferInfoEvent, fMyQOS->GetWindowSize(), fMyQOS->GetDataSize());
2864    XTRACE(kQOSLeadInCountEvent, 0, fMyQOS->GetExtraBOFs());
2865    XTRACE(kQOSMinTurnAroundEvent, 0, fMyQOS->GetMinTurnAroundTime() / kMicroseconds);
2866    XTRACE(kQOSMaxTurnAroundEvent, 0, fMyQOS->GetMaxTurnAroundTime() / kMilliseconds);
2867
2868    // Then the peer device's info
2869    XTRACE(kQOSBufferInfoEvent, fPeerQOS->GetWindowSize(), fPeerQOS->GetDataSize());
2870    XTRACE(kQOSLeadInCountEvent, 1, fPeerQOS->GetExtraBOFs());
2871    XTRACE(kQOSMinTurnAroundEvent, 1, fPeerQOS->GetMinTurnAroundTime() / kMicroseconds);
2872    XTRACE(kQOSMaxTurnAroundEvent, 1, fPeerQOS->GetMaxTurnAroundTime() / kMilliseconds);
2873
2874    // Initialize connection state
2875    fVr = 0;
2876    fVs = 0;
2877    fWindow = fPeerWindowSize;
2878    fValidRecdNs = 0xFF >> (8 - fMyWindowSize);
2879
2880    fRetryCount = 0;
2881#if forMac
2882    fInitialRetryTime   = 0;
2883    //fNextKickScc      = 0;
2884    fInBrokenBeam       = false;
2885    //gConnectionBroken     = false;
2886#endif
2887
2888    fRemoteBusy = false;
2889    fLocalBusy = false;
2890    fSetLocalBusyPending = false;
2891    fClrLocalBusyPending = false;
2892
2893    fRecdNr = 0;
2894    fRecdNs = 0;
2895    fNextToAck = 0;
2896
2897    return noErr;
2898
2899    // Error exits:
2900
2901//Fail_BufferItem_Init:
2902//  delete bufferItem;
2903
2904Fail_BufferItem_New:
2905    FreeGetBuffers();
2906
2907Fail_QOS_NegotiatePeer:
2908Fail_QOS_NegotiateMe:
2909Fail_QOS_ExtractInfo:
2910
2911    ConnLstnComplete(result);
2912    return result;
2913
2914} // TIrLAP::ParseNegotiateAndInitConnState
2915
2916
2917//--------------------------------------------------------------------------------
2918//      ConnLstnComplete
2919//--------------------------------------------------------------------------------
2920void TIrLAP::ConnLstnComplete(IrDAErr result)
2921{
2922    // Let the initiator know that the connect/listen has completed
2923    TIrConnLstnReply* connLstnReply = (TIrConnLstnReply*)fCurrentRequest;
2924    XTRACE(kConnLstnComplete, fPeerDevAddr >> 16, fPeerDevAddr);
2925    fCurrentRequest = nil;
2926    //XASSERT(connLstnReply != nil);    // jdg, this can happen if we're not doing much and get connected to
2927    if (connLstnReply) {            // jdg - if there was a current request (can be listen, connect or discover)
2928	//XASSERT((connLstnReply->fEvent == kIrConnectRequestEvent) || (connLstnReply->fEvent == kIrListenRequestEvent));
2929	if ((connLstnReply->fEvent == kIrConnectRequestEvent) || (connLstnReply->fEvent == kIrListenRequestEvent)) {
2930	    connLstnReply->fEvent = (UByte)RequestIdToReplyId(connLstnReply->fEvent);
2931	    connLstnReply->fPassiveConnect = (connLstnReply->fEvent == kIrConnectReplyEvent) && !fPrimary;
2932	    connLstnReply->fResult = result;
2933	    connLstnReply->fDevAddr = fPeerDevAddr; // Only listen needs this, already set for connect
2934	}
2935	else {      // we have a request, but it's not listen or connect (probably discover).  reject it.
2936	    if (connLstnReply->fEvent == kIrDiscoverRequestEvent) {
2937		RejectRequest(connLstnReply, kIrDAErrRetry);	// send it back with an error
2938		connLstnReply = nil;				// don't do it again!  nil out for below
2939	    }
2940	    else {
2941		XTRACE(kConnLstnComplete, (UInt16)-2, (UInt16)-2);      // bug: can have a listen complete ...
2942		// just ignore it for now ...
2943	    }
2944	}
2945    }
2946    else {
2947	XTRACE(kConnLstnComplete, (UInt16)-1, (UInt16)-1);      // jdg: what to do here?
2948    }
2949    // Connect/listen failed?
2950    if (result != noErr) {
2951	fState = kIrLAPDisconnectedState;
2952    }
2953    if (connLstnReply)      // jdg
2954	GetLMP->EnqueueEvent(connLstnReply);
2955
2956} // TIrLAP::ConnLstnComplete
2957
2958
2959//--------------------------------------------------------------------------------
2960//      DisconnectComplete
2961//--------------------------------------------------------------------------------
2962void TIrLAP::DisconnectComplete(IrDAErr result)
2963{
2964    // Its not good to complete disconnect with okay
2965    XASSERT(result != noErr);
2966
2967    // Stop the Final/Poll/Watchdog timer (if it was on - nop if it wasn't)
2968    StopTimer();
2969
2970    // Strickly speaking this shouldn't be necessary if this has been called properly
2971    // But its a good idea to make sure that they're really "stopped" before shutting down
2972    // At least check to see if calling code has some logic errors/flaws/omissions/opportunities
2973    XASSERT(!fInputInProgress);
2974    XASSERT(!fOutputInProgress);
2975    StopInput();
2976    StopOutput();
2977
2978    // Complete all in progress and pending put requests
2979    CancelPendingPutRequests(nil, kIrDAErrCancel);
2980
2981
2982    // Reset some state in case we are re-connected to.
2983#if forMac
2984    fInBrokenBeam = false;
2985    //gConnectionBroken = false;
2986    fConnected = false;                     // JDG.  we're no longer connected
2987    fNickName[0] = 0;                       // Clear out the connect name.
2988
2989#endif
2990
2991    fLocalBusy = false;
2992    fSetLocalBusyPending = false;
2993    fEnteringCloseState = false;
2994    fFRMRPending = false;
2995    //fNeedNewInputBuffer = true;       // jdg - this is now cleared in FreeGetBuffers
2996
2997    fState = kIrLAPDisconnectedState;
2998
2999    // Notify initiator of disconnect or notify clients via async event response
3000    if (fPendingDisconnect) {
3001	TIrDisconnectReply* disconnectReply = (TIrDisconnectReply*)fPendingDisconnect;
3002	fPendingDisconnect = nil;
3003	disconnectReply->fEvent = kIrDisconnectReplyEvent;
3004	disconnectReply->fResult = result;
3005	XTRACE(kNRMDisconnectReply, fState, 0);
3006	GetLMP->EnqueueEvent(disconnectReply);
3007	fIrDA->Disconnected(false);     // tell glue to reset qos only
3008	Reset();            // JDG: FreeGetBuffers (else memory leak on next connection)
3009    }
3010    else {
3011	// async disconnect
3012	XTRACE(kNRMDisconnectAsyncReply, fState, 0);  // FIXME - This doesn't look good for mac
3013	fIrDA->Disconnected(true);      // tell glue to reset qos and lap and lmp and lapconn ...
3014    }
3015
3016    // Reset back to NDM state (9600bps, disconnected, etc.)
3017    ApplyDefaultConnParms();
3018
3019    // jdg: now that we're back to normal, requeue any requests that came in while
3020    // we were waiting for the close state to exit
3021    if (fPendingRequests && !fPendingRequests->Empty()) {
3022	CListIterator *iter = CListIterator::cListIterator(fPendingRequests);
3023	TIrEvent *request;
3024	for (request = (TIrEvent*)iter->FirstItem();
3025	    iter->More(); request = (TIrEvent*)iter->NextItem()) {
3026		XTRACE(kNRMDisconnectRequeue,0, request->fEvent);
3027		// Send the reply to ourselves
3028		this->EnqueueEvent(request);
3029	}
3030	iter->release();
3031	while (!fPendingRequests->Empty())      // now let's purge the list
3032	    fPendingRequests->RemoveLast();
3033    }
3034
3035
3036} // TIrLAP::DisconnectComplete
3037
3038
3039//--------------------------------------------------------------------------------
3040//      CancelPutRequest
3041//--------------------------------------------------------------------------------
3042void TIrLAP::CancelPutRequest()
3043{
3044    TIrCancelPutRequest* cancelPutRequest = (TIrCancelPutRequest*)GetCurrentEvent();
3045
3046    // Cancel all pending (or in progress) put requests for the lsapConn which made the request
3047    CancelPendingPutRequests(cancelPutRequest->fLSAPConn, kIrDAErrRequestCanceled);
3048
3049    // Respond to the request, using the request block for the response
3050    cancelPutRequest->fEvent = kIrCancelPutReplyEvent;
3051    cancelPutRequest->fResult = noErr;
3052    cancelPutRequest->fLSAPConn->EnqueueEvent(cancelPutRequest);
3053
3054} // TIrLAP::CancelPutRequest
3055
3056
3057//--------------------------------------------------------------------------------
3058//      CancelPendingPutRequests
3059//--------------------------------------------------------------------------------
3060void TIrLAP::CancelPendingPutRequests(TLSAPConn* lsapConn, IrDAErr returnCode)
3061{
3062    FastInt index;
3063    TIrPutReply* putReply;
3064
3065    // Reply to all in-progress put requests
3066    for (index = 0; index < 8; index++) {
3067	putReply = (TIrPutReply*)fPutRequests[index];
3068	if ((putReply != nil) && ((lsapConn == nil) || (lsapConn == putReply->fLSAPConn))) {
3069	    fPutRequests[index] = nil;
3070	    PutComplete(putReply, returnCode);
3071	}
3072    }
3073
3074    // Reply to all pending put requests (must remove from end, since holes will be created, and its faster)
3075    for (index = fPendingPutRequests->GetArraySize() - 1; index >= 0 ; index--) {
3076	putReply = (TIrPutReply*)fPendingPutRequests->At(index);
3077	if ((putReply != nil) && ((lsapConn == nil) || (lsapConn == putReply->fLSAPConn))) {
3078	    fPendingPutRequests->RemoveAt(index);
3079	    PutComplete(putReply, returnCode);
3080	}
3081    }
3082
3083} // TIrLAP::CancelPendingPutRequests
3084
3085
3086//--------------------------------------------------------------------------------
3087//      PutComplete
3088//--------------------------------------------------------------------------------
3089void TIrLAP::PutComplete(TIrPutReply* putReply, IrDAErr result)
3090{
3091    // Put completes happen in a couple of places, so I consolidated them here
3092
3093    // A special case: the peer device acknowledges the put after it was cancelled.
3094    // In this case the caller (UpdateNrReceived) would pass nil, since CancelPutRequests
3095    // was already called and set the pending put request to nil.  So just ignore it.
3096    if (putReply == nil) {
3097	// Nothing to do, man
3098    }
3099
3100    // If fLSAPConn is non-nil, send back put reply
3101    else if (putReply->fLSAPConn != nil) {
3102	putReply->fEvent = kIrPutDataReplyEvent;
3103	putReply->fResult = result;
3104	putReply->fLSAPConn->EnqueueEvent(putReply);
3105    }
3106    // If fLSAPConn is nil, don't reply - just release the put request block
3107    else {
3108	fIrDA->ReleaseEventBlock(putReply);
3109    }
3110
3111} // TIrLAP::PutComplete
3112
3113
3114//--------------------------------------------------------------------------------
3115//      NotConnectedCompletion
3116//--------------------------------------------------------------------------------
3117void TIrLAP::NotConnectedCompletion()
3118{
3119    // A request has been received while either before getting connected or more
3120    // likely some time after a disconnect has begun.  [Most likely its a put request].
3121    TIrLSAPConnEvent* request = (TIrLSAPConnEvent*)GetCurrentEvent();
3122
3123    // Simple reply to the request with an error.
3124    switch (request->fEvent) {
3125	case kIrPutDataRequestEvent:
3126	    request->fEvent = kIrPutDataReplyEvent;
3127	    break;
3128
3129	default:
3130	    DebugLog("TIrLAP::NotConnectedCompletion: unexpected request");
3131	    break;
3132    }
3133    request->fResult = kIrDAErrNotConnected;
3134    request->fLSAPConn->EnqueueEvent(request);
3135
3136} // TIrLAP::NotConnectedCompletion
3137
3138
3139//--------------------------------------------------------------------------------
3140//      ApplyDefaultConnParms
3141//--------------------------------------------------------------------------------
3142void TIrLAP::ApplyDefaultConnParms()
3143{
3144    // Change baud rate back to negotiation baud rate
3145    GetIrDevice->ChangeSpeed(k9600bps);
3146
3147    // Set lead-in count back to default
3148    fLeadInCount = kIrDefaultLeadinCount;
3149
3150} // TIrLAP::ApplyDefaultConnParms
3151
3152
3153//--------------------------------------------------------------------------------
3154//      StartDataReceive
3155//--------------------------------------------------------------------------------
3156void TIrLAP::StartDataReceive()
3157{
3158    CBufferSegment* inputBuffer;
3159
3160    // fIOBufferItem should be used only for control and when local busy
3161    // is in effect.  else we should have a GetBuffer available for a
3162    // normal data read.  GetBuffers are the only ones valid to be passed
3163    // up the stack (and returned via ReleaseInputBuffer).
3164
3165    if (fInputBuffer == fIOBufferItem)  // if currently using control buffer (or busy)
3166	fInputBuffer = nil;             // reset it to switch to getbuffers
3167
3168    if (fInputBuffer) {                 // if non-nil, then we already have a getbuffer
3169					// and reuse the current input buffer
3170	inputBuffer = fInputBuffer;
3171	XTRACE( kReusingBuffer, 0, fInputBuffer );
3172    }
3173
3174    else {
3175	ULong flags;            // better not have more than 32 buffers
3176	ULong index;
3177
3178	// Set default in case no available buffer was found
3179	inputBuffer = fIOBufferItem;            // use this if "local busy" condition
3180
3181	// Find and use an available buffer
3182	for (index = 0, flags = 1; index < fNumGetBuffers; index++, flags <<= 1) {
3183	    if (fGetBufferAvail & flags) {              // if this buffer free
3184		fGetBufferAvail &= ~flags;              // allocate the buffer
3185		inputBuffer = fGetBuffers[index];
3186		//fNeedNewInputBuffer = false;
3187		XTRACE(kLogStartDataRcv1, 0, inputBuffer);
3188		XTRACE(kLogStartDataRcv2, flags, index);
3189		break;
3190	    }
3191	}
3192    }
3193
3194    if (inputBuffer == fIOBufferItem )      // debugging only
3195	XTRACE( kUsingDefaultBuffer, 0, fIOBufferItem );
3196
3197    require(inputBuffer, Bogus);
3198    StartInput(inputBuffer);
3199
3200Bogus:
3201    return;
3202} // TIrLAP::StartDataReceive
3203
3204//--------------------------------------------------------------------------------
3205//      ReleaseInputBuffer
3206//--------------------------------------------------------------------------------
3207void TIrLAP::ReleaseInputBuffer(CBufferSegment* inputBuffer)
3208{
3209    // This is called when the multiplexor has passed the inputbuffer to a client
3210    // and is returning the buffer to the buffer pool.  The buffer is marked as available.
3211
3212    ULong flags;
3213    ULong index;
3214    Boolean bufferFound = false;
3215
3216    XTRACE(kLogReleaseInputBuffer, 0, inputBuffer);
3217
3218    // Find the buffer
3219    for (index = 0, flags = 1; index < fNumGetBuffers; index++, flags <<= 1) {
3220	if (fGetBuffers[index] == inputBuffer) {
3221	    // Check for releasing a buffer twice
3222	    XASSERT((fGetBufferAvail & flags) == 0);
3223	    fGetBufferAvail |= flags;
3224	    bufferFound = true;
3225	    XTRACE(kLogReleaseInputBuffer2, flags, index);
3226	}
3227    }
3228
3229    //XASSERT(bufferFound);                         // It should be one of the buffers,
3230    require(bufferFound, BufferNotFound);           // but don't croak if its not
3231
3232    // Clear localBusy condition before it gets reported
3233    if (fSetLocalBusyPending) {
3234	XTRACE(kAbortLocalBusyPendingEvent, 0, 0);
3235	XASSERT(!fLocalBusy);
3236	fSetLocalBusyPending = false;
3237    }
3238
3239    // Clear localBusy condition if we were in a local busy condition and just now got out of it
3240    else if (fLocalBusy && !fClrLocalBusyPending) {
3241	XTRACE(kClrLocalBusyPendingEvent, 0, 0);
3242	fLocalBusyClearedEvent->fEvent = kIrLocalBusyClearedEvent;
3243	fLocalBusyClearedEvent->fResult = noErr;
3244	fClrLocalBusyPending = true;
3245	this->EnqueueEvent(fLocalBusyClearedEvent);
3246    }
3247BufferNotFound:
3248    return;
3249
3250} // TIrLAP::ReleaseInputBuffer
3251
3252
3253//--------------------------------------------------------------------------------
3254//      PostponePutRequest
3255//--------------------------------------------------------------------------------
3256void TIrLAP::PostponePutRequest()
3257{
3258    fPendingPutRequests->InsertFirst(GetCurrentEvent());
3259
3260} // TIrLAP::PostponePutRequest
3261
3262
3263//--------------------------------------------------------------------------------
3264//      PrepareFRMRResponse
3265//--------------------------------------------------------------------------------
3266void TIrLAP::PrepareFRMRResponse()
3267{
3268    // Save info necessary when the FRMR can be sent
3269    fFRMRRejCtrlField = fRecdCtrl;
3270    fFRMRMyNrAndNs = (fVr << kIrLAPNrShift) | (fVs << kIrLAPNsShift) | (fRecdCR ? kIrFRMRCrBit : 0);
3271    if (RecdInvalidNr()) {
3272	fFRMRReasonFlags = kIrFRMRFlagInvalidNrCount;
3273    }
3274    else if (RecdInvalidNs()) {
3275	fFRMRReasonFlags = 0;
3276    }
3277    else {
3278	fFRMRReasonFlags = kIrFRMRFlagUndefinedCtrl;
3279    }
3280
3281    // Set flag indicating that frmr is pending
3282    fFRMRPending = true;
3283
3284} // TIrLAP::PrepareFRMRResponse
3285
3286
3287//--------------------------------------------------------------------------------
3288//      OutputXIDCommand
3289//--------------------------------------------------------------------------------
3290void TIrLAP::OutputXIDCommand()
3291{
3292    ULong deviceInfoLength = 0;
3293    TIrDscInfo* myDscInfo;
3294    TXIDPacket* xidCmd = (TXIDPacket*)fIOBufferItem->GetBufferPtr();
3295
3296    XTRACE(kDiscoverXIDCmdEvent, fDiscoverSlot, 0);
3297
3298    // Set cmd output so output complete event knows what to do next
3299    fNextCmdRspToSend = kIrLAPCmdXID;
3300
3301    // Fill out the discover XID frame
3302    xidCmd->fAddress = (kIrLAPBroadcastAddr << 1) | kIrLAPCommandBit;
3303    xidCmd->fCmdRsp = kIrLAPCmdXID | kIrLAPPollBit;
3304    xidCmd->fFormatId = kIrLAPDiscoveryXIDFormat;
3305    xidCmd->fSrcDevAddr = fMyDevAddr;
3306    xidCmd->fDstDevAddr = fConflictDevAddr;
3307    xidCmd->fFlags = fDiscoverFlags;
3308    xidCmd->fSlotNum = fDiscoverSlot;
3309    xidCmd->fVersion = kIrLAPVersionNumber;
3310
3311    // Add the caller supplied discovery info on final.
3312    if (fDiscoverSlot == kIrLAPFinalSlot) {
3313	// Get my discovery info (PDA/"Newton" unless changed by client)
3314#if forMac
3315	myDscInfo = GetDiscovery->GetDiscoveryInfo();
3316#else
3317	myDscInfo = fIrDA->GetMyDscInfo();
3318#endif
3319	deviceInfoLength = myDscInfo->AddDevInfoToBuffer(&xidCmd->fDevInfo[0],
3320	    kMaxUnconnectedPacketSize - kTXIDPacketSize);
3321    }
3322
3323    // Set up the put buffer
3324    fPutBuffer->SetControlBuffer(&xidCmd->fAddress, kTXIDPacketSize + deviceInfoLength, true);
3325
3326    // Output the discover XID frame
3327    check(fLeadInCount == kIrDefaultLeadinCount);       // if not, how'd that happen?
3328    StartOutput(fPutBuffer, kIrDefaultLeadinCount );    // XID should have 10 BOFs per spec
3329
3330//#if forMac                            // Immediately post a read for the response packet.  The driver
3331//  StartInput(&fIOBufferItem);     // will queue it behind the XID write and it be posted to .XIn
3332//#endif                                // when the XID completes.  It takes too long for the stack to
3333				    // process the Output complete and post the response read.
3334} // TIrLAP::OutputXIDCommand
3335
3336
3337//--------------------------------------------------------------------------------
3338//      OutputXIDResponse
3339//--------------------------------------------------------------------------------
3340void TIrLAP::OutputXIDResponse(TXIDPacket& xidCmd)
3341{
3342    ULong deviceInfoLength;
3343    UByte xidFlags = xidCmd.fFlags;
3344    TIrDscInfo* myDscInfo;
3345    TXIDPacket* xidRsp = (TXIDPacket*)fIOBufferItem->GetBufferPtr();
3346
3347    XTRACE(kDiscoverXIDRspEvent, fDiscoverSlot, xidFlags);
3348
3349    // Set cmd output so output complete event knows what to do next
3350    fNextCmdRspToSend = kIrLAPRspXID;
3351
3352    // Give myself a new dev address if conflict resolution situation
3353#if forMac
3354
3355    if( xidFlags & kIrLAPDiscoverFlagsNewAddr )
3356	fReplacementDevAddr = ( UInt32 ) ( random()  % 0xFFFFFFFE + 1 );
3357    else
3358	fReplacementDevAddr = 0;
3359
3360#else
3361    fReplacementDevAddr = xidFlags & kIrLAPDiscoverFlagsNewAddr ? (ULong)rand() % 0xFFFFFFFE + 1 : 0;
3362#endif
3363
3364    // Create a response XID frame
3365    xidRsp->fAddress = kIrLAPBroadcastAddr << 1;
3366    xidRsp->fCmdRsp = kIrLAPRspXID | kIrLAPFinalBit;
3367    xidRsp->fFormatId = kIrLAPDiscoveryXIDFormat;
3368    xidRsp->fSrcDevAddr = fReplacementDevAddr ? fReplacementDevAddr : fMyDevAddr;
3369    xidRsp->fDstDevAddr = xidCmd.fSrcDevAddr;
3370    // Response flags are essentially reflection of the flags received.
3371    // Mask off all but supported flags just in case some junk was received.
3372    xidRsp->fFlags = xidFlags & (kIrLAPDiscoverFlagsNewAddr | kIrLAPDiscoverFlagsSlotMask);
3373    xidRsp->fSlotNum = fDiscoverSlot;
3374    xidRsp->fVersion = kIrLAPVersionNumber;
3375
3376    // Add the caller supplied discovery info.
3377#if forMac
3378	myDscInfo = GetDiscovery->GetDiscoveryInfo();
3379#else
3380	myDscInfo = fIrDA->GetMyDscInfo();
3381#endif
3382    deviceInfoLength = myDscInfo->AddDevInfoToBuffer(&xidRsp->fDevInfo[0],
3383	kMaxUnconnectedPacketSize - kTXIDPacketSize);
3384
3385    // Set up the put buffer
3386    fPutBuffer->SetControlBuffer(&xidRsp->fAddress, kTXIDPacketSize + deviceInfoLength, true);
3387
3388    // Output the discover XID frame
3389    StartOutput(fPutBuffer, /* fLeadInCount */ 10); // CPD-XID should have 10 BOFs per spec
3390
3391} // TIrLAP::OutputXIDResponse
3392
3393
3394//--------------------------------------------------------------------------------
3395//      OutputSNRMCommand
3396//--------------------------------------------------------------------------------
3397void TIrLAP::OutputSNRMCommand()
3398{
3399    ULong qosDataLength;
3400    TSNRMPacket* snrmCmd = (TSNRMPacket*)fIOBufferItem->GetBufferPtr();
3401
3402    // Set cmd output so output complete event knows what to do next
3403    fNextCmdRspToSend = kIrLAPCmdSNRM;
3404
3405    // Fill out the SNRM frame
3406    snrmCmd->fAddress = (kIrLAPBroadcastAddr << 1) | kIrLAPCommandBit;
3407    snrmCmd->fCmdRsp = kIrLAPCmdSNRM | kIrLAPPollBit;
3408    snrmCmd->fSrcDevAddr = fMyDevAddr;
3409    snrmCmd->fDstDevAddr = fPeerDevAddr;
3410    snrmCmd->fConnAddr = fConnAddr << 1;
3411
3412    // Add negotiation info passed down to me
3413    qosDataLength = fMyQOS->AddInfoToBuffer(&snrmCmd->fQOSParmData[0],
3414	kMaxUnconnectedPacketSize - kTSNRMPacketSize);
3415
3416    // Set up the put buffer
3417    fPutBuffer->SetControlBuffer(&snrmCmd->fAddress, kTSNRMPacketSize + qosDataLength, true);
3418
3419    // Output the connect SNRM frame
3420    StartOutput(fPutBuffer, fLeadInCount);
3421
3422} // TIrLAP::OutputSNRMCommand
3423
3424
3425//--------------------------------------------------------------------------------
3426//      OutputUAResponse
3427//--------------------------------------------------------------------------------
3428void TIrLAP::OutputUAResponse()
3429{
3430    ULong qosDataLength;
3431    TUAPacket* uaRsp = (TUAPacket*)fIOBufferItem->GetBufferPtr();
3432
3433#if forMac
3434    if (!fConnected) {              // calling OutputUA more than once, tell discover only once
3435	fConnected = true;                      // jdg flag as connected a little earlier than before
3436	GetDiscovery->GetRemoteDeviceName( fPeerDevAddr, fNickName, sizeof(fNickName) );
3437    }
3438#endif
3439
3440    // Set cmd output so output complete event knows what to do next
3441    fNextCmdRspToSend = kIrLAPRspUA;
3442
3443    // Fill out the UA frame
3444    uaRsp->fAddress = fConnAddr << 1;
3445    uaRsp->fCmdRsp = kIrLAPRspUA | kIrLAPFinalBit;
3446    uaRsp->fSrcDevAddr = fMyDevAddr;
3447    uaRsp->fDstDevAddr = fPeerDevAddr;
3448
3449    // Add negotiation info (passed down to me and negotiated against SNRM QOS parms)
3450    qosDataLength = fMyQOS->AddInfoToBuffer(&uaRsp->fQOSParmData[0],
3451	kMaxUnconnectedPacketSize - kTUAPacketSize);
3452
3453    // Set up the put buffer
3454    fPutBuffer->SetControlBuffer(&uaRsp->fAddress, kTUAPacketSize + qosDataLength, true);
3455
3456    XTRACE(kOutputUACommandEvent, uaRsp->fCmdRsp, uaRsp->fAddress );
3457    XTRACE(kOutputUACommandEvent, qosDataLength >> 16, qosDataLength ); // testing
3458
3459    // Output the connect UA response frame
3460    StartOutput(fPutBuffer, fLeadInCount);
3461
3462} // TIrLAP::OutputUAResponse
3463
3464
3465//--------------------------------------------------------------------------------
3466//      OutputFRMRResponse
3467//--------------------------------------------------------------------------------
3468void TIrLAP::OutputFRMRResponse()
3469{
3470    TFRMRPacket* frmrRsp = (TFRMRPacket*)fIOBufferItem->GetBufferPtr();
3471
3472    // Set cmd output so output complete event knows what to do next
3473    fNextCmdRspToSend = kIrLAPRspFRMR;
3474
3475    // Fill out the FRMR frame
3476    frmrRsp->fAddress = fConnAddr << 1;
3477    frmrRsp->fCmdRsp = kIrLAPRspFRMR | kIrLAPFinalBit;
3478    frmrRsp->fRejCtrlField = fFRMRRejCtrlField;
3479    frmrRsp->fMyNrAndNs = fFRMRMyNrAndNs;
3480    frmrRsp->fReasonFlags = fFRMRReasonFlags;
3481
3482    // Set up the put buffer
3483    fPutBuffer->SetControlBuffer(&frmrRsp->fAddress, kTFRMRPacketSize, true);
3484
3485    // Output the FRMR response frame
3486    StartOutput(fPutBuffer, fLeadInCount);
3487} // TIrLAP::OutputFRMRResponse
3488
3489
3490//--------------------------------------------------------------------------------
3491//      OutputControlFrame
3492//--------------------------------------------------------------------------------
3493void TIrLAP::OutputControlFrame(UByte cmdRsp)
3494{
3495    // This can be used to output simple U frames or S frames (not intended for I frames)
3496    // NOTE: The final/poll bit is always set by this.
3497
3498    TControlPacket* frame = (TControlPacket*)fIOBufferItem->GetBufferPtr();
3499
3500    // Set cmd output so output complete event knows what to do next
3501    fNextCmdRspToSend = cmdRsp;
3502
3503    // Fill out the control frame
3504    frame->fAddress = (fConnAddr << 1) | (fPrimary ? kIrLAPCommandBit : 0);
3505    frame->fCmdRsp = cmdRsp | kIrLAPPollBit;
3506    if ((cmdRsp & kIrLAPUSIMask) != kIrLAPUnnumbered) {
3507	frame->fCmdRsp |= fVr << kIrLAPNrShift;
3508    }
3509
3510    if (cmdRsp == kIrLAPFrameRR) XTRACE(kOutputControlFrameRR, 0, fVr);
3511    else                         XTRACE(kOutputControlFrame, cmdRsp, fVr);
3512
3513    // Set up the put buffer
3514    fPutBuffer->SetControlBuffer(&frame->fAddress, kTControlPacketSize, true);
3515
3516    // Output the frame
3517    StartOutput(fPutBuffer, fLeadInCount);
3518
3519#if forMac
3520    switch( cmdRsp ) {          // Log the packet type sent
3521	case kIrLAPFrameRR:
3522	    GetIrDevice->Stats_RRSent();
3523	    break;
3524
3525	case kIrLAPFrameRNR:
3526	    GetIrDevice->Stats_RNRSent();
3527	    break;
3528
3529	case kIrLAPFrameREJ:
3530	    GetIrDevice->Stats_REJSent();
3531	    break;
3532
3533	case kIrLAPFrameSREJ:
3534	    GetIrDevice->Stats_SREJSent();
3535	    break;
3536    }
3537#endif
3538
3539} // TIrLAP::OutputControlFrame
3540
3541
3542//--------------------------------------------------------------------------------
3543//      OutputDataFrame
3544//--------------------------------------------------------------------------------
3545void TIrLAP::OutputDataFrame(TIrPutRequest* request, Boolean finalOrPollFlag)
3546{
3547    ULong lmPDULength;
3548    UByte finalPollBit = finalOrPollFlag ? kIrLAPFinalBit : 0;  // Note: final/poll bit same bit
3549    TControlPacket* frame = (TControlPacket*)fIOBufferItem->GetBufferPtr();
3550
3551    if (finalPollBit) XTRACE(kOutputDataFrame, fVs, fVr);
3552    else             XTRACE(kOutputDataFrameNotFinal, fVs, fVr);
3553
3554
3555    // Set cmd output so output complete event knows what to do next
3556    fNextCmdRspToSend = kIrLAPFrameINFO;
3557
3558    // Keep track of the send buffer in the resend/ack/reply array
3559    fPutRequests[fVs] = request;
3560
3561    // Update the valid fRecdNr bits
3562    fValidRecdNr |= 1 << fVs;
3563
3564    // Fill out the data frame header
3565    frame->fAddress = (fConnAddr << 1) | (fPrimary ? kIrLAPCommandBit : 0);
3566    frame->fCmdRsp = kIrLAPFrameINFO | finalPollBit | (fVr << kIrLAPNrShift) | (fVs << kIrLAPNsShift);
3567
3568    // Advance the send index
3569    fVs = (fVs + 1) & 0x7;
3570
3571    // Fill in the LM-PDU header (control or data LM-PDU info)
3572    lmPDULength = GetLMP->FillInLMPDUHeader(request, frame->fLMPDUData);
3573
3574    // Set up the put buffer
3575    fPutBuffer->SetControlBuffer(&frame->fAddress, kTControlPacketSize + lmPDULength, true);
3576    fPutBuffer->SetDataBuffer(request->fData, request->fOffset, request->fLength);
3577
3578    // Output the data frame
3579    StartOutput(fPutBuffer, (UInt32)fLeadInCount);
3580
3581#if forMac
3582    GetIrDevice->Stats_IFrameSent();
3583#endif
3584} // TIrLAP::OutputDataFrame
3585
3586
3587//--------------------------------------------------------------------------------
3588//      GotData
3589//--------------------------------------------------------------------------------
3590Boolean TIrLAP::GotData(UByte *data, ULong size)
3591{
3592    ULong   result;
3593    result = fInputBuffer->Getn(data, size);    // try and get size bytes
3594    XTRACE(kLogGotData, size, result);          // log requested/result counts
3595    return (result == size);
3596    //return (ULong)fInputBuffer->Getn(data, size) == size;
3597} // TIrLAP::GotData
3598
3599
3600//--------------------------------------------------------------------------------
3601//      RecdCmd
3602//--------------------------------------------------------------------------------
3603Boolean TIrLAP::RecdCmd(UByte cmdPattern)
3604{
3605    return fRecdCR && (fRecdCmdRsp == cmdPattern);
3606
3607} // TIrLAP::RecdCmd
3608
3609
3610//--------------------------------------------------------------------------------
3611//      RecdPollCmd
3612//--------------------------------------------------------------------------------
3613Boolean TIrLAP::RecdPollCmd(UByte cmdPattern)
3614{
3615    return fRecdPF && RecdCmd(cmdPattern);
3616
3617} // TIrLAP::RecdPollCmd
3618
3619
3620//--------------------------------------------------------------------------------
3621//      RecdRsp
3622//--------------------------------------------------------------------------------
3623Boolean TIrLAP::RecdRsp(UByte rspPattern)
3624{
3625    return !fRecdCR && (fRecdCmdRsp == rspPattern);
3626
3627} // TIrLAP::RecdRsp
3628
3629
3630//--------------------------------------------------------------------------------
3631//      RecdFinalRsp
3632//--------------------------------------------------------------------------------
3633Boolean TIrLAP::RecdFinalRsp(UByte rspPattern)
3634{
3635    return fRecdPF && RecdRsp(rspPattern);
3636
3637} // TIrLAP::RecdFinalRsp
3638
3639
3640//================================= Timer stuff ==================================
3641
3642
3643//--------------------------------------------------------------------------------
3644//      StartTimer
3645//--------------------------------------------------------------------------------
3646void TIrLAP::StartTimer(TTimeout timeDelay, int refCon)
3647{
3648    XTRACE(kLogStartTimer, timeDelay, refCon);
3649
3650    fIrDA->StartTimer(kTimer_LAP, timeDelay, refCon);
3651
3652} // TIrLAP::StartTimer
3653
3654
3655//--------------------------------------------------------------------------------
3656//      StopTimer
3657//--------------------------------------------------------------------------------
3658void TIrLAP::StopTimer()
3659{
3660/*  fMediaBusyTimer.        StopTimer();    // Stop them all to make sure.  This is fine
3661    fDiscoverSlotTime.      StopTimer();    // since the stack expects only one timer
3662    fFinalTimer.            StopTimer();    // to be active at any given time, which is
3663    fBackOffTimer.          StopTimer();    // not always the case.  Real work is done only
3664    fWatchDogTimer.         StopTimer();    // if the timer is active.
3665    fDiscoverMaxSlotTimer.  StopTimer();
3666    fMinTurnAroundTimer.    StopTimer();
3667*/
3668    XTRACE(kLogStopTimer, 0, 0);
3669    fIrDA->StopTimer(kTimer_LAP);
3670
3671} // TIrLAP::StopTimer
3672
3673
3674//--------------------------------------------------------------------------------
3675//      TimerComplete
3676//--------------------------------------------------------------------------------
3677void TIrLAP::TimerComplete(ULong refCon)
3678{
3679    XTRACE(kLogTimerComplete, 0, refCon);
3680    check((refCon >= kIrFirstIrLAPTimerEvent) && (refCon <= kIrLastIrLAPTimerEvent));
3681    NextState(refCon);
3682} // TIrLAP::TimerComplete
3683
3684
3685//============================= Input/Output stuff ===============================
3686
3687
3688//--------------------------------------------------------------------------------
3689//      StartOutput
3690//--------------------------------------------------------------------------------
3691void TIrLAP::StartOutput(TIrLAPPutBuffer* outputBuffer, ULong leadInCount)
3692{
3693    fOutputInProgress = true;
3694    fLastCmdRsp = fNextCmdRspToSend;    // Stash the current packet type so it is valid
3695					// between sends.
3696#if forMac
3697    GetIrDevice->StartTransmit(outputBuffer, leadInCount);
3698#else
3699    fIrDA->StartTransmit(outputBuffer, leadInCount);
3700#endif
3701
3702} // TIrLAP::StartOutput
3703
3704
3705//--------------------------------------------------------------------------------
3706//      StopOutput
3707//--------------------------------------------------------------------------------
3708void TIrLAP::StopOutput()
3709{
3710    fOutputInProgress = false;
3711#if !forMac                         // Packet was completely written during StartOutput
3712    fIrDA->StopTransmit();
3713#endif
3714} // TIrLAP::StopOutput
3715
3716
3717//--------------------------------------------------------------------------------
3718//      StartInput
3719//--------------------------------------------------------------------------------
3720void TIrLAP::StartInput(CBufferSegment* inputBuffer)
3721{
3722    XTRACE(kLogStartInput, 0, inputBuffer);
3723    XTRACE(kLogStartInput2, 0, fInputBuffer);
3724
3725    require(inputBuffer, Bogus);        // shouldn't ever happen
3726    //Boolean localBusy = fLocalBusy || fSetLocalBusyPending;
3727
3728    // jdg hack #832
3729    // if fInputBuffer is non-nil and not fIOBufferItem and not the same as what
3730    // was used last time, then it's one of the get buffers and we need to "release"
3731    // it so it can be safely cleaned up by FreeGetBuffers.  Could skip this except for
3732    // the sanity checks in FreeGetBuffers.
3733    if (fInputBuffer && fInputBuffer != fIOBufferItem && inputBuffer != fInputBuffer) {
3734	XTRACE(kLogStartInput3, 0xfeed, 0xbeef);
3735	require(inputBuffer == fIOBufferItem, SanityLacks);
3736	//DebugLog("working to avoid buffer leak in StartInput, release on 0x%lx\n", (UInt32) fInputBuffer);
3737	ReleaseInputBuffer(fInputBuffer);   // could queue clear local busy event... should be ok
3738    }
3739SanityLacks:
3740
3741    fInputInProgress = true;
3742    fInputBuffer = inputBuffer;         // remember input buffer
3743    inputBuffer->Reset();               // Start the ball rolling
3744
3745    // Used to tell the i/o guy to just return the afield and cfield if we've run out
3746    // of buffers, but now that fIOBufferItem is a full-sized CBufferSegment we
3747    // go ahead and always accept a full-size packet anyway.  Shouldn't ever
3748    // get back more than the header anyway.
3749    GetIrDevice->StartReceive(inputBuffer);
3750Bogus:
3751    return;
3752} // TIrLAP::StartInput
3753
3754
3755//--------------------------------------------------------------------------------
3756//      StopInput
3757//--------------------------------------------------------------------------------
3758void TIrLAP::StopInput()
3759{
3760    fInputInProgress = false;
3761    GetIrDevice->StopReceive();
3762
3763} // TIrLAP::StopInput
3764
3765/*
3766//--------------------------------------------------------------------------------
3767//      InputHappening
3768//--------------------------------------------------------------------------------
3769Boolean TIrLAP::InputHappening()
3770{
3771    // Are we receiving data even though receipt may not be complete?
3772    return fIrSIR->Stats_ReceivingData();
3773} // TIrLAP::InputHappening
3774*/
3775
3776//--------------------------------------------------------------------------------
3777//      OutputComplete
3778//--------------------------------------------------------------------------------
3779void TIrLAP::OutputComplete()
3780{
3781    fOutputInProgress = false;
3782#ifdef IRDA_TEST_FRAME_SUPPORTED
3783    if (fHandlingTestFrame) {
3784	TestFrameComplete();
3785    }
3786    else
3787#endif
3788    {
3789	XTRACE( kPacketOutput, 0, 0 );
3790	NextState(kIrOutputCompleteEvent);
3791    }
3792} // TIrLAP::OutputComplete
3793
3794//--------------------------------------------------------------------------------
3795//      ChangeSpeedComplete
3796//--------------------------------------------------------------------------------
3797void TIrLAP::ChangeSpeedComplete()
3798{
3799    // only do the ChangeSpeedComplete event in the two states that handle it, otherwise
3800    // this routine is a nop (i.e. called from one of the paths to DisconnectComplete)
3801    if (fState == kIrLAPConnectState || fState == kIrLAPListenState)
3802	NextState(kIrChangeSpeedCompleteEvent);
3803    else {
3804	XTRACE(kLogChangeSpeedCompleteIgnored, 0, 0);
3805    }
3806} // TIrLAP::ChangeSpeedComplete
3807
3808
3809
3810//--------------------------------------------------------------------------------
3811//      InputAborted -- input aborted, pretend we timed out (but faster)
3812//          returns true if the 'abort' worked (else the caller shoujld
3813//          hang another read out)
3814//--------------------------------------------------------------------------------
3815Boolean TIrLAP::InputAborted()
3816{
3817    XTRACE(kInputAborted, 0, 0);
3818    if (fState == kIrLAPPriReceiveState &&      // sanity
3819	fMyWindowSize == 1) {           // if aborted read and my windowsize == 1
3820	StartTimer(fMinTurnAroundTimeout, kIrFinalTimerExpiredEvent);
3821	return true;
3822    }
3823    return false;
3824}
3825
3826//--------------------------------------------------------------------------------
3827//      InputComplete
3828//--------------------------------------------------------------------------------
3829void TIrLAP::InputComplete(UByte aField, UByte cField)
3830{
3831    // Note: The aField and cField were extracted by the low level input routine (vs being
3832    // added to the input buffer) because the IrLAP spec specifies that the negotiated data
3833    // size is the maximum bytes in the I field of a frame, which does not leave room for the
3834    // aField or the cField.
3835
3836    //fInputInProgress = false;     // jdg - use as a read complete "valid" flag below
3837    // Extract the c/r bit from aField and normalize the address
3838    fRecdCR = aField & kIrLAPCommandBit;
3839    fRecdAddr = aField >> 1;
3840
3841    // Extract the PF bit from cField
3842    fRecdPF = cField & kIrLAPPFMask;
3843
3844    UByte nrMask = 0;
3845    UByte nsMask = 0;
3846    fNrNsFlags = 0;
3847
3848    // Only set (change from its previous value) fRecdNr if S or I frame
3849    if ((cField & kIrLAPUSIMask) != kIrLAPUnnumbered) {
3850	nrMask = kIrLAPNrMask;
3851	fRecdNr = (cField & nrMask) >> kIrLAPNrShift;
3852	if (fRecdNr != fVs) {
3853	    fNrNsFlags |= kIrLAPUnexpectedNr;
3854	    XTRACE(kUnexpectedNr, fRecdNr, fVs);                // jdg
3855
3856	    if ((fValidRecdNr & (1 << fRecdNr)) == 0) {
3857		fNrNsFlags |= kIrLAPInvalidNr;
3858		XTRACE(kInvalidNr, fValidRecdNr, fRecdNr);      // jdg
3859	    }
3860	}
3861    }
3862    // Only set (change from its previous value) fRecdNs if I frame
3863    if ((cField & kIrLAPIMask) == kIrLAPInformation) {
3864	nsMask = kIrLAPNsMask;
3865	fRecdNs = (cField & nsMask) >> kIrLAPNsShift;
3866	if (fRecdNs != fVr) {
3867	    fNrNsFlags |= kIrLAPUnexpectedNs;
3868	    XTRACE(kUnexpectedNs, fRecdNs, fVr);            // jdg
3869
3870	    if ((fValidRecdNs & (1 << fRecdNs)) == 0) {
3871		fNrNsFlags |= kIrLAPInvalidNs;
3872		XTRACE(kInvalidNs, fValidRecdNs, fRecdNs);      // jdg
3873	    }
3874	}
3875    }
3876    // Mask off P/F, Nr and Ns from cField to get received command
3877    fRecdCmdRsp = cField & ~(kIrLAPPFMask | nrMask | nsMask);
3878
3879    // jdg ... now that that's set, let's do some debugging
3880    if (RecdSFrame()) {             // supervisor, only Nr valid
3881	if (RecdPollOrFinal()) {
3882	    if (fRecdCmdRsp == kIrLAPFrameRR) XTRACE(kInputControlFrameRR, 0, fRecdNr);
3883	    else XTRACE(kInputControlFrame, fRecdCmdRsp, fRecdNr);
3884	}
3885	else {
3886	    XTRACE(kInputControlFrameNotFinal, cField, fRecdNr);        // possible??
3887	}
3888    }
3889    else if (RecdIFrame()) {            // data, both Ns and Nr valid
3890#if forMac
3891	GetIrDevice->Stats_IFrameRec();
3892#endif
3893	if (RecdPollOrFinal()) XTRACE(kInputDataFrame, fRecdNs, fRecdNr);
3894	else {
3895			       XTRACE(kInputDataFrameNotFinal, fRecdNs, fRecdNr);
3896	}
3897    }
3898    else if( RecdUFrame() ) {
3899	GetIrDevice->Stats_UFrameRec();
3900    }
3901    /// end jdg add
3902
3903    // Save the control field as is for FRMR error reporting
3904    fRecdCtrl = cField;
3905
3906    // Only accept the input if broadcast or for me
3907    // Should have been verified by the input routine
3908    XASSERT ((fRecdAddr == kIrLAPBroadcastAddr) || (fRecdAddr == fConnAddr));
3909
3910#ifdef IRDA_TEST_FRAME_SUPPORTED
3911    if (fRecdCmdRsp == kIrLAPCmdTEST) {
3912	// Handle test frame as a special case (man oh man, I hate special cases)
3913	HandleTestFrame();
3914    }
3915    else
3916#endif
3917    if (fInputInProgress) {                 // Only if we're expecting a read complete ...
3918	XTRACE( kValidPacketReceived, fState, 0 );
3919	fInputInProgress = false;           // now we don't have a read pending anymore
3920	NextState(kIrInputCompleteEvent);
3921    }
3922    else {
3923	// on my iMac, with a USB IrDA Pod, I get this every time the disk spins
3924	// back *up*.  The deferred tasks are held for maybe 3 seconds, more than
3925	// long enough to fire the fTimer -- while a completed read is in the "queue"
3926	// waiting for us to handle.  Could fix this at the IrDA USB layer, but the
3927	// general solution is to not accept packets here unless a read is still pending.
3928	XTRACE(kLogPacketDropped, 0, 0);
3929	//DebugLog("irlap ignoring packet;g");
3930    }
3931} // TIrLAP::InputComplete
3932
3933
3934#ifdef IRDA_TEST_FRAME_SUPPORTED
3935//--------------------------------------------------------------------------------
3936//      HandleTestFrame
3937//--------------------------------------------------------------------------------
3938void TIrLAP::HandleTestFrame()
3939{
3940    XTRACE(kTestFrameReceivedEvent, fRecdAddr, 0);
3941
3942    // If the frame was either sent to my connection or broadcast to me or anyone then send a response
3943    ULong testFrameLength = fInputBuffer->GetSize();
3944    ULong* testFrame = (ULong*)fInputBuffer->GetBufferPtr();
3945    if ((fRecdAddr == fConnAddr) ||
3946	((testFrameLength >= 8) && ((testFrame[1] == fMyDevAddr) || (testFrame[1] == kIrLAPSniffeeDevAddr) || (testFrame[1] == kIrLAPBroadcastDevAddr)))) {
3947
3948	// By typical standards this appears to be a test frame for me, but still need
3949	// to check for special considerations when its for Sniffee's and I'm listening -
3950	// In that case do not respond, as Sniffers are only interested in non-listeners.
3951	if ((testFrame[1] == kIrLAPSniffeeDevAddr) &&
3952	    (fCurrentRequest != nil) && (fCurrentRequest->fEvent == kIrListenRequestEvent)) {
3953	    TestFrameComplete();
3954	}
3955
3956	// It's a test frame for me or broadcast to anyone and not a sniff special -
3957	else {
3958	    fHandlingTestFrame = true;
3959
3960	    // Build the header
3961	    fTestHeader.fAddress = (fRecdAddr << 1) | (fPrimary ? kIrLAPCommandBit : 0);
3962	    fTestHeader.fCmdRsp = kIrLAPRspTEST | kIrLAPFinalBit;
3963
3964	    // Swap the source and destination addresses if broadcast
3965	    if (fRecdAddr == kIrLAPBroadcastAddr) {
3966		// Source becomes the destination
3967		testFrame[1] = testFrame[0];
3968
3969		// And I'm now the source
3970		testFrame[0] = fMyDevAddr;
3971	    }
3972
3973	    // Set up the put buffer
3974	    fPutBuffer->SetControlBuffer(&fTestHeader.fAddress, kTTestHdrPacketSize, true);
3975	    fPutBuffer->SetDataBuffer(fInputBuffer, 0, testFrameLength);
3976
3977	    // Output the data frame
3978	    StartOutput(fPutBuffer, fLeadInCount);
3979	}
3980    }
3981
3982    // Test frame wasn't for me, so continue inputting in the simplest/least code way
3983    else {
3984	TestFrameComplete();
3985    }
3986
3987} // TIrLAP::HandleTestFrame
3988#endif
3989
3990
3991#ifdef IRDA_TEST_FRAME_SUPPORTED
3992//--------------------------------------------------------------------------------
3993//      TestFrameComplete
3994//--------------------------------------------------------------------------------
3995void TIrLAP::TestFrameComplete()
3996{
3997    XTRACE(kTestFrameOutputDoneEvent, 0, 0);
3998
3999    // Output of the test frame response has completed.
4000    fHandlingTestFrame = false;
4001
4002    // Restart whatever input was pending and continue on (as you were private!).
4003    StartInput(fInputBuffer);
4004
4005} // TIrLAP::TestFrameComplete
4006#endif
4007
4008//
4009// JDG hacking.  Currently used in HandleDisconnectedStateEvent to reject
4010// pending requests rather than croak.  Needs some cleanup.
4011//
4012void TIrLAP::RejectRequest(TIrEvent *request, IrDAErr err)
4013{
4014    XTRACE(kRejectRequest, request->fEvent, err);
4015    request->fEvent = (UByte)RequestIdToReplyId(request->fEvent);
4016    request->fResult = err;
4017    GetLMP->EnqueueEvent(request);
4018}
4019
4020#if forMac
4021//--------------------------------------------------------------------------------
4022//      LAPTimerNotifier: Completion proc for both timers
4023//--------------------------------------------------------------------------------
4024void LAPTimerNotifier( UInt32 refCon, UInt32 sig )
4025{
4026    check( refCon );
4027    TIrLAP *    obj = ( TIrLAP * )refCon;
4028    obj->TimerComplete( sig );
4029}
4030
4031//=============================== TIrLAPPutBuffer ================================
4032
4033#endif
4034
4035#undef super
4036#define super OSObject
4037    OSDefineMetaClassAndStructors(TIrLAPPutBuffer, OSObject);
4038
4039//--------------------------------------------------------------------------------
4040//      TIrLAPPutBuffer
4041//--------------------------------------------------------------------------------
4042/*static*/
4043TIrLAPPutBuffer *
4044TIrLAPPutBuffer::tIrLAPPutBuffer()
4045{
4046    TIrLAPPutBuffer *obj = new TIrLAPPutBuffer;
4047    if (obj && !obj->init()) {
4048	obj->release();
4049	obj = nil;
4050    }
4051    return obj;
4052}
4053
4054
4055//--------------------------------------------------------------------------------
4056//      Init
4057//--------------------------------------------------------------------------------
4058bool TIrLAPPutBuffer::init()
4059{
4060    if (!super::init()) return false;
4061
4062    fCtrlBuf = nil;
4063    fCtrlBufLength = 0;
4064    fCtrlBufPos = 0;
4065
4066    fDataBuf = nil;
4067    fDataBufOffset = 0;
4068    fDataBufLength = 0;
4069    fDataBufPos = 0;
4070
4071    return true;
4072
4073} // TIrLAPPutBuffer::init
4074
4075//--------------------------------------------------------------------------------
4076//      Free
4077//--------------------------------------------------------------------------------
4078void TIrLAPPutBuffer::free(void)
4079{
4080    super::free();
4081}
4082
4083//--------------------------------------------------------------------------------
4084//      SetControlBuffer
4085//--------------------------------------------------------------------------------
4086void TIrLAPPutBuffer::SetControlBuffer(UByte* buffer, ULong length, Boolean initFirst)
4087{
4088    if (initFirst) {
4089	init();
4090    }
4091
4092    fCtrlBuf = buffer;
4093    fCtrlBufLength = length;
4094    fCtrlBufPos = 0;
4095
4096} // TIrLAPPutBuffer::SetControlBuffer
4097
4098
4099//--------------------------------------------------------------------------------
4100//      SetDataBuffer
4101//--------------------------------------------------------------------------------
4102void TIrLAPPutBuffer::SetDataBuffer(CBuffer* buffer, ULong offset, ULong length)
4103{
4104    fDataBuf = buffer;
4105    fDataBufOffset = offset;
4106    fDataBufLength = length;
4107    fDataBufPos = 0;
4108
4109} // TIrLAPPutBuffer::SetDataBuffer
4110
4111
4112//--------------------------------------------------------------------------------
4113//      Get
4114//--------------------------------------------------------------------------------
4115UByte TIrLAPPutBuffer::Get(void)
4116{
4117    UByte nextChar;
4118
4119    if (fCtrlBufPos < fCtrlBufLength) {
4120	XASSERT(fCtrlBuf);
4121	nextChar = fCtrlBuf[fCtrlBufPos++];
4122    }
4123    else if (fDataBufPos < fDataBufLength) {
4124	nextChar = fDataBuf->Get();
4125	fDataBufPos++;
4126    }
4127    else {
4128	DebugLog("TIrLAPPutBuffer::Get: getting past end of buffer(s)");
4129	nextChar = 0xFF;
4130    }
4131
4132    return nextChar;
4133
4134} // TIrLAPPutBuffer::Get
4135
4136
4137//--------------------------------------------------------------------------------
4138//      Seek
4139//--------------------------------------------------------------------------------
4140void TIrLAPPutBuffer::Seek(Long off, int dir)
4141{
4142#pragma unused(off)
4143
4144    // Low-rent version only supports whats needed
4145    XASSERT(((dir == kPosBeg) && (off == 0)) || ((dir == kPosCur) && (off == -1)));
4146
4147    // If direction is kPosBeg, then this is a seek to 0
4148    if (dir == kPosBeg) {
4149	fCtrlBufPos = 0;
4150	if (fDataBuf) {
4151	    fDataBuf->Seek(fDataBufOffset, kPosBeg);
4152	    fDataBufPos = 0;
4153	}
4154    }
4155
4156    // Otherwise the only other supported option is to seek back to the previous character
4157    else {
4158	if (fDataBufPos) {
4159	    // If fDataBufPos > 0 then must be getting chars from there, back up one
4160	    XASSERT(fDataBuf);
4161	    fDataBuf->Seek(-1, kPosCur);
4162	    fDataBufPos--;
4163	}
4164	else if (fCtrlBufPos) {
4165	    fCtrlBufPos--;
4166	}
4167    }
4168
4169} // TIrLAPPutBuffer::Seek
4170
4171
4172//--------------------------------------------------------------------------------
4173//      AtEOF
4174//--------------------------------------------------------------------------------
4175Boolean TIrLAPPutBuffer::AtEOF(void) const
4176{
4177    return (fCtrlBufPos == fCtrlBufLength) && (fDataBufPos == fDataBufLength);
4178
4179} // TIrLAPPutBuffer::AtEOF
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194