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