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.

623 lines
11 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. rtmif.c
  5. Abstract:
  6. Contains the RTM interface functions
  7. Author:
  8. Stefan Solomon 07/06/1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. // RTM RIP Client Handle
  14. HANDLE RtmRipHandle;
  15. typedef struct _ROUTE_NODE {
  16. LIST_ENTRY Linkage;
  17. IPX_ROUTE IpxRoute;
  18. } ROUTE_NODE, *PROUTE_NODE;
  19. // List of route nodes with RIP route changes
  20. LIST_ENTRY RipChangedList;
  21. // state of the RipChangedList
  22. BOOL RipChangedListOpen = FALSE;
  23. // Lock for the RIP changed list
  24. CRITICAL_SECTION RipChangedListCritSec;
  25. VOID
  26. AddRouteToRipChangedList(PIPX_ROUTE IpxRoutep);
  27. HANDLE
  28. CreateRipRoutesEnumHandle(ULONG InterfaceIndex);
  29. DWORD
  30. OpenRTM(VOID)
  31. {
  32. // initialize the variables for the RIP changes list
  33. InitializeListHead(&RipChangedList);
  34. RipChangedListOpen = TRUE;
  35. // register as RTM client
  36. if((RtmRipHandle = RtmRegisterClient(RTM_PROTOCOL_FAMILY_IPX,
  37. IPX_PROTOCOL_RIP,
  38. WorkerThreadObjects[RTM_EVENT],
  39. 0)) == NULL) {
  40. return ERROR_CAN_NOT_COMPLETE;
  41. }
  42. else
  43. {
  44. return NO_ERROR;
  45. }
  46. }
  47. VOID
  48. CloseRTM(VOID)
  49. {
  50. PLIST_ENTRY lep;
  51. PROUTE_NODE rnp;
  52. // flush the RIP changed list and destroy its critical section
  53. ACQUIRE_RIP_CHANGED_LIST_LOCK;
  54. while(!IsListEmpty(&RipChangedList))
  55. {
  56. lep = RemoveHeadList(&RipChangedList);
  57. rnp = CONTAINING_RECORD(lep, ROUTE_NODE, Linkage);
  58. GlobalFree(rnp);
  59. }
  60. RipChangedListOpen = FALSE;
  61. RELEASE_RIP_CHANGED_LIST_LOCK;
  62. // deregister as RTM client
  63. RtmDeregisterClient(RtmRipHandle);
  64. }
  65. VOID
  66. RtmToIpxRoute(PIPX_ROUTE IpxRoutep,
  67. PRTM_IPX_ROUTE RtmRoutep)
  68. {
  69. IpxRoutep->InterfaceIndex = (ULONG)(RtmRoutep->R_Interface);
  70. IpxRoutep->Protocol = RtmRoutep->R_Protocol;
  71. PUTULONG2LONG(IpxRoutep->Network, RtmRoutep->R_Network);
  72. IpxRoutep->TickCount = RtmRoutep->R_TickCount;
  73. IpxRoutep->HopCount = RtmRoutep->R_HopCount;
  74. memcpy(IpxRoutep->NextHopMacAddress,
  75. RtmRoutep->R_NextHopMacAddress,
  76. 6);
  77. IpxRoutep->Flags = RtmRoutep->R_Flags;
  78. }
  79. VOID
  80. IpxToRtmRoute(PRTM_IPX_ROUTE RtmRoutep,
  81. PIPX_ROUTE IpxRoutep)
  82. {
  83. RtmRoutep->R_Interface = IpxRoutep->InterfaceIndex;
  84. RtmRoutep->R_Protocol = IpxRoutep->Protocol;
  85. GETLONG2ULONG(&RtmRoutep->R_Network, IpxRoutep->Network);
  86. RtmRoutep->R_TickCount = IpxRoutep->TickCount;
  87. RtmRoutep->R_HopCount = IpxRoutep->HopCount;
  88. memcpy(RtmRoutep->R_NextHopMacAddress,
  89. IpxRoutep->NextHopMacAddress,
  90. 6);
  91. RtmRoutep->R_Flags = IpxRoutep->Flags;
  92. }
  93. /*++
  94. Function: AddRipRoute
  95. Descr: adds a RIP route to RTM
  96. --*/
  97. DWORD
  98. AddRipRoute(PIPX_ROUTE IpxRoutep,
  99. ULONG TimeToLive)
  100. {
  101. DWORD rc = 0;
  102. DWORD flags = 0;
  103. RTM_IPX_ROUTE RtmRoute;
  104. RTM_IPX_ROUTE CurBestRoute;
  105. RTM_IPX_ROUTE PrevBestRoute;
  106. IPX_ROUTE PrevBestIpxRoute;
  107. IpxRoutep->Protocol = IPX_PROTOCOL_RIP;
  108. IpxToRtmRoute(&RtmRoute, IpxRoutep);
  109. if((rc = RtmAddRoute(
  110. RtmRipHandle,
  111. &RtmRoute,
  112. TimeToLive,
  113. &flags,
  114. &CurBestRoute,
  115. &PrevBestRoute)) != NO_ERROR) {
  116. return rc;
  117. }
  118. // check the type of change
  119. switch(flags) {
  120. case RTM_ROUTE_ADDED:
  121. AddRouteToRipChangedList(IpxRoutep);
  122. break;
  123. case RTM_ROUTE_CHANGED:
  124. if(CurBestRoute.R_HopCount == 16) {
  125. if(PrevBestRoute.R_HopCount < 16) {
  126. // advertise that the previous route is down
  127. RtmToIpxRoute(&PrevBestIpxRoute, &PrevBestRoute);
  128. PrevBestIpxRoute.HopCount = 16;
  129. AddRouteToRipChangedList(&PrevBestIpxRoute);
  130. }
  131. }
  132. else
  133. {
  134. if((CurBestRoute.R_TickCount != PrevBestRoute.R_TickCount) ||
  135. (CurBestRoute.R_HopCount != PrevBestRoute.R_HopCount)) {
  136. AddRouteToRipChangedList(IpxRoutep);
  137. }
  138. }
  139. break;
  140. default:
  141. break;
  142. }
  143. return rc;
  144. }
  145. /*++
  146. Function: DeleteRipRoute
  147. Descr: deletes a RIP route from RTM
  148. --*/
  149. DWORD
  150. DeleteRipRoute(PIPX_ROUTE IpxRoutep)
  151. {
  152. DWORD rc;
  153. DWORD flags = 0;
  154. RTM_IPX_ROUTE RtmRoute;
  155. RTM_IPX_ROUTE CurBestRoute;
  156. IPX_ROUTE CurBestIpxRoute;
  157. IpxRoutep->Protocol = IPX_PROTOCOL_RIP;
  158. IpxToRtmRoute(&RtmRoute, IpxRoutep);
  159. if((rc = RtmDeleteRoute(RtmRipHandle,
  160. &RtmRoute,
  161. &flags,
  162. &CurBestRoute
  163. )) != NO_ERROR) {
  164. return rc;
  165. }
  166. switch(flags) {
  167. case RTM_ROUTE_DELETED:
  168. // bcast that we lost the previous route
  169. AddRouteToRipChangedList(IpxRoutep);
  170. break;
  171. case RTM_ROUTE_CHANGED:
  172. // current best route changed
  173. RtmToIpxRoute(&CurBestIpxRoute, &CurBestRoute);
  174. if(CurBestIpxRoute.HopCount == 16) {
  175. // bcast that we lost the previous route
  176. AddRouteToRipChangedList(IpxRoutep);
  177. }
  178. else
  179. {
  180. // bcast that we have a new best route
  181. AddRouteToRipChangedList(&CurBestIpxRoute);
  182. }
  183. break;
  184. default:
  185. break;
  186. }
  187. return rc;
  188. }
  189. /*++
  190. Function: DeleteAllRipRoutes
  191. Descr: deletes all RIP routes for the specified interface
  192. --*/
  193. VOID
  194. DeleteAllRipRoutes(ULONG InterfaceIndex)
  195. {
  196. HANDLE EnumHandle;
  197. IPX_ROUTE IpxRoute;
  198. RTM_IPX_ROUTE RtmCriteriaRoute;
  199. DWORD rc;
  200. Trace(RTM_TRACE, "DeleteAllRipRoutes: Entered for if # %d\n", InterfaceIndex);
  201. // enumerate all the routes for this interface and add them in the rip changed
  202. // list
  203. if((EnumHandle = CreateRipRoutesEnumHandle(InterfaceIndex)) == NULL) {
  204. Trace(RTM_TRACE, "DeleteAllRipRoutes: cannot create enum handle for if # %d\n", InterfaceIndex);
  205. goto DeleteRoutes;
  206. }
  207. while(EnumGetNextRoute(EnumHandle, &IpxRoute) == NO_ERROR)
  208. {
  209. if(IpxRoute.HopCount < 16) {
  210. IpxRoute.HopCount = 16;
  211. AddRouteToRipChangedList(&IpxRoute);
  212. }
  213. }
  214. CloseEnumHandle(EnumHandle);
  215. DeleteRoutes:
  216. // ... and now delete all routes for this interface
  217. memset(&RtmCriteriaRoute,
  218. 0,
  219. sizeof(RTM_IPX_ROUTE));
  220. RtmCriteriaRoute.R_Interface = InterfaceIndex;
  221. RtmCriteriaRoute.R_Protocol = IPX_PROTOCOL_RIP;
  222. rc = RtmBlockDeleteRoutes(RtmRipHandle,
  223. RTM_ONLY_THIS_INTERFACE,
  224. &RtmCriteriaRoute);
  225. Trace(RTM_TRACE, "DeleteAllRipRoutes: RtmBlockDeleteRoutes returned rc=%d for if # %d\n",
  226. rc,
  227. InterfaceIndex);
  228. }
  229. /*++
  230. Function: IsRoute
  231. Descr: returns TRUE if a route to the specified net exists
  232. --*/
  233. BOOL
  234. IsRoute(PUCHAR Network,
  235. PIPX_ROUTE IpxRoutep)
  236. {
  237. DWORD RtmNetwork;
  238. RTM_IPX_ROUTE RtmRoute;
  239. GETLONG2ULONG(&RtmNetwork, Network);
  240. if(RtmIsRoute(RTM_PROTOCOL_FAMILY_IPX,
  241. &RtmNetwork,
  242. &RtmRoute)) {
  243. if (IpxRoutep!=NULL)
  244. RtmToIpxRoute(IpxRoutep, &RtmRoute);
  245. return TRUE;
  246. }
  247. else
  248. {
  249. return FALSE;
  250. }
  251. }
  252. //***********************************************************************
  253. // *
  254. // Fast Enumeration Functions *
  255. // *
  256. //***********************************************************************
  257. HANDLE
  258. CreateBestRoutesEnumHandle(VOID)
  259. {
  260. HANDLE EnumHandle;
  261. RTM_IPX_ROUTE CriteriaRoute;
  262. EnumHandle = RtmCreateEnumerationHandle(RTM_PROTOCOL_FAMILY_IPX,
  263. RTM_ONLY_BEST_ROUTES,
  264. &CriteriaRoute);
  265. return EnumHandle;
  266. }
  267. DWORD
  268. EnumGetNextRoute(HANDLE EnumHandle,
  269. PIPX_ROUTE IpxRoutep)
  270. {
  271. RTM_IPX_ROUTE RtmRoute;
  272. DWORD rc;
  273. rc = RtmEnumerateGetNextRoute(EnumHandle,
  274. &RtmRoute);
  275. if (rc == NO_ERROR)
  276. {
  277. RtmToIpxRoute(IpxRoutep, &RtmRoute);
  278. }
  279. return rc;
  280. }
  281. VOID
  282. CloseEnumHandle(HANDLE EnumHandle)
  283. {
  284. RtmCloseEnumerationHandle(EnumHandle);
  285. }
  286. HANDLE
  287. CreateRipRoutesEnumHandle(ULONG InterfaceIndex)
  288. {
  289. RTM_IPX_ROUTE EnumCriteriaRoute;
  290. HANDLE EnumHandle;
  291. memset(&EnumCriteriaRoute, 0, sizeof(RTM_IPX_ROUTE));
  292. EnumCriteriaRoute.R_Interface = InterfaceIndex;
  293. EnumCriteriaRoute.R_Protocol = IPX_PROTOCOL_RIP;
  294. EnumHandle = RtmCreateEnumerationHandle(RTM_PROTOCOL_FAMILY_IPX,
  295. RTM_ONLY_BEST_ROUTES | RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL,
  296. &EnumCriteriaRoute);
  297. return EnumHandle;
  298. }
  299. /*++
  300. Function: GetRipRoutesCount
  301. Descr: returns the number of rip routes associated with this interface
  302. --*/
  303. ULONG
  304. GetRipRoutesCount(ULONG InterfaceIndex)
  305. {
  306. HANDLE EnumHandle;
  307. ULONG RipRoutesCount = 0;
  308. IPX_ROUTE IpxRoute;
  309. if((EnumHandle = CreateRipRoutesEnumHandle(InterfaceIndex)) == NULL) {
  310. return 0;
  311. }
  312. while(EnumGetNextRoute(EnumHandle, &IpxRoute) == NO_ERROR)
  313. {
  314. RipRoutesCount++;
  315. }
  316. CloseEnumHandle(EnumHandle);
  317. return RipRoutesCount;
  318. }
  319. /*++
  320. Function: DequeueRouteChangeFromRip
  321. Descr:
  322. Remark: >> called with the database & queues lock held <<
  323. --*/
  324. DWORD
  325. DequeueRouteChangeFromRip(PIPX_ROUTE IpxRoutep)
  326. {
  327. PLIST_ENTRY lep;
  328. PROUTE_NODE rnp;
  329. if(!IsListEmpty(&RipChangedList)) {
  330. lep = RemoveHeadList(&RipChangedList);
  331. rnp = CONTAINING_RECORD(lep, ROUTE_NODE, Linkage);
  332. *IpxRoutep = rnp->IpxRoute;
  333. GlobalFree(rnp);
  334. return NO_ERROR;
  335. }
  336. else
  337. {
  338. return ERROR_NO_MORE_ITEMS;
  339. }
  340. }
  341. /*++
  342. Function: DequeueRouteChangeFromRtm
  343. Descr:
  344. Remark: >> called with the database locks held <<
  345. --*/
  346. DWORD
  347. DequeueRouteChangeFromRtm(PIPX_ROUTE IpxRoutep,
  348. PBOOL skipitp,
  349. PBOOL lastmessagep)
  350. {
  351. RTM_IPX_ROUTE CurBestRoute, PrevBestRoute;
  352. DWORD Flags = 0;
  353. DWORD rc;
  354. *skipitp = FALSE;
  355. *lastmessagep = FALSE;
  356. rc = RtmDequeueRouteChangeMessage(RtmRipHandle,
  357. &Flags,
  358. &CurBestRoute,
  359. &PrevBestRoute);
  360. switch(rc) {
  361. case NO_ERROR:
  362. *lastmessagep = TRUE;
  363. break;
  364. case ERROR_MORE_MESSAGES:
  365. break;
  366. default:
  367. return ERROR_NO_MORE_ITEMS;
  368. }
  369. switch(Flags) {
  370. case RTM_ROUTE_ADDED:
  371. RtmToIpxRoute(IpxRoutep, &CurBestRoute);
  372. break;
  373. case RTM_ROUTE_DELETED:
  374. RtmToIpxRoute(IpxRoutep, &PrevBestRoute);
  375. IpxRoutep->HopCount = 16;
  376. break;
  377. case RTM_ROUTE_CHANGED:
  378. // if there was a change in metric advertise it.
  379. // Else, ignore it.
  380. if(CurBestRoute.R_TickCount != PrevBestRoute.R_TickCount) {
  381. RtmToIpxRoute(IpxRoutep, &CurBestRoute);
  382. }
  383. else
  384. {
  385. *skipitp = TRUE;
  386. }
  387. break;
  388. default:
  389. *skipitp = TRUE;
  390. break;
  391. }
  392. return NO_ERROR;
  393. }
  394. VOID
  395. AddRouteToRipChangedList(PIPX_ROUTE IpxRoutep)
  396. {
  397. PROUTE_NODE rnp;
  398. if((rnp = GlobalAlloc(GPTR, sizeof(ROUTE_NODE))) == NULL) {
  399. return;
  400. }
  401. rnp->IpxRoute = *IpxRoutep;
  402. ACQUIRE_RIP_CHANGED_LIST_LOCK;
  403. if(!RipChangedListOpen) {
  404. GlobalFree(rnp);
  405. }
  406. else
  407. {
  408. InsertTailList(&RipChangedList, &rnp->Linkage);
  409. SetEvent(WorkerThreadObjects[RIP_CHANGES_EVENT]);
  410. }
  411. RELEASE_RIP_CHANGED_LIST_LOCK;
  412. }
  413. BOOL
  414. IsDuplicateBestRoute(PICB icbp,
  415. PIPX_ROUTE IpxRoutep)
  416. {
  417. RTM_IPX_ROUTE RtmRoute;
  418. DWORD rc;
  419. GETLONG2ULONG(&RtmRoute.R_Network, IpxRoutep->Network);
  420. RtmRoute.R_Interface = icbp->InterfaceIndex;
  421. rc = RtmGetFirstRoute(
  422. RTM_PROTOCOL_FAMILY_IPX,
  423. RTM_ONLY_THIS_NETWORK | RTM_ONLY_THIS_INTERFACE,
  424. &RtmRoute);
  425. // check if it has the same metric
  426. if((rc == NO_ERROR) &&
  427. ((USHORT)(RtmRoute.R_TickCount) == IpxRoutep->TickCount)) {
  428. // duplicate !
  429. return TRUE;
  430. }
  431. else
  432. {
  433. return FALSE;
  434. }
  435. }