Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1102 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. conn.c
  5. Abstract:
  6. Boot loader TFTP connection handling routines.
  7. Author:
  8. Chuck Lenzmeier (chuckl) December 27, 1996
  9. based on code by Mike Massa (mikemas) Feb 21, 1992
  10. based on SpiderTCP code
  11. Revision History:
  12. Notes:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. ULONG
  17. ConnItoa (
  18. IN ULONG Value,
  19. OUT PUCHAR Buffer
  20. );
  21. #if defined(REMOTE_BOOT_SECURITY)
  22. ULONG
  23. ConnSigntoa (
  24. IN PUCHAR Sign,
  25. IN ULONG SignLength,
  26. OUT PUCHAR Buffer
  27. );
  28. ULONG
  29. ConnAtoSign (
  30. IN PUCHAR Buffer,
  31. IN ULONG SignLength,
  32. OUT PUCHAR Sign
  33. );
  34. #endif // defined(REMOTE_BOOT_SECURITY)
  35. ULONG
  36. ConnSafeAtol (
  37. IN PUCHAR Buffer,
  38. IN PUCHAR BufferEnd
  39. );
  40. BOOLEAN
  41. ConnSafeStrequal (
  42. IN PUCHAR Buffer,
  43. IN PUCHAR BufferEnd,
  44. IN PUCHAR CompareString
  45. );
  46. ULONG
  47. ConnSafeStrsize (
  48. IN PUCHAR Buffer,
  49. IN PUCHAR BufferEnd
  50. );
  51. ULONG
  52. ConnStrsize (
  53. IN PUCHAR Buffer
  54. );
  55. NTSTATUS
  56. ConnInitialize (
  57. IN OUT PCONNECTION *Connection,
  58. IN USHORT Operation,
  59. IN ULONG RemoteHost,
  60. IN USHORT RemotePort,
  61. IN PUCHAR Filename,
  62. IN ULONG BlockSize,
  63. #if defined(REMOTE_BOOT_SECURITY)
  64. IN OUT PULONG SecurityHandle,
  65. #endif // defined(REMOTE_BOOT_SECURITY)
  66. IN OUT PULONG FileSize
  67. )
  68. //
  69. // Open up the connection, make a request packet, and send the
  70. // packet out on it. Allocate space for the connection control
  71. // block and fill it in. Allocate another packet for data and,
  72. // on writes, another to hold received packets. Don't wait
  73. // for connection ack; it will be waited for in cn_rcv or cn_wrt.
  74. // Return pointer to the connection control block, or NULL on error.
  75. //
  76. //
  77. {
  78. NTSTATUS status;
  79. PCONNECTION connection;
  80. PTFTP_PACKET packet;
  81. ULONG length;
  82. ULONG stringSize;
  83. PUCHAR options;
  84. PUCHAR end;
  85. BOOLEAN blksizeAcked;
  86. BOOLEAN tsizeAcked;
  87. #if defined(REMOTE_BOOT_SECURITY)
  88. BOOLEAN securityAcked;
  89. PUCHAR sign;
  90. ULONG signLength;
  91. #endif // defined(REMOTE_BOOT_SECURITY)
  92. DPRINT( TRACE, ("ConnInitialize\n") );
  93. #ifdef EFI
  94. //
  95. // There's nothing to do here for an EFI environment.
  96. //
  97. return STATUS_SUCCESS;
  98. #endif
  99. connection = &NetTftpConnection;
  100. *Connection = connection;
  101. RtlZeroMemory( connection, sizeof(CONNECTION) );
  102. connection->Synced = FALSE; // connection not synchronized yet
  103. connection->Operation = Operation;
  104. connection->RemoteHost = RemoteHost;
  105. connection->LocalPort = UdpAssignUnicastPort();
  106. connection->RemotePort = RemotePort;
  107. connection->Timeout = INITIAL_TIMEOUT;
  108. connection->Retransmissions = 0;
  109. connection->LastSentPacket = NetTftpPacket[0];
  110. connection->CurrentPacket = NetTftpPacket[1];
  111. if ( Operation == TFTP_RRQ ) {
  112. connection->LastReceivedPacket = connection->CurrentPacket;
  113. } else {
  114. connection->LastReceivedPacket = NetTftpPacket[2];
  115. }
  116. packet = connection->LastSentPacket;
  117. packet->Opcode = Operation;
  118. options = (PUCHAR)&packet->BlockNumber; // start of file name
  119. strcpy( options, Filename );
  120. //DPRINT( LOUD, ("ConnInitialize: opening %s\n", options) );
  121. length = ConnStrsize( options );
  122. options += length;
  123. strcpy( options, "octet" );
  124. length += sizeof("octet");
  125. options += sizeof("octet");
  126. length += sizeof(packet->Opcode);
  127. if ( BlockSize == 0 ) {
  128. BlockSize = DEFAULT_BLOCK_SIZE;
  129. }
  130. strcpy( options, "blksize" );
  131. length += sizeof("blksize");
  132. options += sizeof("blksize");
  133. stringSize = ConnItoa( BlockSize, options );
  134. DPRINT( REAL_LOUD, ("ConnInitialize: requesting block size = %s\n", options) );
  135. length += stringSize;
  136. options += stringSize;
  137. strcpy( options, "tsize" );
  138. length += sizeof("tsize");
  139. options += sizeof("tsize");
  140. stringSize = ConnItoa( (Operation == TFTP_RRQ) ? 0 : *FileSize, options );
  141. DPRINT( REAL_LOUD, ("ConnInitialize: requesting transfer size = %s\n", options) );
  142. length += stringSize;
  143. options += stringSize;
  144. #if defined(REMOTE_BOOT_SECURITY)
  145. if (*SecurityHandle) {
  146. strcpy( options, "security" );
  147. length += sizeof("security");
  148. options += sizeof("security");
  149. stringSize = ConnItoa( *SecurityHandle, options );
  150. DPRINT( REAL_LOUD, ("ConnInitialize: requesting security handle = %s\n", options) );
  151. length += stringSize;
  152. options += stringSize;
  153. //
  154. // Sign the name and send that, to make sure it is not changed.
  155. //
  156. if (TftpSignString(Filename, &sign, &signLength) != STATUS_SUCCESS) {
  157. return STATUS_UNEXPECTED_NETWORK_ERROR;
  158. }
  159. strcpy(options, "sign");
  160. length += sizeof("sign");
  161. options += sizeof("sign");
  162. stringSize = ConnSigntoa( sign, signLength, options );
  163. DPRINT( REAL_LOUD, ("ConnInitialize: using sign = %s\n", options) );
  164. length += stringSize;
  165. options += stringSize;
  166. }
  167. #endif // defined(REMOTE_BOOT_SECURITY)
  168. ConnSendPacket( connection, packet, length );
  169. connection->BlockNumber = 0;
  170. connection->BlockSize = BlockSize;
  171. status = ConnWait( connection, TFTP_OACK, &packet );
  172. if ( NT_SUCCESS(status) ) {
  173. options = (PUCHAR)&packet->BlockNumber;
  174. end = (PUCHAR)packet + connection->LastReceivedLength;
  175. blksizeAcked = FALSE;
  176. tsizeAcked = FALSE;
  177. #if defined(REMOTE_BOOT_SECURITY)
  178. securityAcked = FALSE;
  179. #endif // defined(REMOTE_BOOT_SECURITY)
  180. while ( (options < end) && (!blksizeAcked || !tsizeAcked
  181. #if defined(REMOTE_BOOT_SECURITY)
  182. || !securityAcked
  183. #endif // defined(REMOTE_BOOT_SECURITY)
  184. ) ) {
  185. if ( ConnSafeStrequal(options, end, "blksize") ) {
  186. options += sizeof("blksize");
  187. DPRINT( REAL_LOUD, ("ConnInitialize: received block size = %s\n", options) );
  188. BlockSize = ConnSafeAtol( options, end );
  189. if ( (BlockSize < 8) || (BlockSize > connection->BlockSize) ) {
  190. goto bad_options;
  191. }
  192. options += ConnStrsize(options);
  193. connection->BlockSize = BlockSize;
  194. DPRINT( REAL_LOUD, ("ConnInitialize: block size for transfer = %d\n", BlockSize) );
  195. blksizeAcked = TRUE;
  196. } else if ( ConnSafeStrequal(options, end, "tsize") ) {
  197. options += sizeof("tsize");
  198. DPRINT( REAL_LOUD, ("ConnInitialize: received transfer size = %s\n", options) );
  199. BlockSize = ConnSafeAtol( options, end ); // use this as a temp variable
  200. if ( BlockSize == (ULONG)-1 ) {
  201. goto bad_options;
  202. }
  203. options += ConnStrsize(options);
  204. if ( Operation == TFTP_RRQ ) {
  205. *FileSize = BlockSize;
  206. }
  207. tsizeAcked = TRUE;
  208. #if defined(REMOTE_BOOT_SECURITY)
  209. } else if ( ConnSafeStrequal(options, end, "security") ) {
  210. options += sizeof("security");
  211. DPRINT( REAL_LOUD, ("ConnInitialize: received security handle = %s\n", options) );
  212. BlockSize = ConnSafeAtol( options, end ); // use this as a temp variable
  213. if ( BlockSize == (ULONG)-1 ) {
  214. goto bad_options;
  215. }
  216. options += ConnStrsize(options);
  217. if ( BlockSize == *SecurityHandle ) {
  218. securityAcked = TRUE;
  219. }
  220. #endif // defined(REMOTE_BOOT_SECURITY)
  221. } else {
  222. DPRINT( ERROR, ("ConnInitialize: skipping unrecognized option %s\n", options) );
  223. options += ConnSafeStrsize( options, end );
  224. options += ConnSafeStrsize( options, end );
  225. }
  226. }
  227. if ( !blksizeAcked || !tsizeAcked ) {
  228. goto bad_options;
  229. }
  230. #if defined(REMOTE_BOOT_SECURITY)
  231. if ((!securityAcked) && (*SecurityHandle != 0)) {
  232. goto bad_options;
  233. }
  234. #endif // defined(REMOTE_BOOT_SECURITY)
  235. if ( Operation == TFTP_RRQ ) {
  236. DPRINT( REAL_LOUD, ("ConnInitialize: ACKing OACK\n") );
  237. ConnAck( connection );
  238. }
  239. }
  240. return status;
  241. bad_options:
  242. DPRINT( ERROR, ("ConnInitialize: bad options in OACK\n") );
  243. ConnError(
  244. connection,
  245. connection->RemoteHost,
  246. connection->RemotePort,
  247. TFTP_ERROR_OPTION_NEGOT_FAILED,
  248. "Bad TFTP options"
  249. );
  250. return STATUS_UNSUCCESSFUL;
  251. } // ConnInitialize
  252. NTSTATUS
  253. ConnReceive (
  254. IN PCONNECTION Connection,
  255. OUT PTFTP_PACKET *Packet
  256. )
  257. //
  258. // Receive a tftp packet into the packet buffer pointed to by Connection->CurrentPacket.
  259. // The packet to be received must be a packet of block number Connection->BlockNumber.
  260. // Returns a pointer to the tftp part of received packet. Also performs
  261. // ack sending and retransmission.
  262. //
  263. {
  264. NTSTATUS status;
  265. #ifdef EFI
  266. //
  267. // There's nothing to do here for an EFI environment.
  268. //
  269. ASSERT( FALSE );
  270. return STATUS_SUCCESS;
  271. #endif
  272. status = ConnWait( Connection, TFTP_DATA, Packet );
  273. if ( NT_SUCCESS(status) ) {
  274. Connection->CurrentPacket = Connection->LastReceivedPacket;
  275. Connection->CurrentLength = Connection->LastReceivedLength;
  276. ConnAck( Connection );
  277. }
  278. return status;
  279. } // ConnReceive
  280. NTSTATUS
  281. ConnSend (
  282. IN PCONNECTION Connection,
  283. IN ULONG Length
  284. )
  285. //
  286. // Write the data packet contained in Connection->CurrentPacket, with data length len,
  287. // to the net. Wait first for an ack for the previous packet to arrive,
  288. // retransmitting it as needed. Then fill in the net headers, etc. and
  289. // send the packet out. Return TRUE if the packet is sent successfully,
  290. // or FALSE if a timeout or error occurs.
  291. //
  292. {
  293. NTSTATUS status;
  294. PTFTP_PACKET packet;
  295. PVOID temp;
  296. USHORT blockNumber;
  297. #ifdef EFI
  298. //
  299. // There's nothing to do here for an EFI environment.
  300. //
  301. ASSERT( FALSE );
  302. return STATUS_SUCCESS;
  303. #endif
  304. packet = Connection->CurrentPacket;
  305. packet->Opcode = TFTP_DATA;
  306. blockNumber = Connection->BlockNumber + 1;
  307. #ifdef WRAP_TO_1
  308. if ( blockNumber == 0 ) {
  309. blockNumber = 1;
  310. }
  311. #endif
  312. packet->BlockNumber = SWAP_WORD( blockNumber );
  313. Length += sizeof(packet->Opcode) + sizeof(packet->BlockNumber);
  314. if ( Connection->BlockNumber != 0 ) {
  315. status = ConnWait( Connection, TFTP_DACK, NULL );
  316. if ( !NT_SUCCESS(status) ) {
  317. return status;
  318. }
  319. }
  320. Connection->BlockNumber = blockNumber; // next expected block number
  321. Connection->Retransmissions = 0;
  322. temp = Connection->LastSentPacket; // next write packet buffer
  323. ConnSendPacket( Connection, Connection->CurrentPacket, Length ); // sets up LastSent...
  324. Connection->CurrentPacket = temp; // for next ConnPrepareSend
  325. return STATUS_SUCCESS;
  326. } // ConnSend
  327. NTSTATUS
  328. ConnWait (
  329. IN PCONNECTION Connection,
  330. IN USHORT Opcode,
  331. OUT PTFTP_PACKET *Packet OPTIONAL
  332. )
  333. //
  334. // Wait for a valid tftp packet of the specified type to arrive on the
  335. // specified tftp connection, retransmitting the previous packet as needed up
  336. // to the timeout period. When a packet comes in, check it out.
  337. // Return a pointer to the received packet or NULL if error or timeout.
  338. //
  339. {
  340. ULONG now;
  341. ULONG timeout;
  342. ULONG remoteHost;
  343. USHORT remotePort;
  344. PTFTP_PACKET packet;
  345. ULONG length;
  346. USHORT blockNumber;
  347. #ifdef EFI
  348. //
  349. // There's nothing to do here for an EFI environment.
  350. //
  351. return STATUS_SUCCESS;
  352. #endif
  353. while ( TRUE) {
  354. now = SysGetRelativeTime();
  355. timeout = Connection->NextRetransmit - now;
  356. DPRINT( REAL_LOUD, ("ConnWait: now=%d, next retransmit=%d, timeout=%d\n",
  357. now, Connection->NextRetransmit, timeout) );
  358. length = UdpReceive(
  359. Connection->LastReceivedPacket,
  360. sizeof(TFTP_HEADER) + Connection->BlockSize,
  361. &remoteHost,
  362. &remotePort,
  363. timeout
  364. );
  365. if ( length <= 0 ) {
  366. if ( !ConnRetransmit( Connection, TRUE ) ) {
  367. break;
  368. }
  369. continue;
  370. }
  371. //
  372. // Got a packet; check it out.
  373. //
  374. packet = Connection->LastReceivedPacket;
  375. //
  376. // First, check the received length for validity.
  377. //
  378. Connection->LastReceivedLength = length;
  379. if ( (length < sizeof(TFTP_HEADER)) ||
  380. ((packet->Opcode == TFTP_DATA) &&
  381. (length > (sizeof(TFTP_HEADER) + Connection->BlockSize))) ) {
  382. ConnError(
  383. Connection,
  384. remoteHost,
  385. remotePort,
  386. TFTP_ERROR_UNDEFINED,
  387. "Bad TFTP packet length"
  388. );
  389. continue;
  390. }
  391. //
  392. // Next, check for correct remote host.
  393. //
  394. if ( remoteHost != Connection->RemoteHost ) {
  395. ConnError(
  396. Connection,
  397. remoteHost,
  398. remotePort,
  399. TFTP_ERROR_UNKNOWN_TRANSFER_ID,
  400. "Sorry, wasn't talking to you!"
  401. );
  402. continue;
  403. }
  404. //
  405. // Next, the remote port. If still unsynchronized, use his port.
  406. //
  407. blockNumber = SWAP_WORD( packet->BlockNumber );
  408. if ( !Connection->Synced &&
  409. (((packet->Opcode == Opcode) &&
  410. ((Opcode == TFTP_OACK) || (blockNumber == Connection->BlockNumber))) ||
  411. (packet->Opcode == TFTP_ERROR)) ) {
  412. Connection->Synced = TRUE;
  413. Connection->RemotePort = remotePort;
  414. Connection->Timeout = TIMEOUT; // normal data timeout
  415. } else if ( remotePort != Connection->RemotePort ) {
  416. ConnError(
  417. Connection,
  418. remoteHost,
  419. remotePort,
  420. TFTP_ERROR_UNKNOWN_TRANSFER_ID,
  421. "Unexpected port number"
  422. );
  423. continue;
  424. }
  425. //
  426. // Now check out the TFTP opcode.
  427. //
  428. if ( packet->Opcode == Opcode ) {
  429. if ( (Opcode == TFTP_OACK) || (blockNumber == Connection->BlockNumber) ) {
  430. if ( Packet != NULL ) {
  431. *Packet = packet;
  432. }
  433. Connection->Timeout = TIMEOUT; // normal data timeout
  434. return STATUS_SUCCESS;
  435. } else if ( (blockNumber == Connection->BlockNumber - 1) &&
  436. (Opcode == TFTP_DATA) ) {
  437. if ( !ConnRetransmit( Connection, FALSE ) ) {
  438. break;
  439. }
  440. } else if ( blockNumber > Connection->BlockNumber ) {
  441. DPRINT( ERROR, ("ConnWait: Block number too high (%d vs. %d)\n",
  442. blockNumber, Connection->BlockNumber) );
  443. ConnError(
  444. Connection,
  445. remoteHost,
  446. remotePort,
  447. TFTP_ERROR_ILLEGAL_OPERATION,
  448. "Block number greater than expected"
  449. );
  450. return STATUS_UNSUCCESSFUL;
  451. } else { // old duplicate; ignore
  452. continue;
  453. }
  454. } else if ( packet->Opcode == TFTP_OACK ) {
  455. DPRINT( ERROR, ("ConnWait: received duplicate OACK packet\n") );
  456. if ( Connection->BlockNumber == 1 ) {
  457. if ( !ConnRetransmit( Connection, FALSE ) ) {
  458. break;
  459. }
  460. }
  461. } else if ( packet->Opcode == TFTP_ERROR ) {
  462. //DPRINT( ERROR, ("ConnWait: received error packet; code %x, msg %s\n",
  463. // packet->BlockNumber, packet->Data) );
  464. return STATUS_UNSUCCESSFUL;
  465. } else { // unexpected TFTP opcode
  466. DPRINT( ERROR, ("ConnWait: received unknown TFTP opcode %d\n", packet->Opcode) );
  467. ConnError(
  468. Connection,
  469. remoteHost,
  470. remotePort,
  471. TFTP_ERROR_ILLEGAL_OPERATION,
  472. "Bad opcode received"
  473. );
  474. return STATUS_UNSUCCESSFUL;
  475. }
  476. }
  477. DPRINT( ERROR, ("ConnWait: timeout\n") );
  478. ConnError(
  479. Connection,
  480. Connection->RemoteHost,
  481. Connection->RemotePort,
  482. TFTP_ERROR_UNDEFINED,
  483. "Timeout on receive" );
  484. return STATUS_IO_TIMEOUT;
  485. } // ConnWait
  486. VOID
  487. ConnAck (
  488. IN PCONNECTION Connection
  489. )
  490. //
  491. // Generate and send an ack packet for the specified connection. Also
  492. // update the block number. Use the packet stored in Connection->LastSent to build
  493. // the ack in.
  494. //
  495. {
  496. PTFTP_PACKET packet;
  497. ULONG length;
  498. #ifdef EFI
  499. //
  500. // There's nothing to do here for an EFI environment.
  501. //
  502. ASSERT( FALSE );
  503. return;
  504. #endif
  505. packet = Connection->LastSentPacket;
  506. length = 4;
  507. packet->Opcode = TFTP_DACK;
  508. packet->BlockNumber = SWAP_WORD( Connection->BlockNumber );
  509. ConnSendPacket( Connection, packet, length );
  510. Connection->Retransmissions = 0;
  511. Connection->BlockNumber++;
  512. #ifdef WRAP_TO_1
  513. if ( Connection->BlockNumber == 0 ) {
  514. Connection->BlockNumber = 1;
  515. }
  516. #endif
  517. return;
  518. } // ConnAck
  519. VOID
  520. ConnError (
  521. IN PCONNECTION Connection,
  522. IN ULONG RemoteHost,
  523. IN USHORT RemotePort,
  524. IN USHORT ErrorCode,
  525. IN PUCHAR ErrorMessage
  526. )
  527. //
  528. // Make an error packet to send to the specified foreign host and port
  529. // with the specified error code and error message. This routine is
  530. // used to send error messages in response to packets received from
  531. // unexpected foreign hosts or tid's as well as those received for the
  532. // current connection. It allocates a packet specially
  533. // for the error message because such error messages will not be
  534. // retransmitted. Send it out on the connection.
  535. //
  536. {
  537. PTFTP_PACKET packet;
  538. ULONG length;
  539. DPRINT( CONN_ERROR, ("ConnError: code %x, msg %s\n", ErrorCode, ErrorMessage) );
  540. #ifdef EFI
  541. //
  542. // There's nothing to do here for an EFI environment.
  543. //
  544. return;
  545. #endif
  546. packet = (PTFTP_PACKET)NetTftpPacket[2];
  547. length = 4;
  548. packet->Opcode = TFTP_ERROR;
  549. packet->BlockNumber = ErrorCode;
  550. strcpy( packet->Data, ErrorMessage );
  551. length += ConnStrsize(ErrorMessage);
  552. UdpSend( packet, length, RemoteHost, RemotePort );
  553. return;
  554. } // ConnError
  555. VOID
  556. ConnSendPacket (
  557. IN PCONNECTION Connection,
  558. IN PVOID Packet,
  559. IN ULONG Length
  560. )
  561. //
  562. // Send the specified packet, with the specified tftp length (length -
  563. // udp and ip headers) out on the current connection. Fill in the
  564. // needed parts of the udp and ip headers, byte-swap the tftp packet,
  565. // etc; then write it out. Then set up for retransmit.
  566. //
  567. {
  568. #ifdef EFI
  569. //
  570. // There's nothing to do here for an EFI environment.
  571. //
  572. ASSERT( FALSE );
  573. return;
  574. #endif
  575. UdpSend(
  576. Packet,
  577. Length,
  578. Connection->RemoteHost,
  579. Connection->RemotePort
  580. );
  581. Connection->LastSentPacket = Packet;
  582. Connection->LastSentLength = Length;
  583. Connection->NextRetransmit = SysGetRelativeTime() + Connection->Timeout;
  584. return;
  585. } // ConnSendPacket
  586. PTFTP_PACKET
  587. ConnPrepareSend (
  588. IN PCONNECTION Connection
  589. )
  590. //
  591. // Return a pointer to the next tftp packet suitable for filling for
  592. // writes on the connection.
  593. //
  594. {
  595. #ifdef EFI
  596. //
  597. // There's nothing to do here for an EFI environment.
  598. //
  599. ASSERT( FALSE );
  600. return NULL;
  601. #endif
  602. return Connection->CurrentPacket;
  603. } // ConnPrepareSend
  604. NTSTATUS
  605. ConnWaitForFinalAck (
  606. IN PCONNECTION Connection
  607. )
  608. //
  609. // Finish off a write connection. Wait for the last ack, then
  610. // close the connection and return.
  611. //
  612. {
  613. return ConnWait( Connection, TFTP_DACK, NULL );
  614. } // ConnWaitForFinalAck
  615. BOOLEAN
  616. ConnRetransmit (
  617. IN PCONNECTION Connection,
  618. IN BOOLEAN Timeout
  619. )
  620. //
  621. // Retransmit the last-sent packet, up to MAX_RETRANS times. Exponentially
  622. // back off the timeout time up to a maximum of MAX_TIMEOUT. This algorithm
  623. // may be replaced by a better one in which the timeout time is set from
  624. // the maximum round-trip time to date.
  625. // The second argument indicates whether the retransmission is due to the
  626. // arrival of a duplicate packet or a timeout. If a duplicate, don't include
  627. // this retransmission in the maximum retransmission count.
  628. //
  629. {
  630. #ifdef EFI
  631. //
  632. // There's nothing to do here for an EFI environment.
  633. //
  634. ASSERT( FALSE );
  635. return TRUE;
  636. #endif
  637. if ( Timeout ) {
  638. //
  639. // This is a timeout. Check the retransmit count.
  640. //
  641. if ( ++Connection->Retransmissions >= MAX_RETRANS ) {
  642. //
  643. // Retransmits exhausted.
  644. //
  645. return FALSE;
  646. }
  647. } else {
  648. //
  649. // Duplicate packet. If we just sent a packet, don't send
  650. // another one. This deals with the case where we receive
  651. // multiple identical packets in rapid succession, possibly
  652. // due to network problems or slowness at the remote computer.
  653. //
  654. if ( Connection->NextRetransmit == SysGetRelativeTime() + Connection->Timeout ) {
  655. return TRUE;
  656. }
  657. }
  658. Connection->Timeout <<= 1;
  659. if ( Connection->Timeout > MAX_TIMEOUT ) {
  660. Connection->Timeout = MAX_TIMEOUT;
  661. }
  662. ConnSendPacket( Connection, Connection->LastSentPacket, Connection->LastSentLength );
  663. return TRUE;
  664. } // ConnRetransmit
  665. ULONG
  666. ConnSafeAtol (
  667. IN PUCHAR Buffer,
  668. IN PUCHAR BufferEnd
  669. )
  670. {
  671. ULONG value;
  672. UCHAR c;
  673. value = 0;
  674. while ( Buffer < BufferEnd ) {
  675. c = *Buffer++;
  676. if ( c == 0 ) {
  677. return value;
  678. }
  679. if ( (c < '0') || (c > '9') ) {
  680. break;
  681. }
  682. value = (value * 10) + (c - '0');
  683. }
  684. return (ULONG)-1;
  685. } // ConnSafeAtol
  686. ULONG
  687. ConnItoa (
  688. IN ULONG Value,
  689. OUT PUCHAR Buffer
  690. )
  691. {
  692. PUCHAR p;
  693. ULONG digit;
  694. UCHAR c;
  695. p = Buffer;
  696. //
  697. // Put the value string into the buffer in reverse order.
  698. //
  699. do {
  700. digit = Value % 10;
  701. Value /= 10;
  702. *p++ = (UCHAR)(digit + '0');
  703. } while ( Value > 0 );
  704. //
  705. // Terminate the string and move back to the last character in the string.
  706. //
  707. digit = (ULONG)(p - Buffer + 1); // size of string (including terminator)
  708. *p-- = 0;
  709. //
  710. // Reverse the string.
  711. //
  712. do {
  713. c = *p;
  714. *p-- = *Buffer;
  715. *Buffer++ = c;
  716. } while ( Buffer < p );
  717. return digit;
  718. } // ConnItoa
  719. #if defined(REMOTE_BOOT_SECURITY)
  720. ULONG
  721. ConnSigntoa (
  722. IN PUCHAR Sign,
  723. IN ULONG SignLength,
  724. OUT PUCHAR Buffer
  725. )
  726. {
  727. PUCHAR p;
  728. ULONG digit;
  729. UCHAR c;
  730. ULONG i;
  731. for (i = 0; i < SignLength; i++) {
  732. digit = Sign[i] / 16;
  733. if (digit >= 10) {
  734. c = (UCHAR)('a' + digit - 10);
  735. } else {
  736. c = (UCHAR)('0' + digit);
  737. }
  738. *Buffer = c;
  739. ++Buffer;
  740. digit = Sign[i] % 16;
  741. if (digit >= 10) {
  742. c = (UCHAR)('a' + digit - 10);
  743. } else {
  744. c = (UCHAR)('0' + digit);
  745. }
  746. *Buffer = c;
  747. ++Buffer;
  748. }
  749. *Buffer = '\0';
  750. return (2 * SignLength) + 1;
  751. } // ConnSigntoa
  752. ULONG
  753. ConnAtosign (
  754. IN PUCHAR Buffer,
  755. IN ULONG SignLength,
  756. OUT PUCHAR Sign
  757. )
  758. {
  759. ULONG nibble;
  760. ULONG curDigit;
  761. PUCHAR curBuffer;
  762. curDigit = 0;
  763. curBuffer = Buffer;
  764. while (curDigit <= SignLength) {
  765. if ((*curBuffer >= '0') && (*curBuffer <= '9')) {
  766. nibble = *curBuffer - '0';
  767. } else if ((*curBuffer >= 'a') && (*curBuffer <= 'f')) {
  768. nibble = *curBuffer - 'a' + 10;
  769. } else if ((*curBuffer >= 'A') && (*curBuffer <= 'F')) {
  770. nibble = *curBuffer - 'A' + 10;
  771. } else {
  772. break;
  773. }
  774. ++curBuffer;
  775. if ((*curBuffer >= '0') && (*curBuffer <= '9')) {
  776. Sign[curDigit] = (CHAR)((nibble << 4) + *curBuffer - '0');
  777. } else if ((*curBuffer >= 'a') && (*curBuffer <= 'f')) {
  778. Sign[curDigit] = (CHAR)((nibble << 4) + *curBuffer - 'a' + 10);
  779. } else if ((*curBuffer >= 'A') && (*curBuffer <= 'F')) {
  780. Sign[curDigit] = (CHAR)((nibble << 4) + *curBuffer - 'A' + 10);
  781. } else {
  782. break;
  783. }
  784. ++curBuffer;
  785. ++curDigit;
  786. }
  787. //
  788. // If we hit the end of our curBuffer, then skip the rest of the input.
  789. //
  790. while (*curBuffer != '\0') {
  791. ++curBuffer;
  792. }
  793. //
  794. // Return the amount consumed, plus one for the final \0.
  795. //
  796. return (ULONG)((curBuffer - Buffer) + 1);
  797. } // ConnAtosign
  798. #endif // defined(REMOTE_BOOT_SECURITY)
  799. BOOLEAN
  800. ConnSafeStrequal (
  801. IN PUCHAR Buffer,
  802. IN PUCHAR BufferEnd,
  803. IN PUCHAR CompareString
  804. )
  805. {
  806. while ( Buffer < BufferEnd ) {
  807. if ( *Buffer != *CompareString ) {
  808. return FALSE;
  809. }
  810. if ( *CompareString == 0 ) {
  811. return TRUE;
  812. }
  813. Buffer++;
  814. CompareString++;
  815. }
  816. return FALSE;
  817. } // ConnSafeStrequal
  818. ULONG
  819. ConnSafeStrsize (
  820. IN PUCHAR Buffer,
  821. IN PUCHAR BufferEnd
  822. )
  823. {
  824. PUCHAR eos;
  825. eos = Buffer;
  826. while ( eos < BufferEnd ) {
  827. if ( *eos++ == 0 ) {
  828. return (ULONG)(eos - Buffer);
  829. }
  830. }
  831. return 0;
  832. } // ConnSafeStrsize
  833. ULONG
  834. ConnStrsize (
  835. IN PUCHAR Buffer
  836. )
  837. {
  838. PUCHAR eos;
  839. eos = Buffer;
  840. while ( *eos++ != 0 ) ;
  841. return (ULONG)(eos - Buffer);
  842. } // ConnStrsize