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.

350 lines
7.6 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. ipinip\icmpfn.c
  5. Abstract:
  6. Handlers for ICMP messages relating to the tunnel
  7. Author:
  8. Amritansh Raghav
  9. Revision History:
  10. AmritanR Created
  11. Notes:
  12. --*/
  13. #define __FILE_SIG__ ICMP_SIG
  14. #include "inc.h"
  15. NTSTATUS
  16. HandleTimeExceeded(
  17. PTUNNEL pTunnel,
  18. PICMP_HEADER pIcmpHeader,
  19. PIP_HEADER pInHeader
  20. )
  21. /*++
  22. Routine Description
  23. Locks
  24. The tunnels is locked and refcounted
  25. Arguments
  26. pTunnel Tunnel associated with the ICMP message
  27. pIcmpHeader The ICMP header
  28. pInHeader The original header
  29. Return Value
  30. STATUS_SUCCESS
  31. --*/
  32. {
  33. PPENDING_MESSAGE pMessage;
  34. //
  35. // We mark the tunnel as down.
  36. // Periodically we will sweep the tunnels and mark them as up
  37. //
  38. #if DBG
  39. Trace(TUNN, INFO,
  40. ("HandleTimeExceeded: Time exceeded message for %s\n",
  41. pTunnel->asDebugBindName.Buffer));
  42. #endif
  43. pTunnel->dwOperState = IF_OPER_STATUS_NON_OPERATIONAL;
  44. pTunnel->dwAdminState |= TS_TTL_TOO_LOW;
  45. pMessage = AllocateMessage();
  46. if(pMessage isnot NULL)
  47. {
  48. pMessage->inMsg.ieEvent = IE_INTERFACE_DOWN;
  49. pMessage->inMsg.iseSubEvent = ISE_ICMP_TTL_TOO_LOW;
  50. pMessage->inMsg.dwIfIndex = pTunnel->dwIfIndex;
  51. CompleteNotificationIrp(pMessage);
  52. }
  53. KeQueryTickCount((PLARGE_INTEGER)&((pTunnel->ullLastChange)));
  54. return STATUS_SUCCESS;
  55. }
  56. NTSTATUS
  57. HandleDestUnreachable(
  58. PTUNNEL pTunnel,
  59. PICMP_HEADER pIcmpHeader,
  60. PIP_HEADER pInHeader
  61. )
  62. /*++
  63. Routine Description
  64. Locks
  65. The tunnels is locked and refcounted
  66. Arguments
  67. pTunnel Tunnel associated with the ICMP message
  68. pIcmpHeader The ICMP header
  69. pInHeader The original header
  70. Return Value
  71. STATUS_SUCCESS
  72. --*/
  73. {
  74. PPENDING_MESSAGE pMessage;
  75. if(pIcmpHeader->byCode is ICMP_CODE_DGRAM_TOO_BIG)
  76. {
  77. PICMP_DGRAM_TOO_BIG_MSG pMsg;
  78. ULONG ulNewMtu;
  79. pMsg = (PICMP_DGRAM_TOO_BIG_MSG)pIcmpHeader;
  80. //
  81. // Change the MTU
  82. //
  83. ulNewMtu = (ULONG)(RtlUshortByteSwap(pMsg->usMtu) - MAX_IP_HEADER_LENGTH);
  84. if(ulNewMtu < pTunnel->ulMtu)
  85. {
  86. LLIPMTUChange mtuChangeInfo;
  87. #if DBG
  88. Trace(TUNN, INFO,
  89. ("HandleDestUnreachable: Dgram too big %s. Old %d New %d\n",
  90. pTunnel->asDebugBindName.Buffer,
  91. pTunnel->ulMtu,
  92. ulNewMtu));
  93. #endif
  94. pTunnel->ulMtu = ulNewMtu;
  95. mtuChangeInfo.lmc_mtu = ulNewMtu;
  96. g_pfnIpStatus(pTunnel->pvIpContext,
  97. LLIP_STATUS_MTU_CHANGE,
  98. &mtuChangeInfo,
  99. sizeof(LLIPMTUChange),
  100. NULL);
  101. }
  102. else
  103. {
  104. RtAssert(FALSE);
  105. }
  106. KeQueryTickCount((PLARGE_INTEGER)&((pTunnel->ullLastChange)));
  107. return STATUS_SUCCESS;
  108. }
  109. RtAssert(pIcmpHeader->byCode <= ICMP_CODE_DGRAM_TOO_BIG);
  110. //
  111. // Other codes are NetUnreachable, HostUnreachable, ProtoUnreachable
  112. // and PortUnreachable.
  113. //
  114. RtAssert(pIcmpHeader->byCode isnot ICMP_CODE_PORT_UNREACHABLE);
  115. #if DBG
  116. Trace(TUNN, INFO,
  117. ("HandleDestUnreachable: Code %d\n",
  118. pIcmpHeader->byCode));
  119. #endif
  120. //
  121. // For these codes, we mark the tunnel down.
  122. // Periodically we will sweep the tunnels and mark them as up
  123. //
  124. pTunnel->dwOperState = IF_OPER_STATUS_NON_OPERATIONAL;
  125. pTunnel->dwAdminState |= TS_DEST_UNREACH;
  126. pMessage = AllocateMessage();
  127. if(pMessage isnot NULL)
  128. {
  129. pMessage->inMsg.ieEvent = IE_INTERFACE_DOWN;
  130. pMessage->inMsg.iseSubEvent = ISE_DEST_UNREACHABLE;
  131. pMessage->inMsg.dwIfIndex = pTunnel->dwIfIndex;
  132. CompleteNotificationIrp(pMessage);
  133. }
  134. KeQueryTickCount((PLARGE_INTEGER)&((pTunnel->ullLastChange)));
  135. return STATUS_SUCCESS;
  136. }
  137. VOID
  138. IpIpTimerRoutine(
  139. PKDPC Dpc,
  140. PVOID DeferredContext,
  141. PVOID SystemArgument1,
  142. PVOID SystemArgument2
  143. )
  144. /*++
  145. Routine Description:
  146. The DPC routine associated with the timer.
  147. Locks:
  148. Arguments:
  149. Dpc
  150. DeferredContext
  151. SystemArgument1
  152. SystemArgument2
  153. Return Value:
  154. NONE
  155. --*/
  156. {
  157. PLIST_ENTRY pleNode;
  158. LARGE_INTEGER liDueTime;
  159. RtAcquireSpinLockAtDpcLevel(&g_rlStateLock);
  160. if(g_dwDriverState != DRIVER_STARTED)
  161. {
  162. RtReleaseSpinLockFromDpcLevel(&g_rlStateLock);
  163. return;
  164. }
  165. RtReleaseSpinLockFromDpcLevel(&g_rlStateLock);
  166. EnterReaderAtDpcLevel(&g_rwlTunnelLock);
  167. for(pleNode = g_leTunnelList.Flink;
  168. pleNode isnot &g_leTunnelList;
  169. pleNode = pleNode->Flink)
  170. {
  171. PTUNNEL pTunnel;
  172. ULONGLONG ullCurrentTime;
  173. BOOLEAN bChange;
  174. pTunnel = CONTAINING_RECORD(pleNode,
  175. TUNNEL,
  176. leTunnelLink);
  177. //
  178. // Lock, but dont refcount the tunnel.
  179. // The ref is not needed since, we have the tunnel list lock and
  180. // that means the tunnel cant be remove from the list, which keeps
  181. // a refcount for us
  182. //
  183. RtAcquireSpinLockAtDpcLevel(&(pTunnel->rlLock));
  184. if(GetAdminState(pTunnel) isnot IF_ADMIN_STATUS_UP)
  185. {
  186. //
  187. // TODO: maybe we should move admin state under the tunnel list
  188. // lock? Possibly a perf improvement
  189. //
  190. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  191. continue;
  192. }
  193. KeQueryTickCount((PLARGE_INTEGER)&ullCurrentTime);
  194. //
  195. // If the tunnel has a local address and either (i) the counter has
  196. // rolled over or (ii) more than the change period time has passed
  197. // - update its mtu and reachability info
  198. // The change period is different depending on whether the tunnel is
  199. // UP or DOWN
  200. //
  201. if(pTunnel->dwOperState is IF_OPER_STATUS_OPERATIONAL)
  202. {
  203. bChange = ((ullCurrentTime - pTunnel->ullLastChange) >=
  204. SECS_TO_TICKS(UP_TO_DOWN_CHANGE_PERIOD));
  205. }
  206. else
  207. {
  208. bChange = ((ullCurrentTime - pTunnel->ullLastChange) >=
  209. SECS_TO_TICKS(DOWN_TO_UP_CHANGE_PERIOD));
  210. }
  211. if((pTunnel->dwAdminState & TS_ADDRESS_PRESENT) and
  212. ((pTunnel->ullLastChange > ullCurrentTime) or
  213. bChange))
  214. {
  215. #if DBG
  216. Trace(TUNN, INFO,
  217. ("IpIpTimerRoutine: Updating %s\n",
  218. pTunnel->asDebugBindName.Buffer));
  219. #endif
  220. //
  221. // If everything is good, it will set the OperState to up
  222. //
  223. UpdateMtuAndReachability(pTunnel);
  224. }
  225. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  226. }
  227. ExitReaderFromDpcLevel(&g_rwlTunnelLock);
  228. liDueTime = RtlEnlargedUnsignedMultiply(TIMER_IN_MILLISECS,
  229. SYS_UNITS_IN_ONE_MILLISEC);
  230. liDueTime = RtlLargeIntegerNegate(liDueTime);
  231. KeSetTimerEx(&g_ktTimer,
  232. liDueTime,
  233. 0,
  234. &g_kdTimerDpc);
  235. return;
  236. }