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.

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