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.

2109 lines
67 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. icmp.c - IP ICMP routines.
  5. Abstract:
  6. This module contains all of the ICMP related routines.
  7. Author:
  8. [Environment:]
  9. kernel mode only
  10. [Notes:]
  11. optional-notes
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #include "mdlpool.h"
  16. #include "icmp.h"
  17. #include "info.h"
  18. #include "iproute.h"
  19. #include "ipxmit.h"
  20. #include <icmpif.h>
  21. #include "iprtdef.h"
  22. #include "tcpipbuf.h"
  23. #if GPC
  24. #include "qos.h"
  25. #include "traffic.h"
  26. #include "gpcifc.h"
  27. #include "ntddtc.h"
  28. extern GPC_HANDLE hGpcClient[];
  29. extern ULONG GpcCfCounts[];
  30. extern GPC_EXPORTED_CALLS GpcEntries;
  31. extern ULONG GPCcfInfo;
  32. extern ULONG ServiceTypeOffset;
  33. #endif
  34. extern ProtInfo IPProtInfo[]; // Protocol information table.
  35. extern void *IPRegisterProtocol(uchar, void *, void *, void *, void *, void *, void *);
  36. extern ulong GetTime();
  37. extern ULStatusProc FindULStatus(uchar);
  38. extern uchar IPUpdateRcvdOptions(IPOptInfo *, IPOptInfo *, IPAddr, IPAddr);
  39. extern void IPInitOptions(IPOptInfo *);
  40. extern IP_STATUS IPCopyOptions(uchar *, uint, IPOptInfo *);
  41. extern IP_STATUS IPFreeOptions(IPOptInfo *);
  42. extern uchar IPGetLocalAddr(IPAddr, IPAddr *);
  43. void ICMPRouterTimer(NetTableEntry *);
  44. extern NDIS_HANDLE BufferPool;
  45. extern uint DisableUserTOS;
  46. extern uint DefaultTOS;
  47. extern NetTableEntry **NewNetTableList; // hash table for NTEs
  48. extern uint NET_TABLE_SIZE;
  49. extern ProtInfo *RawPI; // Raw IP protinfo
  50. uint EnableICMPRedirects = 0;
  51. uint AddrMaskReply;
  52. ICMPStats ICMPInStats;
  53. ICMPStats ICMPOutStats;
  54. HANDLE IcmpHeaderPool;
  55. // Each ICMP header buffer contains room for the outer IP header, the
  56. // ICMP header and the inner IP header (for the ICMP error case).
  57. //
  58. #define BUFSIZE_ICMP_HEADER_POOL sizeof(IPHeader) + sizeof(ICMPHeader) + \
  59. sizeof(IPHeader) + MAX_OPT_SIZE + 8
  60. #define TIMESTAMP_MSG_LEN 3 // icmp timestamp message length is 3 long words (12 bytes)
  61. // fix for icmp 3 way ping bug
  62. #define MAX_ICMP_ECHO 1000
  63. int IcmpEchoPendingCnt = 0;
  64. // fix for system crash because of
  65. // too many UDP PORT_UNREACH errors
  66. // this covers redirect as well as
  67. // unreachable errors
  68. #define MAX_ICMP_ERR 1000
  69. int IcmpErrPendingCnt = 0;
  70. void ICMPInit(uint NumBuffers);
  71. IP_STATUS
  72. ICMPEchoRequest(
  73. void *InputBuffer,
  74. uint InputBufferLength,
  75. EchoControl * ControlBlock,
  76. EchoRtn Callback);
  77. #ifdef ALLOC_PRAGMA
  78. #pragma alloc_text(INIT, ICMPInit)
  79. #pragma alloc_text(PAGE, ICMPEchoRequest)
  80. #endif // ALLOC_PRAGMA
  81. //* UpdateICMPStats - Update ICMP statistics.
  82. //
  83. // A routine to update the ICMP statistics.
  84. //
  85. // Input: Stats - Pointer to stat. structure to update (input or output).
  86. // Type - Type of stat to update.
  87. //
  88. // Returns: Nothing.
  89. //
  90. void
  91. UpdateICMPStats(ICMPStats * Stats, uchar Type)
  92. {
  93. switch (Type) {
  94. case ICMP_DEST_UNREACH:
  95. Stats->icmps_destunreachs++;
  96. break;
  97. case ICMP_TIME_EXCEED:
  98. Stats->icmps_timeexcds++;
  99. break;
  100. case ICMP_PARAM_PROBLEM:
  101. Stats->icmps_parmprobs++;
  102. break;
  103. case ICMP_SOURCE_QUENCH:
  104. Stats->icmps_srcquenchs++;
  105. break;
  106. case ICMP_REDIRECT:
  107. Stats->icmps_redirects++;
  108. break;
  109. case ICMP_TIMESTAMP:
  110. Stats->icmps_timestamps++;
  111. break;
  112. case ICMP_TIMESTAMP_RESP:
  113. Stats->icmps_timestampreps++;
  114. break;
  115. case ICMP_ECHO:
  116. Stats->icmps_echos++;
  117. break;
  118. case ICMP_ECHO_RESP:
  119. Stats->icmps_echoreps++;
  120. break;
  121. case ADDR_MASK_REQUEST:
  122. Stats->icmps_addrmasks++;
  123. break;
  124. case ADDR_MASK_REPLY:
  125. Stats->icmps_addrmaskreps++;
  126. break;
  127. default:
  128. break;
  129. }
  130. }
  131. //** GetICMPBuffer - Get an ICMP buffer, and allocate an NDIS_BUFFER that maps it.
  132. //
  133. // A routine to allocate an ICMP buffer and map an NDIS_BUFFER to it.
  134. //
  135. // Entry: Size - Size in bytes header buffer should be mapped as.
  136. // Buffer - Pointer to pointer to NDIS_BUFFER to return.
  137. //
  138. // Returns: Pointer to ICMP buffer if allocated, or NULL.
  139. //
  140. ICMPHeader *
  141. GetICMPBuffer(uint Size, PNDIS_BUFFER *Buffer)
  142. {
  143. ICMPHeader *Header;
  144. ASSERT(Size);
  145. ASSERT(Buffer);
  146. *Buffer = MdpAllocate(IcmpHeaderPool, &Header);
  147. if (*Buffer) {
  148. NdisAdjustBufferLength(*Buffer, Size);
  149. // Reserve room for the IP Header.
  150. //
  151. Header = (ICMPHeader *)((uchar *)Header + sizeof(IPHeader));
  152. Header->ich_xsum = 0;
  153. }
  154. return Header;
  155. }
  156. //** FreeICMPBuffer - Free an ICMP buffer.
  157. //
  158. // This routine puts an ICMP buffer back on our free list.
  159. //
  160. // Entry: Buffer - Pointer to NDIS_BUFFER to be freed.
  161. // Type - ICMP header type
  162. //
  163. // Returns: Nothing.
  164. //
  165. void
  166. FreeICMPBuffer(PNDIS_BUFFER Buffer, uchar Type)
  167. {
  168. ASSERT(Buffer);
  169. // If the header is ICMP echo response, decrement the pending count.
  170. //
  171. if (Type == ICMP_ECHO_RESP) {
  172. InterlockedDecrement(&IcmpEchoPendingCnt);
  173. } else if ((Type == ICMP_DEST_UNREACH) ||
  174. (Type == ICMP_REDIRECT)) {
  175. InterlockedDecrement(&IcmpErrPendingCnt);
  176. }
  177. MdpFree(Buffer);
  178. }
  179. //** DeleteEC - Remove an EchoControl from an NTE, and return a pointer to it.
  180. //
  181. // This routine is called when we need to remove an echo control structure from
  182. // an NTE. We walk the list of EC structures on the NTE, and if we find a match
  183. // we remove it and return a pointer to it.
  184. //
  185. // Entry: NTE - Pointer to NTE to be searched.
  186. // Seq - Seq. # identifying the EC.
  187. // MatchUshort - if TRUE, matches on lower 16 bits of seq. #
  188. //
  189. // Returns: Pointer to the EC if it finds it.
  190. //
  191. EchoControl *
  192. DeleteEC(NetTableEntry * NTE, uint Seq, BOOLEAN MatchUshort)
  193. {
  194. EchoControl *Prev, *Current;
  195. CTELockHandle Handle;
  196. CTEGetLock(&NTE->nte_lock, &Handle);
  197. Prev = STRUCT_OF(EchoControl, &NTE->nte_echolist, ec_next);
  198. Current = NTE->nte_echolist;
  199. while (Current != (EchoControl *) NULL) {
  200. if (Current->ec_seq == Seq ||
  201. (MatchUshort && (ushort)Current->ec_seq == Seq)) {
  202. Prev->ec_next = Current->ec_next;
  203. break;
  204. } else {
  205. Prev = Current;
  206. Current = Current->ec_next;
  207. }
  208. }
  209. CTEFreeLock(&NTE->nte_lock, Handle);
  210. return Current;
  211. }
  212. //** ICMPSendComplete - Complete an ICMP send.
  213. //
  214. // This rtn is called when an ICMP send completes. We free the header buffer,
  215. // the data buffer if there is one, and the NDIS_BUFFER chain.
  216. //
  217. // Entry: SCC - SendCompleteContext
  218. // BufferChain - Pointer to NDIS_BUFFER chain.
  219. //
  220. // Returns: Nothing
  221. //
  222. void
  223. ICMPSendComplete(ICMPSendCompleteCtxt *SCC, PNDIS_BUFFER BufferChain, IP_STATUS SendStatus)
  224. {
  225. PNDIS_BUFFER DataBuffer;
  226. uchar *DataPtr, Type;
  227. NdisGetNextBuffer(BufferChain, &DataBuffer);
  228. DataPtr = SCC->iscc_DataPtr;
  229. Type = SCC->iscc_Type;
  230. FreeICMPBuffer(BufferChain, Type);
  231. if (DataBuffer != (PNDIS_BUFFER) NULL) { // We had data with this ICMP send.
  232. CTEFreeMem(DataPtr);
  233. NdisFreeBuffer(DataBuffer);
  234. }
  235. CTEFreeMem(SCC);
  236. }
  237. //* XsumBufChain - Checksum a chain of buffers.
  238. //
  239. // Called when we need to checksum an IPRcvBuf chain.
  240. //
  241. // Input: BufChain - Buffer chain to be checksummed.
  242. //
  243. // Returns: The checksum.
  244. //
  245. ushort
  246. XsumBufChain(IPRcvBuf * BufChain)
  247. {
  248. ulong CheckSum = 0;
  249. ASSERT(BufChain);
  250. do {
  251. CheckSum += (ulong) xsum(BufChain->ipr_buffer, BufChain->ipr_size);
  252. BufChain = BufChain->ipr_next;
  253. } while (BufChain != NULL);
  254. // Fold the checksum down.
  255. CheckSum = (CheckSum >> 16) + (CheckSum & 0xffff);
  256. CheckSum += (CheckSum >> 16);
  257. return (ushort) CheckSum;
  258. }
  259. //** SendEcho - Send an ICMP Echo or Echo response.
  260. //
  261. // This routine sends an ICMP echo or echo response. The Echo/EchoResponse may
  262. // carry data. If it does we'll copy the data here. The request may also have
  263. // options. Options are not copied, as the IPTransmit routine will copy
  264. // options.
  265. //
  266. // Entry: Dest - Destination to send to.
  267. // Source - Source to send from.
  268. // Type - Type of request (ECHO or ECHO_RESP)
  269. // ID - ID of request.
  270. // Seq - Seq. # of request.
  271. // Data - Pointer to data (NULL if none).
  272. // DataLength - Length in bytes of data
  273. // OptInfo - Pointer to IP Options structure.
  274. //
  275. // Returns: IP_STATUS of request.
  276. //
  277. IP_STATUS
  278. SendEcho(IPAddr Dest, IPAddr Source, uchar Type, ushort ID, uint Seq,
  279. IPRcvBuf * Data, uint DataLength, IPOptInfo * OptInfo)
  280. {
  281. uchar *DataBuffer = (uchar *) NULL; // Pointer to data buffer.
  282. PNDIS_BUFFER HeaderBuffer, Buffer; // Buffers for our header and user data.
  283. ICMPHeader *Header;
  284. ushort header_xsum;
  285. IP_STATUS IpStatus;
  286. RouteCacheEntry *RCE;
  287. ushort MSS;
  288. uchar DestType;
  289. IPAddr SrcAddr;
  290. ICMPSendCompleteCtxt *SCC;
  291. ICMPOutStats.icmps_msgs++;
  292. DEBUGMSG(DBG_TRACE && DBG_ICMP && DBG_TX,
  293. (DTEXT("+SendEcho(%x, %x, %x, %x, %x, %x, %x, %x)\n"),
  294. Dest, Source, Type, ID, Seq, Data, DataLength, OptInfo));
  295. SrcAddr = OpenRCE(Dest, Source, &RCE, &DestType, &MSS, OptInfo);
  296. if (IP_ADDR_EQUAL(SrcAddr,NULL_IP_ADDR)) {
  297. //Failure, free resource and exit
  298. ICMPOutStats.icmps_errors++;
  299. if (Type == ICMP_ECHO_RESP)
  300. CTEInterlockedDecrementLong(&IcmpEchoPendingCnt);
  301. return IP_DEST_HOST_UNREACHABLE;
  302. }
  303. Header = GetICMPBuffer(sizeof(ICMPHeader), &HeaderBuffer);
  304. if (Header == (ICMPHeader *) NULL) {
  305. ICMPOutStats.icmps_errors++;
  306. if (Type == ICMP_ECHO_RESP)
  307. CTEInterlockedDecrementLong(&IcmpEchoPendingCnt);
  308. CloseRCE(RCE);
  309. return IP_NO_RESOURCES;
  310. }
  311. ASSERT(Type == ICMP_ECHO_RESP || Type == ICMP_ECHO);
  312. Header->ich_type = Type;
  313. Header->ich_code = 0;
  314. *(ushort *) & Header->ich_param = ID;
  315. *((ushort *) & Header->ich_param + 1) = (ushort)Seq;
  316. header_xsum = xsum(Header, sizeof(ICMPHeader));
  317. Header->ich_xsum = ~header_xsum;
  318. SCC = CTEAllocMemN(sizeof(ICMPSendCompleteCtxt), 'sICT');
  319. if (SCC == NULL) {
  320. FreeICMPBuffer(HeaderBuffer,Type);
  321. ICMPOutStats.icmps_errors++;
  322. CloseRCE(RCE);
  323. return IP_NO_RESOURCES;
  324. }
  325. SCC->iscc_Type = Type;
  326. SCC->iscc_DataPtr = NULL;
  327. // If there's data, get a buffer and copy it now. If we can't do this fail the request.
  328. if (DataLength != 0) {
  329. NDIS_STATUS Status;
  330. ulong TempXsum;
  331. uint BytesToCopy, CopyIndex;
  332. DataBuffer = CTEAllocMemN(DataLength, 'YICT');
  333. if (DataBuffer == (void *)NULL) { // Couldn't get a buffer
  334. CloseRCE(RCE);
  335. FreeICMPBuffer(HeaderBuffer, Type);
  336. ICMPOutStats.icmps_errors++;
  337. CTEFreeMem(SCC);
  338. return IP_NO_RESOURCES;
  339. }
  340. BytesToCopy = DataLength;
  341. CopyIndex = 0;
  342. do {
  343. uint CopyLength;
  344. ASSERT(Data);
  345. CopyLength = MIN(BytesToCopy, Data->ipr_size);
  346. RtlCopyMemory(DataBuffer + CopyIndex, Data->ipr_buffer, CopyLength);
  347. Data = Data->ipr_next;
  348. CopyIndex += CopyLength;
  349. BytesToCopy -= CopyLength;
  350. } while (BytesToCopy);
  351. SCC->iscc_DataPtr = DataBuffer;
  352. NdisAllocateBuffer(&Status, &Buffer, BufferPool, DataBuffer, DataLength);
  353. if (Status != NDIS_STATUS_SUCCESS) { // Couldn't get an NDIS_BUFFER
  354. CloseRCE(RCE);
  355. CTEFreeMem(DataBuffer);
  356. FreeICMPBuffer(HeaderBuffer, Type);
  357. ICMPOutStats.icmps_errors++;
  358. CTEFreeMem(SCC);
  359. return IP_NO_RESOURCES;
  360. }
  361. // Compute rest of xsum.
  362. TempXsum = (ulong) header_xsum + (ulong) xsum(DataBuffer, DataLength);
  363. TempXsum = (TempXsum >> 16) + (TempXsum & 0xffff);
  364. TempXsum += (TempXsum >> 16);
  365. Header->ich_xsum = ~(ushort) TempXsum;
  366. NDIS_BUFFER_LINKAGE(HeaderBuffer) = Buffer;
  367. }
  368. UpdateICMPStats(&ICMPOutStats, Type);
  369. OptInfo->ioi_hdrincl = 0;
  370. OptInfo->ioi_ucastif = 0;
  371. OptInfo->ioi_mcastif = 0;
  372. #if GPC
  373. if (DisableUserTOS) {
  374. OptInfo->ioi_tos = (uchar) DefaultTOS;
  375. }
  376. if (GPCcfInfo) {
  377. //
  378. // we'll fall into here only if the GPC client is there
  379. // and there is at least one CF_INFO_QOS installed
  380. // (counted by GPCcfInfo).
  381. //
  382. GPC_STATUS status = STATUS_SUCCESS;
  383. ULONG ServiceType = 0;
  384. GPC_IP_PATTERN Pattern;
  385. CLASSIFICATION_HANDLE GPCHandle;
  386. Pattern.SrcAddr = Source;
  387. Pattern.DstAddr = Dest;
  388. Pattern.ProtocolId = PROT_ICMP;
  389. Pattern.gpcSrcPort = 0;
  390. Pattern.gpcDstPort = 0;
  391. Pattern.InterfaceId.InterfaceId = 0;
  392. Pattern.InterfaceId.LinkId = 0;
  393. GetIFAndLink(RCE,
  394. &Pattern.InterfaceId.InterfaceId,
  395. &Pattern.InterfaceId.LinkId);
  396. GPCHandle = 0;
  397. status = GpcEntries.GpcClassifyPatternHandler(
  398. hGpcClient[GPC_CF_QOS],
  399. GPC_PROTOCOL_TEMPLATE_IP,
  400. &Pattern,
  401. NULL, // context
  402. &GPCHandle,
  403. 0,
  404. NULL,
  405. FALSE);
  406. OptInfo->ioi_GPCHandle = (int)GPCHandle;
  407. //
  408. // Only if QOS patterns exist, we get the TOS bits out.
  409. //
  410. if (NT_SUCCESS(status) && GpcCfCounts[GPC_CF_QOS]) {
  411. status = GpcEntries.GpcGetUlongFromCfInfoHandler(
  412. hGpcClient[GPC_CF_QOS],
  413. OptInfo->ioi_GPCHandle,
  414. ServiceTypeOffset,
  415. &ServiceType);
  416. //
  417. // It is likely that the pattern has gone by now (Removed or whatever)
  418. // and the handle that we are caching is INVALID.
  419. // We need to pull up a new handle and get the
  420. // TOS bit again.
  421. //
  422. if (STATUS_NOT_FOUND == status) {
  423. GPCHandle = 0;
  424. status = GpcEntries.GpcClassifyPatternHandler(
  425. hGpcClient[GPC_CF_QOS],
  426. GPC_PROTOCOL_TEMPLATE_IP,
  427. &Pattern,
  428. NULL, // context
  429. &GPCHandle,
  430. 0,
  431. NULL,
  432. FALSE);
  433. OptInfo->ioi_GPCHandle = (int)GPCHandle;
  434. //
  435. // Only if QOS patterns exist, we get the TOS bits out.
  436. //
  437. if (NT_SUCCESS(status) && GpcCfCounts[GPC_CF_QOS]) {
  438. status = GpcEntries.GpcGetUlongFromCfInfoHandler(
  439. hGpcClient[GPC_CF_QOS],
  440. OptInfo->ioi_GPCHandle,
  441. ServiceTypeOffset,
  442. &ServiceType);
  443. }
  444. }
  445. }
  446. if (status == STATUS_SUCCESS) {
  447. OptInfo->ioi_tos = (OptInfo->ioi_tos & TOS_MASK) | (uchar)ServiceType;
  448. }
  449. } // if (GPCcfInfo)
  450. #endif
  451. IpStatus = IPTransmit(IPProtInfo, SCC, HeaderBuffer,
  452. DataLength + sizeof(ICMPHeader), Dest, Source, OptInfo, RCE,
  453. PROT_ICMP,NULL);
  454. CloseRCE(RCE);
  455. if (IpStatus != IP_PENDING) {
  456. ICMPSendComplete(SCC, HeaderBuffer, IP_SUCCESS);
  457. }
  458. return IpStatus;
  459. }
  460. //** SendICMPMsg - Send an ICMP message
  461. //
  462. // This is the general ICMP message sending routine, called for most ICMP
  463. // sends besides echo. Basically, all we do is get a buffer, format the
  464. // info, copy the input header, and send the message.
  465. //
  466. // Entry: Src - IPAddr of source.
  467. // Dest - IPAddr of destination
  468. // Type - Type of request.
  469. // Code - Subcode of request.
  470. // Pointer - Pointer value for request.
  471. // Data - Pointer to data (NULL if none).
  472. // DataLength - Length in bytes of data
  473. //
  474. // Returns: IP_STATUS of request.
  475. //
  476. IP_STATUS
  477. SendICMPMsg(IPAddr Src, IPAddr Dest, uchar Type, uchar Code, ulong Pointer,
  478. uchar * Data, uchar DataLength)
  479. {
  480. PNDIS_BUFFER HeaderBuffer; // Buffer for our header
  481. ICMPHeader *Header;
  482. IP_STATUS IStatus; // Status of transmit
  483. IPOptInfo OptInfo; // Options for this transmit.
  484. RouteCacheEntry *RCE;
  485. ushort MSS;
  486. uchar DestType;
  487. IPAddr SrcAddr;
  488. ICMPSendCompleteCtxt *SCC;
  489. ICMPOutStats.icmps_msgs++;
  490. IPInitOptions(&OptInfo);
  491. SrcAddr = OpenRCE(Dest,Src, &RCE, &DestType, &MSS, &OptInfo);
  492. if (IP_ADDR_EQUAL(SrcAddr,NULL_IP_ADDR)) {
  493. ICMPOutStats.icmps_errors++;
  494. if ((Type == ICMP_DEST_UNREACH) || (Type == ICMP_REDIRECT))
  495. CTEInterlockedDecrementLong(&IcmpErrPendingCnt);
  496. return IP_DEST_HOST_UNREACHABLE;
  497. }
  498. Header = GetICMPBuffer(sizeof(ICMPHeader) + DataLength, &HeaderBuffer);
  499. if (Header == (ICMPHeader *) NULL) {
  500. ICMPOutStats.icmps_errors++;
  501. if ((Type == ICMP_DEST_UNREACH) || (Type == ICMP_REDIRECT))
  502. CTEInterlockedDecrementLong(&IcmpErrPendingCnt);
  503. CloseRCE(RCE);
  504. return IP_NO_RESOURCES;
  505. }
  506. Header->ich_type = Type;
  507. Header->ich_code = Code;
  508. Header->ich_param = Pointer;
  509. if (Data)
  510. RtlCopyMemory(Header + 1, Data, DataLength);
  511. Header->ich_xsum = ~xsum(Header, sizeof(ICMPHeader) + DataLength);
  512. SCC = CTEAllocMemN(sizeof(ICMPSendCompleteCtxt), 'sICT');
  513. if (SCC == NULL) {
  514. ICMPOutStats.icmps_errors++;
  515. FreeICMPBuffer(HeaderBuffer, Type);
  516. CloseRCE(RCE);
  517. return IP_NO_RESOURCES;
  518. }
  519. SCC->iscc_Type = Type;
  520. SCC->iscc_DataPtr = NULL;
  521. UpdateICMPStats(&ICMPOutStats, Type);
  522. #if GPC
  523. if (DisableUserTOS) {
  524. OptInfo.ioi_tos = (uchar) DefaultTOS;
  525. }
  526. if (GPCcfInfo) {
  527. //
  528. // we'll fall into here only if the GPC client is there
  529. // and there is at least one CF_INFO_QOS installed
  530. // (counted by GPCcfInfo).
  531. //
  532. GPC_STATUS status = STATUS_SUCCESS;
  533. ULONG ServiceType = 0;
  534. GPC_IP_PATTERN Pattern;
  535. CLASSIFICATION_HANDLE GPCHandle;
  536. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL, "ICMPSend: Classifying \n"));
  537. Pattern.SrcAddr = Src;
  538. Pattern.DstAddr = Dest;
  539. Pattern.ProtocolId = PROT_ICMP;
  540. Pattern.gpcSrcPort = 0;
  541. Pattern.gpcDstPort = 0;
  542. Pattern.InterfaceId.InterfaceId = 0;
  543. Pattern.InterfaceId.LinkId = 0;
  544. GetIFAndLink(RCE,
  545. &Pattern.InterfaceId.InterfaceId,
  546. &Pattern.InterfaceId.LinkId);
  547. GPCHandle = 0;
  548. status = GpcEntries.GpcClassifyPatternHandler(
  549. hGpcClient[GPC_CF_QOS],
  550. GPC_PROTOCOL_TEMPLATE_IP,
  551. &Pattern,
  552. NULL, // context
  553. &GPCHandle,
  554. 0,
  555. NULL,
  556. FALSE);
  557. OptInfo.ioi_GPCHandle = (int)GPCHandle;
  558. //
  559. // Only if QOS patterns exist, we get the TOS bits out.
  560. //
  561. if (NT_SUCCESS(status) && GpcCfCounts[GPC_CF_QOS]) {
  562. status = GpcEntries.GpcGetUlongFromCfInfoHandler(
  563. hGpcClient[GPC_CF_QOS],
  564. OptInfo.ioi_GPCHandle,
  565. ServiceTypeOffset,
  566. &ServiceType);
  567. //
  568. // It is likely that the pattern has gone by now (Removed or whatever)
  569. // and the handle that we are caching is INVALID.
  570. // We need to pull up a new handle and get the
  571. // TOS bit again.
  572. //
  573. if (STATUS_NOT_FOUND == status) {
  574. GPCHandle = 0;
  575. status = GpcEntries.GpcClassifyPatternHandler(
  576. hGpcClient[GPC_CF_QOS],
  577. GPC_PROTOCOL_TEMPLATE_IP,
  578. &Pattern,
  579. NULL, // context
  580. &GPCHandle,
  581. 0,
  582. NULL,
  583. FALSE);
  584. OptInfo.ioi_GPCHandle = (int)GPCHandle;
  585. //
  586. // Only if QOS patterns exist, we get the TOS bits out.
  587. //
  588. if (NT_SUCCESS(status) && GpcCfCounts[GPC_CF_QOS]) {
  589. status = GpcEntries.GpcGetUlongFromCfInfoHandler(
  590. hGpcClient[GPC_CF_QOS],
  591. OptInfo.ioi_GPCHandle,
  592. ServiceTypeOffset,
  593. &ServiceType);
  594. }
  595. }
  596. }
  597. if (status == STATUS_SUCCESS) {
  598. OptInfo.ioi_tos = (OptInfo.ioi_tos & TOS_MASK) | (UCHAR)ServiceType;
  599. }
  600. } // if (GPCcfInfo)
  601. #endif
  602. IStatus = IPTransmit(IPProtInfo, SCC, HeaderBuffer,
  603. DataLength + sizeof(ICMPHeader),
  604. Dest, Src, &OptInfo, RCE,
  605. PROT_ICMP,NULL);
  606. CloseRCE(RCE);
  607. if (IStatus != IP_PENDING)
  608. ICMPSendComplete(SCC, HeaderBuffer, IP_SUCCESS);
  609. return IStatus;
  610. }
  611. //** SendICMPErr - Send an ICMP error message
  612. //
  613. // This is the routine used to send an ICMP error message, such as ]
  614. // Destination Unreachable. We examine the header to find the length of the
  615. // data, and also make sure we're not replying to another ICMP error message
  616. // or a broadcast message. Then we call SendICMPMsg to send it.
  617. //
  618. // Entry: Src - IPAddr of source.
  619. // Header - Pointer to IP Header that caused the problem.
  620. // Type - Type of request.
  621. // Code - Subcode of request.
  622. // Pointer - Pointer value for request.
  623. //
  624. // Returns: IP_STATUS of request.
  625. //
  626. IP_STATUS
  627. SendICMPErr(IPAddr Src, IPHeader UNALIGNED * Header, uchar Type, uchar Code,
  628. ulong Pointer)
  629. {
  630. uchar HeaderLength; // Length in bytes if header.
  631. uchar DType;
  632. HeaderLength = (Header->iph_verlen & (uchar) ~ IP_VER_FLAG) << 2;
  633. if (Header->iph_protocol == PROT_ICMP) {
  634. ICMPHeader UNALIGNED *ICH = (ICMPHeader UNALIGNED *)
  635. ((uchar *) Header + HeaderLength);
  636. if (ICH->ich_type != ICMP_ECHO)
  637. return IP_SUCCESS;
  638. }
  639. // Don't respond to sends to a broadcast destination.
  640. DType = GetAddrType(Header->iph_dest);
  641. if (DType == DEST_INVALID || IS_BCAST_DEST(DType))
  642. return IP_SUCCESS;
  643. // Don't respond if the source address is bad.
  644. DType = GetAddrType(Header->iph_src);
  645. if (DType == DEST_INVALID || IS_BCAST_DEST(DType) ||
  646. (IP_LOOPBACK(Header->iph_dest) && DType != DEST_LOCAL))
  647. return IP_SUCCESS;
  648. // Make sure the source we're sending from is good.
  649. if (!IP_ADDR_EQUAL(Src, NULL_IP_ADDR)) {
  650. if (GetAddrType(Src) != DEST_LOCAL) {
  651. return IP_SUCCESS;
  652. }
  653. }
  654. // Double check to make sure it's an initial fragment.
  655. if ((Header->iph_offset & IP_OFFSET_MASK) != 0)
  656. return IP_SUCCESS;
  657. if ((Type == ICMP_DEST_UNREACH) || (Type == ICMP_REDIRECT)) {
  658. if (IcmpErrPendingCnt > MAX_ICMP_ERR) {
  659. return IP_SUCCESS;
  660. }
  661. CTEInterlockedIncrementLong(&IcmpErrPendingCnt);
  662. }
  663. return SendICMPMsg(Src, Header->iph_src, Type, Code, Pointer,
  664. (uchar *) Header, (uchar) (MIN(HeaderLength + 8,
  665. Header->iph_length)));
  666. }
  667. //** SendICMPIPSecErr - Send an ICMP error message related to IPSEC
  668. //
  669. // This is the routine used to send an ICMP error message, such as Destination
  670. // Unreachable. We examine the header to find the length of the data, and
  671. // also make sure we're not replying to another ICMP error message or a
  672. // broadcast message. Then we call SendICMPMsg to send it.
  673. //
  674. // This function is essentially the same as SendICMPErr except we don't
  675. // verify the source address is local because the packet could be tunneled.
  676. //
  677. // Entry: Src - IPAddr of source.
  678. // Header - Pointer to IP Header that caused the problem.
  679. // Type - Type of request.
  680. // Code - Subcode of request.
  681. // Pointer - Pointer value for request.
  682. //
  683. // Returns: IP_STATUS of request.
  684. //
  685. IP_STATUS
  686. SendICMPIPSecErr(IPAddr Src, IPHeader UNALIGNED * Header, uchar Type, uchar Code,
  687. ulong Pointer)
  688. {
  689. uchar HeaderLength; // Length in bytes if header.
  690. uchar DType;
  691. HeaderLength = (Header->iph_verlen & (uchar) ~ IP_VER_FLAG) << 2;
  692. if (Header->iph_protocol == PROT_ICMP) {
  693. ICMPHeader UNALIGNED *ICH = (ICMPHeader UNALIGNED *)
  694. ((uchar *) Header + HeaderLength);
  695. if (ICH->ich_type != ICMP_ECHO)
  696. return IP_SUCCESS;
  697. }
  698. // Don't respond to sends to a broadcast destination.
  699. DType = GetAddrType(Header->iph_dest);
  700. if (DType == DEST_INVALID || IS_BCAST_DEST(DType))
  701. return IP_SUCCESS;
  702. // Don't respond if the source address is bad.
  703. DType = GetAddrType(Header->iph_src);
  704. if (DType == DEST_INVALID || IS_BCAST_DEST(DType) ||
  705. (IP_LOOPBACK(Header->iph_dest) && DType != DEST_LOCAL))
  706. return IP_SUCCESS;
  707. // Make sure the source we're sending from is good.
  708. if (IP_ADDR_EQUAL(Src, NULL_IP_ADDR))
  709. return IP_SUCCESS;
  710. // Double check to make sure it's an initial fragment.
  711. if ((Header->iph_offset & IP_OFFSET_MASK) != 0)
  712. return IP_SUCCESS;
  713. if ((Type == ICMP_DEST_UNREACH) || (Type == ICMP_REDIRECT)) {
  714. if (IcmpErrPendingCnt > MAX_ICMP_ERR) {
  715. return IP_SUCCESS;
  716. }
  717. CTEInterlockedIncrementLong(&IcmpErrPendingCnt);
  718. }
  719. return SendICMPMsg(Src, Header->iph_src, Type, Code, Pointer,
  720. (uchar *) Header, (uchar) (HeaderLength + 8));
  721. }
  722. //** ICMPTimer - Timer for ICMP
  723. //
  724. // This is the timer routine called periodically by global IP timer. We
  725. // walk through the list of pending pings, and if we find one that's timed
  726. // out we remove it and call the finish routine.
  727. //
  728. // Entry: NTE - Pointer to NTE being timed out.
  729. //
  730. // Returns: Nothing
  731. //
  732. void
  733. ICMPTimer(NetTableEntry * NTE)
  734. {
  735. CTELockHandle Handle;
  736. EchoControl *TimeoutList = (EchoControl *) NULL; // Timed out entries.
  737. EchoControl *Prev, *Current;
  738. ulong Now = CTESystemUpTime();
  739. CTEGetLock(&NTE->nte_lock, &Handle);
  740. Prev = STRUCT_OF(EchoControl, &NTE->nte_echolist, ec_next);
  741. Current = NTE->nte_echolist;
  742. while (Current != (EchoControl *) NULL)
  743. if ((Current->ec_active) && ((long)(Now - Current->ec_to) > 0)) {
  744. // This one's timed out.
  745. Prev->ec_next = Current->ec_next;
  746. // Link him on timed out list.
  747. Current->ec_next = TimeoutList;
  748. TimeoutList = Current;
  749. Current = Prev->ec_next;
  750. } else {
  751. Prev = Current;
  752. Current = Current->ec_next;
  753. }
  754. CTEFreeLock(&NTE->nte_lock, Handle);
  755. // Now go through the timed out entries, and call the completion routine.
  756. while (TimeoutList != (EchoControl *) NULL) {
  757. Current = TimeoutList;
  758. TimeoutList = Current->ec_next;
  759. Current->ec_rtn(Current, IP_REQ_TIMED_OUT, NULL, 0, NULL);
  760. }
  761. ICMPRouterTimer(NTE);
  762. }
  763. //* CompleteEcho - Complete an echo request.
  764. //
  765. // Called when we need to complete an echo request, either because of
  766. // a response or a received ICMP error message. We look it up, and then
  767. // call the completion routine.
  768. //
  769. // Input: Header - Pointer to ICMP header causing completion.
  770. // Status - Final status of request.
  771. // Src - IPAddr of source
  772. // Data - Data to be returned, if any.
  773. // DataSize - Size in bytes of data.
  774. // OptInfo - Option info structure.
  775. //
  776. // Returns: Nothing.
  777. //
  778. void
  779. CompleteEcho(ICMPHeader UNALIGNED * Header, IP_STATUS Status,
  780. IPAddr Src, IPRcvBuf * Data, uint DataSize, IPOptInfo * OptInfo)
  781. {
  782. ushort NTEContext;
  783. EchoControl *EC;
  784. NetTableEntry *NTE;
  785. uint i;
  786. // Look up and remove the matching echo control block.
  787. NTEContext = (*(ushort UNALIGNED *) & Header->ich_param);
  788. for (i = 0; i < NET_TABLE_SIZE; i++) {
  789. NetTableEntry *NetTableList = NewNetTableList[i];
  790. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
  791. if (NTEContext == NTE->nte_context)
  792. break;
  793. if (NTE != NULL)
  794. break;
  795. }
  796. if (NTE == NULL)
  797. return; // Bad context value.
  798. EC = DeleteEC(NTE, *(((ushort UNALIGNED *) & Header->ich_param) + 1), TRUE);
  799. if (EC != (EchoControl *) NULL) { // Found a match.
  800. EC->ec_src = Src; // Set source address
  801. EC->ec_rtn(EC, Status, Data, DataSize, OptInfo);
  802. }
  803. }
  804. //** ICMPStatus - ICMP status handling procedure.
  805. //
  806. // This is the procedure called during a status change, either from an
  807. // incoming ICMP message or a hardware status change. ICMP ignores most of
  808. // these, unless we get an ICMP status message that was caused be an echo
  809. // request. In that case we will complete the corresponding echo request with
  810. // the appropriate error code.
  811. //
  812. // Input: StatusType - Type of status (NET or HW)
  813. // StatusCode - Code identifying IP_STATUS.
  814. // OrigDest - If this is net status, the original dest. of DG
  815. // that triggered it.
  816. // OrigSrc - " " " " " , the original src.
  817. // Src - IP address of status originator (could be local
  818. // or remote).
  819. // Param - Additional information for status - i.e. the
  820. // param field of an ICMP message.
  821. // Data - Data pertaining to status - for net status, this
  822. // is the first 8 bytes of the original DG.
  823. //
  824. // Returns: Nothing
  825. //
  826. void
  827. ICMPStatus(uchar StatusType, IP_STATUS StatusCode, IPAddr OrigDest,
  828. IPAddr OrigSrc, IPAddr Src, ulong Param, void *Data)
  829. {
  830. if (StatusType == IP_NET_STATUS) {
  831. ICMPHeader UNALIGNED *ICH = (ICMPHeader UNALIGNED *) Data;
  832. // ICH is the datagram that caused the message.
  833. if (ICH->ich_type == ICMP_ECHO) { // And it was an echo request.
  834. IPRcvBuf RcvBuf;
  835. RcvBuf.ipr_next = NULL;
  836. RcvBuf.ipr_buffer = (uchar *) & Src;
  837. RcvBuf.ipr_size = sizeof(IPAddr);
  838. CompleteEcho(ICH, StatusCode, Src, &RcvBuf, sizeof(IPAddr), NULL);
  839. }
  840. }
  841. }
  842. //* ICMPMapStatus - Map an ICMP error to an IP status code.
  843. //
  844. // Called by ICMP status when we need to map from an incoming ICMP error
  845. // code and type to an ICMP status.
  846. //
  847. // Entry: Type - Type of ICMP error.
  848. // Code - Subcode of error.
  849. //
  850. // Returns: Corresponding IP status.
  851. //
  852. IP_STATUS
  853. ICMPMapStatus(uchar Type, uchar Code)
  854. {
  855. switch (Type) {
  856. case ICMP_DEST_UNREACH:
  857. switch (Code) {
  858. case NET_UNREACH:
  859. case HOST_UNREACH:
  860. case PROT_UNREACH:
  861. case PORT_UNREACH:
  862. return IP_DEST_UNREACH_BASE + Code;
  863. break;
  864. case FRAG_NEEDED:
  865. return IP_PACKET_TOO_BIG;
  866. break;
  867. case SR_FAILED:
  868. return IP_BAD_ROUTE;
  869. break;
  870. case DEST_NET_UNKNOWN:
  871. case SRC_ISOLATED:
  872. case DEST_NET_ADMIN:
  873. case NET_UNREACH_TOS:
  874. return IP_DEST_NET_UNREACHABLE;
  875. break;
  876. case DEST_HOST_UNKNOWN:
  877. case DEST_HOST_ADMIN:
  878. case HOST_UNREACH_TOS:
  879. return IP_DEST_HOST_UNREACHABLE;
  880. break;
  881. default:
  882. return IP_DEST_NET_UNREACHABLE;
  883. }
  884. break;
  885. case ICMP_TIME_EXCEED:
  886. if (Code == TTL_IN_TRANSIT)
  887. return IP_TTL_EXPIRED_TRANSIT;
  888. else
  889. return IP_TTL_EXPIRED_REASSEM;
  890. break;
  891. case ICMP_PARAM_PROBLEM:
  892. return IP_PARAM_PROBLEM;
  893. break;
  894. case ICMP_SOURCE_QUENCH:
  895. return IP_SOURCE_QUENCH;
  896. break;
  897. default:
  898. return IP_GENERAL_FAILURE;
  899. break;
  900. }
  901. }
  902. void
  903. SendRouterSolicitation(NetTableEntry * NTE)
  904. {
  905. if (NTE->nte_rtrdiscovery) {
  906. SendICMPMsg(NTE->nte_addr, NTE->nte_rtrdiscaddr,
  907. ICMP_ROUTER_SOLICITATION, 0, 0, NULL, 0);
  908. }
  909. }
  910. //** ICMPRouterTimer - Timeout default gateway entries
  911. //
  912. // This is the router advertisement timeout handler. When a router
  913. // advertisement is received, we add the routers to our default gateway
  914. // list if applicable. We then run a timer on the entries and refresh
  915. // the list as new advertisements are received. If we fail to hear an
  916. // update for a router within the specified lifetime we will delete the
  917. // route from our routing tables.
  918. //
  919. void
  920. ICMPRouterTimer(NetTableEntry * NTE)
  921. {
  922. CTELockHandle Handle;
  923. IPRtrEntry *rtrentry;
  924. IPRtrEntry *temprtrentry;
  925. IPRtrEntry *lastrtrentry = NULL;
  926. uint SendIt = FALSE;
  927. CTEGetLock(&NTE->nte_lock, &Handle);
  928. rtrentry = NTE->nte_rtrlist;
  929. while (rtrentry != NULL) {
  930. if (rtrentry->ire_lifetime-- == 0) {
  931. if (lastrtrentry == NULL) {
  932. NTE->nte_rtrlist = rtrentry->ire_next;
  933. } else {
  934. lastrtrentry->ire_next = rtrentry->ire_next;
  935. }
  936. temprtrentry = rtrentry;
  937. rtrentry = rtrentry->ire_next;
  938. DeleteRoute(NULL_IP_ADDR, DEFAULT_MASK,
  939. temprtrentry->ire_addr, NTE->nte_if, 0);
  940. CTEFreeMem(temprtrentry);
  941. } else {
  942. lastrtrentry = rtrentry;
  943. rtrentry = rtrentry->ire_next;
  944. }
  945. }
  946. if (NTE->nte_rtrdisccount != 0) {
  947. NTE->nte_rtrdisccount--;
  948. if ((NTE->nte_rtrdiscstate == NTE_RTRDISC_SOLICITING) &&
  949. ((NTE->nte_rtrdisccount % SOLICITATION_INTERVAL) == 0)) {
  950. SendIt = TRUE;
  951. }
  952. if ((NTE->nte_rtrdiscstate == NTE_RTRDISC_DELAYING) &&
  953. (NTE->nte_rtrdisccount == 0)) {
  954. NTE->nte_rtrdisccount = (SOLICITATION_INTERVAL) * (MAX_SOLICITATIONS - 1);
  955. NTE->nte_rtrdiscstate = NTE_RTRDISC_SOLICITING;
  956. SendIt = TRUE;
  957. }
  958. }
  959. CTEFreeLock(&NTE->nte_lock, Handle);
  960. if (SendIt) {
  961. SendRouterSolicitation(NTE);
  962. }
  963. }
  964. //** ProcessRouterAdvertisement - Process a router advertisement
  965. //
  966. // This is the router advertisement handler. When a router advertisement
  967. // is received, we add the routers to our default gateway list if applicable.
  968. //
  969. uint
  970. ProcessRouterAdvertisement(IPAddr Src, IPAddr LocalAddr, NetTableEntry * NTE,
  971. ICMPRouterAdHeader UNALIGNED * AdHeader, IPRcvBuf * RcvBuf, uint Size)
  972. {
  973. uchar NumAddrs = AdHeader->irah_numaddrs;
  974. uchar AddrEntrySize = AdHeader->irah_addrentrysize;
  975. ushort Lifetime = net_short(AdHeader->irah_lifetime);
  976. ICMPRouterAdAddrEntry UNALIGNED *RouterAddr = (ICMPRouterAdAddrEntry UNALIGNED *) RcvBuf->ipr_buffer;
  977. uint i;
  978. CTELockHandle Handle;
  979. IPRtrEntry *rtrentry;
  980. IPRtrEntry *lastrtrentry = NULL;
  981. int Update = FALSE;
  982. int New = FALSE;
  983. IP_STATUS status;
  984. if ((NumAddrs == 0) || (AddrEntrySize < 2)) // per rfc 1256
  985. return FALSE;
  986. CTEGetLock(&NTE->nte_lock, &Handle);
  987. for (i = 0; i < NumAddrs; i++, RouterAddr++) {
  988. if ((RouterAddr->irae_addr & NTE->nte_mask) != (NTE->nte_addr & NTE->nte_mask)) {
  989. continue;
  990. }
  991. if (!IsRouteICMP(NULL_IP_ADDR, DEFAULT_MASK, RouterAddr->irae_addr, NTE->nte_if)) {
  992. continue;
  993. }
  994. rtrentry = NTE->nte_rtrlist;
  995. while (rtrentry != NULL) {
  996. if (rtrentry->ire_addr == RouterAddr->irae_addr) {
  997. rtrentry->ire_lifetime = Lifetime * 2;
  998. if (rtrentry->ire_preference != RouterAddr->irae_preference) {
  999. rtrentry->ire_preference = RouterAddr->irae_preference;
  1000. Update = TRUE;
  1001. }
  1002. break;
  1003. }
  1004. lastrtrentry = rtrentry;
  1005. rtrentry = rtrentry->ire_next;
  1006. }
  1007. if (rtrentry == NULL) {
  1008. rtrentry = (IPRtrEntry *) CTEAllocMemN(sizeof(IPRtrEntry), 'dICT');
  1009. if (rtrentry == NULL) {
  1010. return FALSE;
  1011. }
  1012. rtrentry->ire_next = NULL;
  1013. rtrentry->ire_addr = RouterAddr->irae_addr;
  1014. rtrentry->ire_preference = RouterAddr->irae_preference;
  1015. rtrentry->ire_lifetime = Lifetime * 2;
  1016. if (lastrtrentry == NULL) {
  1017. NTE->nte_rtrlist = rtrentry;
  1018. } else {
  1019. lastrtrentry->ire_next = rtrentry;
  1020. }
  1021. New = TRUE;
  1022. Update = TRUE;
  1023. }
  1024. if (Update && (RouterAddr->irae_preference != (long)0x00000080)) { // per rfc 1256
  1025. status = AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
  1026. RouterAddr->irae_addr,
  1027. NTE->nte_if, NTE->nte_mss,
  1028. (uint) (MIN(9999, MAX(1, 1000 - net_long(RouterAddr->irae_preference)))), // invert for metric
  1029. IRE_PROTO_ICMP, ATYPE_OVERRIDE, 0, 0);
  1030. if (New && (status != IP_SUCCESS)) {
  1031. if (lastrtrentry == NULL) {
  1032. NTE->nte_rtrlist = NULL;
  1033. }
  1034. CTEFreeMem(rtrentry);
  1035. }
  1036. }
  1037. Update = FALSE;
  1038. New = FALSE;
  1039. }
  1040. CTEFreeLock(&NTE->nte_lock, Handle);
  1041. return TRUE;
  1042. }
  1043. //** ICMPRcv - Receive an ICMP datagram.
  1044. //
  1045. // Called by the main IP code when we receive an ICMP datagram. The action we
  1046. // take depends on what the DG is. For some DGs, we call upper layer status
  1047. // handlers. For Echo Requests, we call the echo responder.
  1048. //
  1049. // Entry: NTE - Pointer to NTE on which ICMP message was received.
  1050. // Dest - IPAddr of destionation.
  1051. // Src - IPAddr of source
  1052. // LocalAddr - Local address of network which caused this to be
  1053. // received.
  1054. // SrcAddr - Address of local interface which received the
  1055. // packet
  1056. // IPHdr - Pointer to IP Header
  1057. // IPHdrLength - Bytes in Header.
  1058. // RcvBuf - ICMP message buffer.
  1059. // Size - Size in bytes of ICMP message.
  1060. // IsBCast - Boolean indicator of whether or not this came in
  1061. // as a bcast.
  1062. // Protocol - Protocol this came in on.
  1063. // OptInfo - Pointer to info structure for received options.
  1064. //
  1065. // Returns: Status of reception
  1066. //
  1067. IP_STATUS
  1068. ICMPRcv(NetTableEntry * NTE, IPAddr Dest, IPAddr Src, IPAddr LocalAddr,
  1069. IPAddr SrcAddr, IPHeader UNALIGNED * IPHdr, uint IPHdrLength,
  1070. IPRcvBuf * RcvBuf, uint Size, uchar IsBCast, uchar Protocol,
  1071. IPOptInfo * OptInfo)
  1072. {
  1073. ICMPHeader UNALIGNED *Header;
  1074. void *Data; // Pointer to data received.
  1075. IPHeader UNALIGNED *IPH; // Pointer to IP Header in error messages.
  1076. uint HeaderLength; // Size of IP header.
  1077. ULStatusProc ULStatus; // Pointer to upper layer status procedure.
  1078. IPOptInfo NewOptInfo;
  1079. uchar DType;
  1080. uint PassUp = FALSE;
  1081. uint PromiscuousMode = 0;
  1082. DEBUGMSG(DBG_TRACE && DBG_ICMP && DBG_RX,
  1083. (DTEXT("+ICMPRcv(%x, %x, %x, %x, %x, %x, %d, %x, %d, %x, %x, %x)\n"),
  1084. NTE, Dest, Src, LocalAddr, SrcAddr, IPHdr, IPHdrLength,
  1085. RcvBuf, Size, IsBCast, Protocol, OptInfo));
  1086. ICMPInStats.icmps_msgs++;
  1087. PromiscuousMode = NTE->nte_if->if_promiscuousmode;
  1088. DType = GetAddrType(Src);
  1089. if (Size < sizeof(ICMPHeader) || DType == DEST_INVALID ||
  1090. IS_BCAST_DEST(DType) || (IP_LOOPBACK(Dest) && DType != DEST_LOCAL) ||
  1091. XsumBufChain(RcvBuf) != (ushort) 0xffff) {
  1092. DEBUGMSG(DBG_WARN && DBG_ICMP && DBG_RX,
  1093. (DTEXT("ICMPRcv: Packet dropped, invalid checksum.\n")));
  1094. ICMPInStats.icmps_errors++;
  1095. return IP_SUCCESS; // Bad checksum.
  1096. }
  1097. Header = (ICMPHeader UNALIGNED *) RcvBuf->ipr_buffer;
  1098. RcvBuf->ipr_buffer += sizeof(ICMPHeader);
  1099. RcvBuf->ipr_size -= sizeof(ICMPHeader);
  1100. // Set up the data pointer for most requests, i.e. those that take less
  1101. // than MIN_FIRST_SIZE data.
  1102. if (Size -= sizeof(ICMPHeader))
  1103. Data = (void *)(Header + 1);
  1104. else
  1105. Data = (void *)NULL;
  1106. switch (Header->ich_type) {
  1107. case ICMP_DEST_UNREACH:
  1108. case ICMP_TIME_EXCEED:
  1109. case ICMP_PARAM_PROBLEM:
  1110. case ICMP_SOURCE_QUENCH:
  1111. case ICMP_REDIRECT:
  1112. if (IsBCast)
  1113. return IP_SUCCESS; // ICMP doesn't respond to bcast requests.
  1114. if (Data == NULL || Size < sizeof(IPHeader)) {
  1115. ICMPInStats.icmps_errors++;
  1116. return IP_SUCCESS; // No data, error.
  1117. }
  1118. IPH = (IPHeader UNALIGNED *) Data;
  1119. HeaderLength = (IPH->iph_verlen & (uchar) ~ IP_VER_FLAG) << 2;
  1120. if (HeaderLength < sizeof(IPHeader) || Size < (HeaderLength + MIN_ERRDATA_LENGTH)) {
  1121. ICMPInStats.icmps_errors++;
  1122. return IP_SUCCESS; // Not enough data for this
  1123. // ICMP message.
  1124. }
  1125. // Make sure that the source address of the datagram that triggered
  1126. // the message is one of ours.
  1127. if (GetAddrType(IPH->iph_src) != DEST_LOCAL) {
  1128. ICMPInStats.icmps_errors++;
  1129. return IP_SUCCESS; // Bad src in header.
  1130. }
  1131. if (Header->ich_type != ICMP_REDIRECT) {
  1132. UpdateICMPStats(&ICMPInStats, Header->ich_type);
  1133. if (ULStatus = FindULStatus(IPH->iph_protocol)) {
  1134. (void)(*ULStatus) (IP_NET_STATUS,
  1135. ICMPMapStatus(Header->ich_type, Header->ich_code),
  1136. IPH->iph_dest, IPH->iph_src, Src, Header->ich_param,
  1137. (uchar *) IPH + HeaderLength);
  1138. }
  1139. if (Header->ich_code == FRAG_NEEDED)
  1140. RouteFragNeeded(
  1141. IPH,
  1142. (ushort) net_short(
  1143. *((ushort UNALIGNED *) & Header->ich_param + 1)));
  1144. } else {
  1145. ICMPInStats.icmps_redirects++;
  1146. if (EnableICMPRedirects)
  1147. Redirect(NTE, Src, IPH->iph_dest, IPH->iph_src,
  1148. Header->ich_param);
  1149. }
  1150. PassUp = TRUE;
  1151. break;
  1152. case ICMP_ECHO_RESP:
  1153. if (IsBCast)
  1154. return IP_SUCCESS; // ICMP doesn't respond to bcast requests.
  1155. ICMPInStats.icmps_echoreps++;
  1156. // Look up and remove the matching echo control block.
  1157. CompleteEcho(Header, IP_SUCCESS, Src, RcvBuf, Size, OptInfo);
  1158. PassUp = TRUE;
  1159. break;
  1160. case ICMP_ECHO:
  1161. if (IsBCast)
  1162. return IP_SUCCESS; // ICMP doesn't respond to bcast requests.
  1163. // NKS Outstanding PINGs can not exceed MAX_ICMP_ECHO
  1164. // else they can eat up system resource and kill the system
  1165. if (IcmpEchoPendingCnt > MAX_ICMP_ECHO) {
  1166. return IP_SUCCESS;
  1167. }
  1168. CTEInterlockedIncrementLong(&IcmpEchoPendingCnt);
  1169. ICMPInStats.icmps_echos++;
  1170. IPInitOptions(&NewOptInfo);
  1171. NewOptInfo.ioi_tos = OptInfo->ioi_tos;
  1172. NewOptInfo.ioi_flags = OptInfo->ioi_flags;
  1173. // If we have options, we need to reverse them and update any
  1174. // record route info. We can use the option buffer supplied by the
  1175. // IP layer, since we're part of him.
  1176. if (OptInfo->ioi_options != (uchar *) NULL)
  1177. IPUpdateRcvdOptions(OptInfo, &NewOptInfo, Src, LocalAddr);
  1178. DEBUGMSG(DBG_INFO && DBG_ICMP && DBG_RX,
  1179. (DTEXT("ICMPRcv: responding to echo request from SA:%x\n"),
  1180. Src));
  1181. SendEcho(Src, LocalAddr, ICMP_ECHO_RESP,
  1182. *(ushort UNALIGNED *) & Header->ich_param,
  1183. *((ushort UNALIGNED *) & Header->ich_param + 1),
  1184. RcvBuf, Size, &NewOptInfo);
  1185. IPFreeOptions(&NewOptInfo);
  1186. break;
  1187. case ADDR_MASK_REQUEST:
  1188. if (!AddrMaskReply)
  1189. return IP_SUCCESS; // By default we dont send a reply
  1190. ICMPInStats.icmps_addrmasks++;
  1191. Dest = Src;
  1192. SendICMPMsg(LocalAddr, Dest, ADDR_MASK_REPLY, 0, Header->ich_param,
  1193. (uchar *) & NTE->nte_mask, sizeof(IPMask));
  1194. break;
  1195. case ICMP_TIMESTAMP:
  1196. {
  1197. ulong *TimeStampData;
  1198. ulong CurrentTime;
  1199. // Don't respond to sends to a broadcast destination.
  1200. if (IsBCast) {
  1201. return IP_SUCCESS;
  1202. }
  1203. if (Header->ich_code != 0)
  1204. return IP_SUCCESS; // Code must be 0
  1205. ICMPInStats.icmps_timestamps++;
  1206. Dest = Src;
  1207. // create the data to be transmited
  1208. CurrentTime = GetTime();
  1209. TimeStampData = (ulong *) (CTEAllocMemN(TIMESTAMP_MSG_LEN * sizeof(ulong), 'eICT'));
  1210. if (TimeStampData) {
  1211. // originate timestamp
  1212. RtlCopyMemory(TimeStampData, RcvBuf->ipr_buffer, sizeof(ulong));
  1213. // receive timestamp
  1214. RtlCopyMemory(TimeStampData + 1, &CurrentTime, sizeof(ulong));
  1215. // transmit timestamp = receive timestamp
  1216. RtlCopyMemory(TimeStampData + 2, &CurrentTime, sizeof(ulong));
  1217. SendICMPMsg(LocalAddr, Dest, ICMP_TIMESTAMP_RESP, 0, Header->ich_param,
  1218. (uchar *) TimeStampData, TIMESTAMP_MSG_LEN * sizeof(ulong));
  1219. CTEFreeMem(TimeStampData);
  1220. }
  1221. break;
  1222. }
  1223. case ICMP_ROUTER_ADVERTISEMENT:
  1224. if (Header->ich_code != 0)
  1225. return IP_SUCCESS; // Code must be 0 as per RFC1256
  1226. if (NTE->nte_rtrdiscovery) {
  1227. if (!ProcessRouterAdvertisement(Src, LocalAddr, NTE,
  1228. (ICMPRouterAdHeader *) & Header->ich_param, RcvBuf, Size))
  1229. return IP_SUCCESS; // An error was returned
  1230. }
  1231. PassUp = TRUE;
  1232. break;
  1233. case ICMP_ROUTER_SOLICITATION:
  1234. if (Header->ich_code != 0)
  1235. return IP_SUCCESS; // Code must be 0 as per RFC1256
  1236. PassUp = TRUE;
  1237. break;
  1238. default:
  1239. PassUp = TRUE;
  1240. UpdateICMPStats(&ICMPInStats, Header->ich_type);
  1241. break;
  1242. }
  1243. if (PromiscuousMode) {
  1244. // since if promiscuous mode is set then we will anyway call rawrcv
  1245. PassUp = FALSE;
  1246. }
  1247. //
  1248. // Pass the packet up to the raw layer if applicable.
  1249. //
  1250. if (PassUp && (RawPI != NULL)) {
  1251. if (RawPI->pi_rcv != NULL) {
  1252. //
  1253. // Restore the original values.
  1254. //
  1255. RcvBuf->ipr_buffer -= sizeof(ICMPHeader);
  1256. RcvBuf->ipr_size += sizeof(ICMPHeader);
  1257. Size += sizeof(ICMPHeader);
  1258. Data = (void *)Header;
  1259. (*(RawPI->pi_rcv)) (NTE, Dest, Src, LocalAddr, SrcAddr, IPHdr,
  1260. IPHdrLength, RcvBuf, Size, IsBCast, Protocol, OptInfo);
  1261. }
  1262. }
  1263. return IP_SUCCESS;
  1264. }
  1265. //** ICMPEcho - Send an echo to the specified address.
  1266. //
  1267. // Entry: ControlBlock - Pointer to an EchoControl structure. This structure
  1268. // must remain valid until the req. completes.
  1269. // Timeout - Time in milliseconds to wait for response.
  1270. // Data - Pointer to data to send with echo.
  1271. // DataSize - Size in bytes of data.
  1272. // Callback - Routine to call when request is responded to or
  1273. // times out.
  1274. // Dest - Address to be pinged.
  1275. // OptInfo - Pointer to opt info structure to use for ping.
  1276. //
  1277. // Returns: IP_STATUS of attempt to ping..
  1278. //
  1279. IP_STATUS
  1280. ICMPEcho(EchoControl * ControlBlock, ulong Timeout, void *Data, uint DataSize,
  1281. EchoRtn Callback, IPAddr Dest, IPOptInfo * OptInfo)
  1282. {
  1283. IPAddr Dummy;
  1284. NetTableEntry *NTE;
  1285. CTELockHandle Handle;
  1286. uint Seq;
  1287. IP_STATUS Status;
  1288. IPOptInfo NewOptInfo;
  1289. IPRcvBuf RcvBuf;
  1290. uint MTU;
  1291. Interface *IF;
  1292. uchar DType;
  1293. IPHeader IPH;
  1294. if (OptInfo->ioi_ttl == 0) {
  1295. return IP_BAD_OPTION;
  1296. }
  1297. IPInitOptions(&NewOptInfo);
  1298. NewOptInfo.ioi_ttl = OptInfo->ioi_ttl;
  1299. NewOptInfo.ioi_flags = OptInfo->ioi_flags;
  1300. NewOptInfo.ioi_tos = OptInfo->ioi_tos & 0xfe;
  1301. if (OptInfo->ioi_optlength != 0) {
  1302. Status = IPCopyOptions(OptInfo->ioi_options, OptInfo->ioi_optlength,
  1303. &NewOptInfo);
  1304. if (Status != IP_SUCCESS)
  1305. return Status;
  1306. }
  1307. if (!IP_ADDR_EQUAL(NewOptInfo.ioi_addr, NULL_IP_ADDR)) {
  1308. Dest = NewOptInfo.ioi_addr;
  1309. }
  1310. DType = GetAddrType(Dest);
  1311. if (DType == DEST_INVALID) {
  1312. IPFreeOptions(&NewOptInfo);
  1313. return IP_BAD_DESTINATION;
  1314. }
  1315. IPH.iph_protocol = 1;
  1316. IPH.iph_xsum = 0;
  1317. IPH.iph_dest = Dest;
  1318. IPH.iph_src = 0;
  1319. IPH.iph_ttl = 128;
  1320. IF = LookupNextHopWithBuffer(Dest, NULL_IP_ADDR, &Dummy, &MTU, 0x1,
  1321. (uchar *) &IPH, sizeof(IPHeader), NULL, NULL, NULL_IP_ADDR, 0);
  1322. if (IF == NULL) {
  1323. IPFreeOptions(&NewOptInfo);
  1324. return IP_DEST_HOST_UNREACHABLE; // Don't know how to get there.
  1325. }
  1326. // Loop through the NetTable, looking for a matching NTE.
  1327. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1328. if (DHCPActivityCount != 0) {
  1329. NTE = NULL;
  1330. } else {
  1331. NTE = BestNTEForIF(Dummy, IF);
  1332. }
  1333. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1334. // We're done with the interface, so dereference it.
  1335. DerefIF(IF);
  1336. if (NTE == NULL) {
  1337. IPFreeOptions(&NewOptInfo);
  1338. return IP_DEST_HOST_UNREACHABLE;
  1339. }
  1340. // Figure out the timeout.
  1341. ControlBlock->ec_to = CTESystemUpTime() + Timeout;
  1342. ControlBlock->ec_rtn = Callback;
  1343. ControlBlock->ec_active = 0; // Prevent from timing out until sent
  1344. CTEGetLock(&NTE->nte_lock, &Handle);
  1345. // Link onto ping list, and get seq. # */
  1346. Seq = ++NTE->nte_icmpseq;
  1347. ControlBlock->ec_seq = Seq;
  1348. ControlBlock->ec_next = NTE->nte_echolist;
  1349. NTE->nte_echolist = ControlBlock;
  1350. CTEFreeLock(&NTE->nte_lock, Handle);
  1351. //
  1352. // N.B. At this point, it is only safe to return IP_PENDING from this
  1353. // routine. This is because we may recieve a spoofed ICMP reply/status
  1354. // which matches the Seq in the echo control block we just linked. If
  1355. // this happens, it will be completed via CompleteEcho and we do not
  1356. // want to risk double-completion by returning anything other than
  1357. // pending from here on.
  1358. //
  1359. RcvBuf.ipr_next = NULL;
  1360. RcvBuf.ipr_buffer = Data;
  1361. RcvBuf.ipr_size = DataSize;
  1362. Status = SendEcho(Dest, NTE->nte_addr, ICMP_ECHO, NTE->nte_context,
  1363. Seq, &RcvBuf, DataSize, &NewOptInfo);
  1364. IPFreeOptions(&NewOptInfo);
  1365. if (Status != IP_PENDING && Status != IP_SUCCESS) {
  1366. EchoControl *FoundEC;
  1367. // We had an error on the send. We need to complete the request
  1368. // but only if it has not already been completed. (We can get
  1369. // an "error" via IpSec negotiating security, but the reply may
  1370. // have already been received which would cause CompleteEcho to be
  1371. // invoked. Therefore, we must lookup the echo control by sequence
  1372. // number and only complete it here if it was found (not already
  1373. // completed.)
  1374. FoundEC = DeleteEC(NTE, Seq, FALSE);
  1375. if (FoundEC == ControlBlock) {
  1376. FoundEC->ec_rtn(FoundEC, Status, NULL, 0, NULL);
  1377. }
  1378. } else {
  1379. EchoControl *Current;
  1380. // If the request is still pending, activate the timer
  1381. CTEGetLock(&NTE->nte_lock, &Handle);
  1382. for (Current = NTE->nte_echolist; Current != (EchoControl *) NULL;
  1383. Current = Current->ec_next) {
  1384. if (Current->ec_seq == Seq) {
  1385. Current->ec_active = 1; // start the timer
  1386. break;
  1387. }
  1388. }
  1389. CTEFreeLock(&NTE->nte_lock, Handle);
  1390. }
  1391. return IP_PENDING;
  1392. }
  1393. //** ICMPEchoRequest - Common dispatch routine for echo requests
  1394. //
  1395. // This is the routine called by the OS-specific code on behalf of a user to
  1396. // issue an echo request.
  1397. //
  1398. // Entry: InputBuffer - Pointer to an ICMP_ECHO_REQUEST structure.
  1399. // InputBufferLength - Size in bytes of the InputBuffer.
  1400. // ControlBlock - Pointer to an EchoControl structure. This
  1401. // structure must remain valid until the
  1402. // request completes.
  1403. // Callback - Routine to call when request is responded to
  1404. // or times out.
  1405. //
  1406. // Returns: IP_STATUS of attempt to ping.
  1407. //
  1408. IP_STATUS
  1409. ICMPEchoRequest(void *InputBuffer, uint InputBufferLength,
  1410. EchoControl *ControlBlock, EchoRtn Callback)
  1411. {
  1412. PICMP_ECHO_REQUEST requestBuffer;
  1413. struct IPOptInfo optionInfo;
  1414. PUCHAR endOfRequestBuffer;
  1415. IP_STATUS status;
  1416. PAGED_CODE();
  1417. requestBuffer = (PICMP_ECHO_REQUEST) InputBuffer;
  1418. endOfRequestBuffer = ((PUCHAR) requestBuffer) + InputBufferLength;
  1419. //
  1420. // Validate the request.
  1421. //
  1422. if (InputBufferLength < sizeof(ICMP_ECHO_REQUEST)) {
  1423. status = IP_BUF_TOO_SMALL;
  1424. goto common_echo_exit;
  1425. }
  1426. if (requestBuffer->DataSize > 0) {
  1427. if (((PUCHAR)requestBuffer + requestBuffer->DataSize > endOfRequestBuffer) ||
  1428. ((PUCHAR)requestBuffer + requestBuffer->DataOffset > endOfRequestBuffer)){
  1429. status = IP_GENERAL_FAILURE;
  1430. goto common_echo_exit;
  1431. }
  1432. if ((requestBuffer->DataOffset < sizeof(ICMP_ECHO_REQUEST)) ||
  1433. (((PUCHAR) requestBuffer + requestBuffer->DataOffset +
  1434. requestBuffer->DataSize) > endOfRequestBuffer)) {
  1435. status = IP_GENERAL_FAILURE;
  1436. goto common_echo_exit;
  1437. }
  1438. }
  1439. if (requestBuffer->OptionsSize > 0) {
  1440. if (((PUCHAR)requestBuffer->OptionsOffset > endOfRequestBuffer) ||
  1441. ((PUCHAR)requestBuffer->OptionsSize > endOfRequestBuffer)){
  1442. status = IP_GENERAL_FAILURE;
  1443. goto common_echo_exit;
  1444. }
  1445. if ((requestBuffer->OptionsOffset < sizeof(ICMP_ECHO_REQUEST)) ||
  1446. (((PUCHAR) requestBuffer + requestBuffer->OptionsOffset +
  1447. requestBuffer->OptionsSize) > endOfRequestBuffer)) {
  1448. status = IP_GENERAL_FAILURE;
  1449. goto common_echo_exit;
  1450. }
  1451. }
  1452. RtlZeroMemory(&optionInfo, sizeof(IPOptInfo));
  1453. //
  1454. // Copy the options to a local structure.
  1455. //
  1456. if (requestBuffer->OptionsValid) {
  1457. optionInfo.ioi_optlength = requestBuffer->OptionsSize;
  1458. if (requestBuffer->OptionsSize > 0) {
  1459. optionInfo.ioi_options = ((uchar *) requestBuffer) +
  1460. requestBuffer->OptionsOffset;
  1461. } else {
  1462. optionInfo.ioi_options = NULL;
  1463. }
  1464. optionInfo.ioi_addr = 0;
  1465. optionInfo.ioi_ttl = requestBuffer->Ttl;
  1466. optionInfo.ioi_tos = requestBuffer->Tos;
  1467. optionInfo.ioi_flags = requestBuffer->Flags;
  1468. optionInfo.ioi_flags &= ~IP_FLAG_IPSEC;
  1469. } else {
  1470. optionInfo.ioi_optlength = 0;
  1471. optionInfo.ioi_options = NULL;
  1472. optionInfo.ioi_addr = 0;
  1473. optionInfo.ioi_ttl = DEFAULT_TTL;
  1474. optionInfo.ioi_tos = 0;
  1475. optionInfo.ioi_flags = 0;
  1476. }
  1477. status = ICMPEcho(
  1478. ControlBlock,
  1479. requestBuffer->Timeout,
  1480. ((uchar *) requestBuffer) + requestBuffer->DataOffset,
  1481. requestBuffer->DataSize,
  1482. Callback,
  1483. (IPAddr) requestBuffer->Address,
  1484. &optionInfo);
  1485. common_echo_exit:
  1486. return (status);
  1487. } // ICMPEchoRequest
  1488. //** ICMPEchoComplete - Common completion routine for echo requests
  1489. //
  1490. // This is the routine is called by the OS-specific code to process an
  1491. // ICMP echo response.
  1492. //
  1493. // Entry: OutputBuffer - Pointer to an ICMP_ECHO_REPLY structure.
  1494. // OutputBufferLength - Size in bytes of the OutputBuffer.
  1495. // Status - The status of the reply.
  1496. // Data - The reply data (may be NULL).
  1497. // DataSize - The amount of reply data.
  1498. // OptionInfo - A pointer to the reply options
  1499. //
  1500. // Returns: The number of bytes written to the output buffer
  1501. //
  1502. ulong
  1503. ICMPEchoComplete(EchoControl * ControlBlock, IP_STATUS Status, void *Data,
  1504. uint DataSize, struct IPOptInfo * OptionInfo)
  1505. {
  1506. PICMP_ECHO_REPLY replyBuffer;
  1507. IPRcvBuf *dataBuffer;
  1508. uchar *replyData;
  1509. uchar *replyOptionsData;
  1510. uchar optionsLength;
  1511. uchar *tmp;
  1512. ulong bytesReturned = sizeof(ICMP_ECHO_REPLY);
  1513. replyBuffer = (PICMP_ECHO_REPLY)ControlBlock->ec_replybuf;
  1514. dataBuffer = (IPRcvBuf *)Data;
  1515. if (OptionInfo != NULL) {
  1516. optionsLength = OptionInfo->ioi_optlength;
  1517. } else {
  1518. optionsLength = 0;
  1519. }
  1520. //
  1521. // Initialize the reply buffer
  1522. //
  1523. replyBuffer->Options.OptionsSize = 0;
  1524. replyBuffer->Options.OptionsData = (PUCHAR)(replyBuffer + 1);
  1525. replyBuffer->DataSize = 0;
  1526. replyBuffer->Data = replyBuffer->Options.OptionsData;
  1527. replyOptionsData = (uchar*)(replyBuffer + 1);
  1528. replyData = replyOptionsData;
  1529. if ((Status != IP_SUCCESS) && (DataSize == 0)) {
  1530. //
  1531. // Timed out or internal error.
  1532. //
  1533. replyBuffer->Reserved = 0; // indicate no replies.
  1534. replyBuffer->Status = Status;
  1535. } else {
  1536. if (Status != IP_SUCCESS) {
  1537. //
  1538. // A message other than an echo reply was received.
  1539. // The IP Address of the system that reported the error is
  1540. // in the data buffer. There is no other data.
  1541. //
  1542. ASSERT(dataBuffer->ipr_size == sizeof(IPAddr));
  1543. RtlCopyMemory(&(replyBuffer->Address), dataBuffer->ipr_buffer,
  1544. sizeof(IPAddr));
  1545. DataSize = 0;
  1546. dataBuffer = NULL;
  1547. } else {
  1548. // If there were no timeouts or errors, store the source
  1549. // address in the reply buffer.
  1550. //
  1551. replyBuffer->Address = ControlBlock->ec_src;
  1552. }
  1553. //
  1554. // Check that the reply buffer is large enough to hold all the data.
  1555. //
  1556. if (ControlBlock->ec_replybuflen <
  1557. (sizeof(ICMP_ECHO_REPLY) + DataSize + optionsLength)) {
  1558. //
  1559. // Not enough space to hold the reply.
  1560. //
  1561. replyBuffer->Reserved = 0; // indicate no replies
  1562. replyBuffer->Status = IP_BUF_TOO_SMALL;
  1563. } else {
  1564. LARGE_INTEGER Now, Freq;
  1565. replyBuffer->Reserved = 1; // indicate one reply
  1566. replyBuffer->Status = Status;
  1567. Now = KeQueryPerformanceCounter(&Freq);
  1568. replyBuffer->RoundTripTime = (uint)
  1569. ((1000 * (Now.QuadPart - ControlBlock->ec_starttime.QuadPart))
  1570. / Freq.QuadPart);
  1571. //
  1572. // Copy the reply options.
  1573. //
  1574. if (OptionInfo != NULL) {
  1575. replyBuffer->Options.Ttl = OptionInfo->ioi_ttl;
  1576. replyBuffer->Options.Tos = OptionInfo->ioi_tos;
  1577. replyBuffer->Options.Flags = OptionInfo->ioi_flags;
  1578. replyBuffer->Options.OptionsSize = optionsLength;
  1579. if (optionsLength > 0) {
  1580. RtlCopyMemory(replyOptionsData,
  1581. OptionInfo->ioi_options, optionsLength);
  1582. }
  1583. }
  1584. //
  1585. // Copy the reply data
  1586. //
  1587. replyBuffer->DataSize = (ushort) DataSize;
  1588. replyData = replyOptionsData + replyBuffer->Options.OptionsSize;
  1589. if (DataSize > 0) {
  1590. uint bytesToCopy;
  1591. ASSERT(Data != NULL);
  1592. tmp = replyData;
  1593. while (DataSize) {
  1594. ASSERT(dataBuffer != NULL);
  1595. bytesToCopy =
  1596. (DataSize > dataBuffer->ipr_size)
  1597. ? dataBuffer->ipr_size : DataSize;
  1598. RtlCopyMemory(tmp, dataBuffer->ipr_buffer, bytesToCopy);
  1599. tmp += bytesToCopy;
  1600. DataSize -= bytesToCopy;
  1601. dataBuffer = dataBuffer->ipr_next;
  1602. }
  1603. }
  1604. bytesReturned += replyBuffer->DataSize + optionsLength;
  1605. //
  1606. // Convert the kernel-mode pointers to offsets from start of reply
  1607. // buffer.
  1608. //
  1609. replyBuffer->Options.OptionsData =
  1610. (PUCHAR)((ULONG_PTR)replyOptionsData - (ULONG_PTR)replyBuffer);
  1611. replyBuffer->Data =
  1612. (PVOID)((ULONG_PTR)replyData - (ULONG_PTR)replyBuffer);
  1613. }
  1614. }
  1615. return (bytesReturned);
  1616. }
  1617. #if defined(_WIN64)
  1618. //** ICMPEchoComplete32 - common completion routine for 32-bit client requests.
  1619. //
  1620. // This is the routine called by the OS-specific request handler to complete
  1621. // processing of an ICMP echo-request issued by a 32-bit client on Win64.
  1622. //
  1623. // Entry: see ICMPEchoComplete.
  1624. //
  1625. // Returns: see ICMPEchoComplete.
  1626. //
  1627. ulong
  1628. ICMPEchoComplete32(EchoControl * ControlBlock, IP_STATUS Status, void *Data,
  1629. uint DataSize, struct IPOptInfo * OptionInfo)
  1630. {
  1631. PICMP_ECHO_REPLY32 replyBuffer;
  1632. IPRcvBuf *dataBuffer;
  1633. uchar *replyData;
  1634. uchar *replyOptionsData;
  1635. uchar optionsLength;
  1636. uchar *tmp;
  1637. ulong bytesReturned = sizeof(ICMP_ECHO_REPLY32);
  1638. replyBuffer = (PICMP_ECHO_REPLY32)ControlBlock->ec_replybuf;
  1639. dataBuffer = (IPRcvBuf *)Data;
  1640. if (OptionInfo != NULL) {
  1641. optionsLength = OptionInfo->ioi_optlength;
  1642. } else {
  1643. optionsLength = 0;
  1644. }
  1645. //
  1646. // Initialize the reply buffer
  1647. //
  1648. replyBuffer->Options.OptionsSize = 0;
  1649. replyBuffer->Options.OptionsData = (UCHAR* POINTER_32)(replyBuffer + 1);
  1650. replyBuffer->DataSize = 0;
  1651. replyBuffer->Data = replyBuffer->Options.OptionsData;
  1652. replyOptionsData = (uchar*)(replyBuffer + 1);
  1653. replyData = replyOptionsData;
  1654. if ((Status != IP_SUCCESS) && (DataSize == 0)) {
  1655. //
  1656. // Timed out or internal error.
  1657. //
  1658. replyBuffer->Reserved = 0; // indicate no replies.
  1659. replyBuffer->Status = Status;
  1660. } else {
  1661. if (Status != IP_SUCCESS) {
  1662. //
  1663. // A message other than an echo reply was received.
  1664. // The IP Address of the system that reported the error is
  1665. // in the data buffer. There is no other data.
  1666. //
  1667. ASSERT(dataBuffer->ipr_size == sizeof(IPAddr));
  1668. RtlCopyMemory(&(replyBuffer->Address), dataBuffer->ipr_buffer,
  1669. sizeof(IPAddr));
  1670. DataSize = 0;
  1671. dataBuffer = NULL;
  1672. } else {
  1673. // If there were no timeouts or errors, store the source
  1674. // address in the reply buffer.
  1675. //
  1676. replyBuffer->Address = ControlBlock->ec_src;
  1677. }
  1678. //
  1679. // Check that the reply buffer is large enough to hold all the data.
  1680. //
  1681. if (ControlBlock->ec_replybuflen <
  1682. (sizeof(ICMP_ECHO_REPLY) + DataSize + optionsLength)) {
  1683. //
  1684. // Not enough space to hold the reply.
  1685. //
  1686. replyBuffer->Reserved = 0; // indicate no replies
  1687. replyBuffer->Status = IP_BUF_TOO_SMALL;
  1688. } else {
  1689. LARGE_INTEGER Now, Freq;
  1690. replyBuffer->Reserved = 1; // indicate one reply
  1691. replyBuffer->Status = Status;
  1692. Now = KeQueryPerformanceCounter(&Freq);
  1693. replyBuffer->RoundTripTime = (uint)
  1694. ((1000 * (Now.QuadPart - ControlBlock->ec_starttime.QuadPart))
  1695. / Freq.QuadPart);
  1696. //
  1697. // Copy the reply options.
  1698. //
  1699. if (OptionInfo != NULL) {
  1700. replyBuffer->Options.Ttl = OptionInfo->ioi_ttl;
  1701. replyBuffer->Options.Tos = OptionInfo->ioi_tos;
  1702. replyBuffer->Options.Flags = OptionInfo->ioi_flags;
  1703. replyBuffer->Options.OptionsSize = optionsLength;
  1704. if (optionsLength > 0) {
  1705. RtlCopyMemory(replyOptionsData,
  1706. OptionInfo->ioi_options, optionsLength);
  1707. }
  1708. }
  1709. //
  1710. // Copy the reply data
  1711. //
  1712. replyBuffer->DataSize = (ushort) DataSize;
  1713. replyData = replyOptionsData + replyBuffer->Options.OptionsSize;
  1714. if (DataSize > 0) {
  1715. uint bytesToCopy;
  1716. ASSERT(Data != NULL);
  1717. tmp = replyData;
  1718. while (DataSize) {
  1719. ASSERT(dataBuffer != NULL);
  1720. bytesToCopy =
  1721. (DataSize > dataBuffer->ipr_size)
  1722. ? dataBuffer->ipr_size : DataSize;
  1723. RtlCopyMemory(tmp, dataBuffer->ipr_buffer, bytesToCopy);
  1724. tmp += bytesToCopy;
  1725. DataSize -= bytesToCopy;
  1726. dataBuffer = dataBuffer->ipr_next;
  1727. }
  1728. }
  1729. bytesReturned += replyBuffer->DataSize + optionsLength;
  1730. //
  1731. // Convert the kernel-mode pointers to offsets from start of reply
  1732. // buffer.
  1733. //
  1734. replyBuffer->Options.OptionsData =
  1735. (UCHAR * POINTER_32)
  1736. ((ULONG_PTR)replyOptionsData - (ULONG_PTR)replyBuffer);
  1737. replyBuffer->Data =
  1738. (VOID * POINTER_32)
  1739. ((ULONG_PTR)replyData - (ULONG_PTR)replyBuffer);
  1740. }
  1741. }
  1742. return (bytesReturned);
  1743. }
  1744. #endif // _WIN64
  1745. #pragma BEGIN_INIT
  1746. //** ICMPInit - Initialize ICMP.
  1747. //
  1748. // This routine initializes ICMP. All we do is allocate and link up some header buffers,
  1749. /// and register our protocol with IP.
  1750. //
  1751. // Entry: NumBuffers - Number of ICMP buffers to allocate.
  1752. //
  1753. // Returns: Nothing
  1754. //
  1755. void
  1756. ICMPInit(uint NumBuffers)
  1757. {
  1758. IcmpHeaderPool = MdpCreatePool(BUFSIZE_ICMP_HEADER_POOL, 'chCT');
  1759. IPRegisterProtocol(PROT_ICMP, ICMPRcv, ICMPSendComplete, ICMPStatus, NULL, NULL, NULL);
  1760. }
  1761. #pragma END_INIT