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.

380 lines
10 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\rtm\rtm.c
  5. Abstract:
  6. Routing Table Manager DLL. Helper routines
  7. Author:
  8. Vadim Eydelman
  9. Revision History:
  10. --*/
  11. #include "pchrtm.h"
  12. #pragma hdrstop
  13. // Initializes sync list object
  14. VOID
  15. InitializeSyncList (
  16. PRTM_SYNC_LIST list
  17. ) {
  18. list->RSL_Sync = NULL;
  19. list->RSL_UseCount = 0;
  20. InitializeListHead (&list->RSL_Head);
  21. }
  22. // Get mutually exclusive access to the sync list obect
  23. // Returns TRUE if access if obtained, FALSE otherwise
  24. BOOLEAN
  25. DoEnterSyncList (
  26. PRTM_TABLE table, // Table this list belongs to
  27. PRTM_SYNC_LIST list, // List of interest
  28. BOOLEAN wait // True if caller wants to wait
  29. // until list becomes available
  30. #if DBG
  31. , LPSTR file,
  32. ULONG line
  33. #endif
  34. ) {
  35. DWORD status; // Status of OS calls
  36. BOOLEAN result; // Result of operation
  37. EnterCriticalSection (&table->RT_Lock);
  38. // Protect manipilation by table-wide critical section
  39. #if DBG
  40. IF_DEBUG (SYNCHRONIZATION)
  41. Trace4 (ANY, "%08lx (%s,%ld) - trying to enter sync list: %08x\n",
  42. GetCurrentThreadId (), file, line, (ULONG_PTR)list);
  43. #endif
  44. if (list->RSL_UseCount<=0) {
  45. // Nobody uses the list -> get it and return ok
  46. list->RSL_UseCount = 1;
  47. #if DBG
  48. IF_DEBUG (SYNCHRONIZATION)
  49. Trace0 (ANY, "\t - first to enter\n");
  50. #endif
  51. result = TRUE;
  52. }
  53. else if (wait) { // Somebody is using it, but caller agrees to wait
  54. list->RSL_UseCount += 1; // Increment usage count
  55. #if DBG
  56. IF_DEBUG (SYNCHRONIZATION)
  57. Trace1 (ANY, "\t - list in use: %d\n", list->RSL_UseCount);
  58. #endif
  59. if (list->RSL_Sync==NULL) { // if there is no event to wait on,
  60. // get one
  61. // First see if one is available
  62. // in the stack
  63. PSINGLE_LIST_ENTRY cur = PopEntryList (&table->RT_SyncObjectList);
  64. #if DBG
  65. IF_DEBUG (SYNCHRONIZATION)
  66. Trace0 (ANY, "\t - need event\n");
  67. #endif
  68. if (cur==NULL) { // No, we'll have to create one
  69. PRTM_SYNC_OBJECT sync;
  70. sync = (PRTM_SYNC_OBJECT)GlobalAlloc (
  71. GMEM_FIXED,
  72. sizeof (RTM_SYNC_OBJECT));
  73. if (sync==NULL) {
  74. #if DBG
  75. Trace2 (ANY,
  76. "Can't allocate synchronization object.\n"
  77. "\tat line %ld of %s\n",
  78. __LINE__, __FILE__);
  79. #endif
  80. list->RSL_UseCount -= 1;
  81. LeaveCriticalSection (&table->RT_Lock);
  82. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  83. return FALSE;
  84. }
  85. sync->RSO_Event = CreateEvent (NULL,
  86. FALSE, // Auto reset event
  87. FALSE, // Initially nonsignaled
  88. NULL);
  89. if (sync->RSO_Event==NULL) {
  90. status = GetLastError ();
  91. #if DBG
  92. Trace2 (ANY,
  93. "Can't allocate synchronization event.\n"
  94. "\tat line %ld of %s\n",
  95. __LINE__, __FILE__);
  96. #endif
  97. list->RSL_UseCount -= 1;
  98. GlobalFree (sync);
  99. LeaveCriticalSection (&table->RT_Lock);
  100. SetLastError (status);
  101. return FALSE;
  102. }
  103. list->RSL_Sync = sync;
  104. #if DBG
  105. IF_DEBUG (SYNCHRONIZATION)
  106. Trace0 (ANY, "\t - event created\n");
  107. #endif
  108. }
  109. else { // Yes, make sure it is reset
  110. list->RSL_Sync = CONTAINING_RECORD (cur, RTM_SYNC_OBJECT, RSO_Link);
  111. // Autoreset event gets reset after releasing a thread anyway
  112. // status = ResetEvent (list->RSL_Sync->RSO_Event);
  113. // ASSERTERRMSG ("Can't reset event.", status);
  114. }
  115. }
  116. // Now as we set up the object to wait, we can leave critical
  117. // section and wait on event
  118. LeaveCriticalSection (&table->RT_Lock);
  119. status = WaitForSingleObject (
  120. list->RSL_Sync->RSO_Event,
  121. INFINITE
  122. );
  123. ASSERTERRMSG ("Wait event failed.", status==WAIT_OBJECT_0);
  124. // Event is signaled, we may now access the list (auto reset event
  125. // releases only one thread
  126. EnterCriticalSection (&table->RT_Lock);
  127. #if DBG
  128. IF_DEBUG (SYNCHRONIZATION)
  129. Trace1 (ANY, "%08lx - wait completed\n", GetCurrentThreadId ());
  130. #endif
  131. // If our caller was the only one waiting,
  132. // we can release the event
  133. if (list->RSL_UseCount==1) {
  134. #if DBG
  135. IF_DEBUG (SYNCHRONIZATION)
  136. Trace0 (ANY, "\t - restocking event\n");
  137. #endif
  138. PushEntryList (&table->RT_SyncObjectList, &list->RSL_Sync->RSO_Link);
  139. list->RSL_Sync = NULL;
  140. }
  141. result = TRUE;
  142. }
  143. else {
  144. // Caller does not want to wait
  145. result = FALSE;
  146. #if DBG
  147. IF_DEBUG (SYNCHRONIZATION)
  148. Trace0 (ANY, "\t - doesn't want to wait\n");
  149. #endif
  150. }
  151. LeaveCriticalSection (&table->RT_Lock);
  152. return result;
  153. }
  154. // Release previously owned sync list object
  155. VOID
  156. LeaveSyncList (
  157. PRTM_TABLE table, // Table to which this object belongs
  158. PRTM_SYNC_LIST list // List to release
  159. ) {
  160. DWORD status;
  161. EnterCriticalSection (&table->RT_Lock);
  162. #if DBG
  163. IF_DEBUG (SYNCHRONIZATION)
  164. Trace2 (ANY, "%08lx - leaving sync list: %08x\n",
  165. GetCurrentThreadId (), (ULONG_PTR)list);
  166. #endif
  167. // Decrement the count and signal the event (only one thread
  168. // will be released for the auto-reset events
  169. list->RSL_UseCount -= 1;
  170. if (list->RSL_UseCount>0) {
  171. #if DBG
  172. IF_DEBUG (SYNCHRONIZATION)
  173. Trace1 (ANY, "%\t - releasing one of %d waiting threads\n",
  174. list->RSL_UseCount);
  175. #endif
  176. status = SetEvent (list->RSL_Sync->RSO_Event);
  177. ASSERTERRMSG ("Can't signal event.", status);
  178. }
  179. LeaveCriticalSection (&table->RT_Lock);
  180. }
  181. // Finds list of routes that are associated with given interface and returns
  182. // pointer to its head
  183. // Creates new list of none exists yet
  184. PLIST_ENTRY
  185. FindInterfaceList (
  186. PRTM_SYNC_LIST intfHash,
  187. DWORD InterfaceID, // Interface to look for
  188. BOOL CreateNew
  189. ) {
  190. PRTM_INTERFACE_NODE intfNode;
  191. PLIST_ENTRY cur;
  192. // First try to find existing one in the list of interface lists
  193. cur = intfHash->RSL_Head.Flink;
  194. while (cur!=&intfHash->RSL_Head) {
  195. intfNode = CONTAINING_RECORD (cur, RTM_INTERFACE_NODE, IN_Link);
  196. if (InterfaceID<=intfNode->IN_InterfaceID) // List is ordered
  197. // so we can stop
  198. // if bigger number is reached
  199. break;
  200. cur = cur->Flink;
  201. }
  202. if ((cur==&intfHash->RSL_Head)
  203. || (InterfaceID!=intfNode->IN_InterfaceID)) { // Create new interface
  204. // list
  205. if (!CreateNew)
  206. return NULL;
  207. intfNode = (PRTM_INTERFACE_NODE)GlobalAlloc (
  208. GMEM_FIXED,
  209. sizeof (RTM_INTERFACE_NODE));
  210. if (intfNode==NULL) {
  211. #if DBG
  212. // Report error in debuging builds
  213. Trace2 (ANY,
  214. "Can't allocate interface node\n\tat line %ld of %s\n",
  215. __LINE__, __FILE__);
  216. #endif
  217. return NULL;
  218. }
  219. intfNode->IN_InterfaceID = InterfaceID;
  220. InitializeListHead (&intfNode->IN_Head); // Insert it in
  221. // list of interface lists
  222. InsertTailList (cur, &intfNode->IN_Link);
  223. }
  224. return &intfNode->IN_Head;
  225. }
  226. #if RTM_USE_PROTOCOL_LISTS
  227. // Finds list of routes that are associated with given iprotocol and returns
  228. // pointer to its head
  229. // Creates new list of none exists yet
  230. PLIST_ENTRY
  231. FindProtocolList (
  232. PRTM_TABLE Table,
  233. DWORD RoutingProtocol,
  234. BOOL CreateNew
  235. ) {
  236. PRTM_PROTOCOL_NODE protNode;
  237. PLIST_ENTRY cur;
  238. cur = Table->RT_ProtocolList.RSL_Head.Flink;
  239. while (cur!=&Table->RT_ProtocolList.RSL_Head) {
  240. protNode = CONTAINING_RECORD (cur, RTM_PROTOCOL_NODE, PN_Link);
  241. if (RoutingProtocol<=protNode->PN_RoutingProtocol)
  242. break;
  243. cur = cur->Flink;
  244. }
  245. if ((cur==&Table->RT_ProtocolList.RSL_Head)
  246. || (RoutingProtocol!=protNode->PN_RoutingProtocol)) {
  247. if (!CreateNew)
  248. return NULL;
  249. protNode = (PRTM_PROTOCOL_NODE)GlobalAlloc (
  250. GMEM_FIXED,
  251. sizeof (RTM_PROTOCOL_NODE));
  252. if (protNode==NULL) {
  253. #if DBG
  254. // Report error in debuging builds
  255. Trace2 (ANY,
  256. "Can't allocate protocol node\n\tat line %ld of %s\n",
  257. __LINE__, __FILE__);
  258. #endif
  259. return NULL;
  260. }
  261. protNode->PN_RoutingProtocol = RoutingProtocol;
  262. InitializeListHead (&protNode->PN_Head);
  263. InsertTailList (cur, &protNode->PN_Link);
  264. }
  265. return &protNode->PN_Head;
  266. }
  267. #endif
  268. // Adds node to temporary net number list (to be later merged with master list)
  269. // Both lists are ordered by net number.interface.protocol.next hop address
  270. VOID
  271. AddNetNumberListNode (
  272. PRTM_TABLE Table,
  273. PRTM_ROUTE_NODE newNode
  274. ) {
  275. PLIST_ENTRY cur;
  276. INT res;
  277. cur = Table->RT_NetNumberTempList.RSL_Head.Flink;
  278. while (cur!=&Table->RT_NetNumberTempList.RSL_Head) {
  279. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  280. cur,
  281. RTM_ROUTE_NODE,
  282. RN_Links[RTM_NET_NUMBER_LIST_LINK]
  283. );
  284. res = NetNumCmp (Table, &newNode->RN_Route, &node->RN_Route);
  285. if ((res<0)
  286. ||((res==0)
  287. &&((newNode->RN_Route.XX_PROTOCOL
  288. < node->RN_Route.XX_PROTOCOL)
  289. ||((newNode->RN_Route.XX_PROTOCOL
  290. ==node->RN_Route.XX_PROTOCOL)
  291. &&((newNode->RN_Route.XX_INTERFACE
  292. < node->RN_Route.XX_INTERFACE)
  293. ||((newNode->RN_Route.XX_INTERFACE
  294. == node->RN_Route.XX_INTERFACE)
  295. && (NextHopCmp (Table, &newNode->RN_Route,
  296. &node->RN_Route)
  297. < 0)))))))
  298. break;
  299. cur = cur->Flink;
  300. }
  301. InsertTailList (cur, &newNode->RN_Links[RTM_NET_NUMBER_LIST_LINK]);
  302. }
  303. // Adds node to expiration time queue. (Queue is ordered by expiration time)
  304. // Return TRUE if new node is the first in the queue
  305. BOOL
  306. AddExpirationQueueNode (
  307. PRTM_TABLE Table,
  308. PRTM_ROUTE_NODE newNode
  309. ) {
  310. PLIST_ENTRY cur;
  311. BOOL res = TRUE;
  312. // We'll travers the queue from the back, because normally
  313. // new entries are added closer the end of the queue
  314. cur = Table->RT_ExpirationQueue.RSL_Head.Blink;
  315. while (cur!=&Table->RT_ExpirationQueue.RSL_Head) {
  316. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  317. cur,
  318. RTM_ROUTE_NODE,
  319. RN_Links[RTM_EXPIRATION_QUEUE_LINK]
  320. );
  321. if (IsLater(newNode->RN_ExpirationTime, node->RN_ExpirationTime)) {
  322. res = FALSE;
  323. break;
  324. }
  325. cur = cur->Blink;
  326. }
  327. InsertHeadList (cur, &newNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK]);
  328. return res;
  329. }