Leaked source code of windows server 2003
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.

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