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.

635 lines
15 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ripproc.c
  5. Abstract:
  6. RIP processing functions
  7. Author:
  8. Stefan Solomon 09/01/1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. VOID
  14. RipRequest(PWORK_ITEM wip);
  15. VOID
  16. RipResponse(PWORK_ITEM wip);
  17. VOID
  18. StartGenResponse(PICB icbp,
  19. PUCHAR dstnodep,
  20. PUCHAR dstsocket);
  21. ULONG
  22. RouteTimeToLiveSecs(PICB icbp);
  23. /*++
  24. Function: ProcessReceivedPacket
  25. Descr: increments the receive if statistics
  26. does rip processing
  27. Remark: >> called with the if lock held <<
  28. --*/
  29. VOID
  30. ProcessReceivedPacket(PWORK_ITEM wip)
  31. {
  32. USHORT opcode;
  33. PUCHAR hdrp; // ptr to the packet header
  34. PICB icbp;
  35. USHORT pktlen;
  36. icbp = wip->icbp;
  37. // check that the interface is up
  38. if(icbp->IfStats.RipIfOperState != OPER_STATE_UP) {
  39. return;
  40. }
  41. // get a ptr to the packet header
  42. hdrp = wip->Packet;
  43. // check if this is a looped back packet
  44. if(!memcmp(hdrp + IPXH_SRCNODE, icbp->AdapterBindingInfo.LocalNode, 6)) {
  45. return;
  46. }
  47. // update the interface receive statistics
  48. icbp->IfStats.RipIfInputPackets++;
  49. // check the packet length
  50. GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
  51. if(pktlen > MAX_PACKET_LEN) {
  52. // bad length RIP packet
  53. return;
  54. }
  55. // check the RIP operation type
  56. GETSHORT2USHORT(&opcode, hdrp + RIP_OPCODE);
  57. switch(opcode) {
  58. case RIP_REQUEST:
  59. RipRequest(wip);
  60. break;
  61. case RIP_RESPONSE:
  62. RipResponse(wip);
  63. break;
  64. default:
  65. // this is a bad opcode RIP packet
  66. break;
  67. }
  68. }
  69. //***
  70. //
  71. // Function: RipRequest
  72. //
  73. // Descr: process the RIP request
  74. //
  75. // Remark: >> called with the if lock held <<
  76. //
  77. //***
  78. VOID
  79. RipRequest(PWORK_ITEM wip)
  80. {
  81. USHORT reqlen; // offset to get next request
  82. USHORT resplen; // offset to put next response
  83. USHORT pktlen; // packet length
  84. PUCHAR hdrp; // ptr to the received packet header
  85. PUCHAR resphdrp; // ptr to the response packet header
  86. PICB icbp;
  87. USHORT srcsocket;
  88. IPX_ROUTE IpxRoute;
  89. PWORK_ITEM respwip = NULL; // response packet
  90. ULONG network;
  91. icbp = wip->icbp;
  92. Trace(RIP_REQUEST_TRACE, "RipRequest: Entered on if # %d", icbp->InterfaceIndex);
  93. if(icbp->IfConfigInfo.Supply != ADMIN_STATE_ENABLED) {
  94. Trace(RIP_REQUEST_TRACE,
  95. "RIP request discarded on if %d because Supply is DISABLED\n",
  96. icbp->InterfaceIndex);
  97. return;
  98. }
  99. // get a ptr to the packet header
  100. hdrp = wip->Packet;
  101. // get IPX packet length
  102. GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
  103. // if the packet is too long, discard
  104. if(pktlen > MAX_PACKET_LEN) {
  105. Trace(RIP_REQUEST_TRACE,
  106. "RIP request discarded on if %d because the packet size %d > max packet len %d\n",
  107. icbp->InterfaceIndex,
  108. pktlen,
  109. MAX_PACKET_LEN);
  110. return;
  111. }
  112. // We may have one or more network entry requests in the packet.
  113. // If one network entry is 0xFFFFFFFF, then a general RIP response is
  114. // requested.
  115. // for each network entry, try to get the answer from our routing table
  116. for(reqlen = resplen = RIP_INFO;
  117. (reqlen+NE_ENTRYSIZE) <= pktlen;
  118. reqlen += NE_ENTRYSIZE) {
  119. // check if a general response is requested
  120. if(!memcmp(hdrp + reqlen + NE_NETNUMBER, bcastnet, 4)) {
  121. //*** a general response is requested ***
  122. // create the initial general response packet (work item).
  123. // when the send completes for this packet, the work item will
  124. // contain the RTM enumeration handle which is used to continue
  125. // for the creation of the next succesive gen response packets
  126. StartGenResponse(icbp,
  127. hdrp + IPXH_SRCNODE,
  128. hdrp + IPXH_SRCSOCK);
  129. return;
  130. }
  131. //*** a specific response is requested. ***
  132. // allocate a response packet if none allocated yet
  133. if(respwip == NULL) {
  134. if((respwip = AllocateWorkItem(SEND_PACKET_TYPE)) == NULL) {
  135. // give up!
  136. Trace(RIP_REQUEST_TRACE,
  137. "RIP request discarded on if %d because cannot allocate response packet\n",
  138. icbp->InterfaceIndex);
  139. return;
  140. }
  141. else
  142. {
  143. // init the send packet
  144. respwip->icbp = icbp;
  145. respwip->AdapterIndex = icbp->AdapterBindingInfo.AdapterIndex;
  146. resphdrp = respwip->Packet;
  147. }
  148. }
  149. if(IsRoute(hdrp + reqlen + NE_NETNUMBER, &IpxRoute)) {
  150. // check if we can route the packet
  151. // the route should be on a different interface index than the
  152. // received packet. For the global WAN net, the interface index is
  153. // the GLOBAL_INTERFACE_INDEX
  154. if(IsRouteAdvertisable(icbp, &IpxRoute)) {
  155. // we can route it -> answer to it
  156. // fill in the network entry structure in the packet with the
  157. // info from the route entry
  158. SetNetworkEntry(resphdrp + resplen, &IpxRoute, icbp->LinkTickCount);
  159. // increment the response length to the next response entry
  160. resplen += NE_ENTRYSIZE;
  161. }
  162. }
  163. else
  164. {
  165. GETLONG2ULONG(&network, hdrp + reqlen + NE_NETNUMBER);
  166. Trace(RIP_REQUEST_TRACE,
  167. "RIP Request on if %d : Route not found for net %x\n",
  168. icbp->InterfaceIndex,
  169. network);
  170. }
  171. }
  172. // We are done answering this request.
  173. // Check if any response has been generated
  174. if(resplen == RIP_INFO) {
  175. // no response generated for this packet
  176. if(respwip != NULL) {
  177. FreeWorkItem(respwip);
  178. }
  179. return;
  180. }
  181. // set the response packet header (src becomes dest)
  182. SetRipIpxHeader(resphdrp,
  183. icbp, // sets the src&dst net, src node and src socket
  184. hdrp + IPXH_SRCNODE,
  185. hdrp + IPXH_SRCSOCK,
  186. RIP_RESPONSE);
  187. // set the new packet length
  188. PUTUSHORT2SHORT(resphdrp + IPXH_LENGTH, resplen);
  189. // send the response
  190. if(SendSubmit(respwip) != NO_ERROR) {
  191. FreeWorkItem(respwip);
  192. }
  193. }
  194. //***
  195. //
  196. // Function: RipResponse
  197. //
  198. // Descr: Updates the routing table with the response info
  199. //
  200. // Params: Packet
  201. //
  202. // Returns: none
  203. //
  204. // Remark: >> called with the interface lock held <<
  205. //
  206. //***
  207. VOID
  208. RipResponse(PWORK_ITEM wip)
  209. {
  210. PICB icbp;
  211. USHORT resplen; // offset of the next response network entry
  212. USHORT pktlen; // IPX packet length
  213. PUCHAR hdrp; // ptr to the packet header
  214. USHORT nrofhops;
  215. USHORT tickcount;
  216. IPX_ROUTE IpxRoute;
  217. ULONG i;
  218. // get a ptr to this ICB
  219. icbp = wip->icbp;
  220. // check if LISTEN TO RIP UPDATES is enabled on this interface
  221. if(icbp->IfConfigInfo.Listen != ADMIN_STATE_ENABLED) {
  222. Trace(RIP_RESPONSE_TRACE,
  223. "RIP Response on if %d : discard response packet because LISTEN is DISABLED\n",
  224. icbp->InterfaceIndex);
  225. return;
  226. }
  227. // get a ptr to the received response packet header
  228. hdrp = wip->Packet;
  229. // get received response packet length
  230. GETSHORT2USHORT(&pktlen, hdrp + IPXH_LENGTH);
  231. // check the source address of the sender. If different then what is locally
  232. // configured log an error.
  233. if(memcmp(hdrp + IPXH_SRCNET, icbp->AdapterBindingInfo.Network, 4)) {
  234. Trace(RIP_ALERT,
  235. "The router at %.2x%.2x%.2x%.2x%.2x%.2x claims the local interface # %d has network number %.2x%.2x%.2x%.2x !\n",
  236. *(hdrp + IPXH_SRCNODE),
  237. *(hdrp + IPXH_SRCNODE + 1),
  238. *(hdrp + IPXH_SRCNODE + 2),
  239. *(hdrp + IPXH_SRCNODE + 3),
  240. *(hdrp + IPXH_SRCNODE + 4),
  241. *(hdrp + IPXH_SRCNODE + 5),
  242. icbp->InterfaceIndex,
  243. *(hdrp + IPXH_SRCNET),
  244. *(hdrp + IPXH_SRCNET + 1),
  245. *(hdrp + IPXH_SRCNET + 2),
  246. *(hdrp + IPXH_SRCNET + 3));
  247. IF_LOG (EVENTLOG_WARNING_TYPE) {
  248. LPWSTR pname[1] = {icbp->InterfaceName};
  249. RouterLogWarningDataW (RipEventLogHdl,
  250. ROUTERLOG_IPXRIP_LOCAL_NET_NUMBER_CONFLICT,
  251. 1, pname,
  252. 10, hdrp+IPXH_SRCNET);
  253. }
  254. return;
  255. }
  256. // For each network entry:
  257. // chcek if it passes the acceptance filter and if yes:
  258. // add it to our routing table if route not down
  259. // delete it from the routing table if route down
  260. for(resplen = RIP_INFO, i = 0;
  261. ((resplen+NE_ENTRYSIZE) <= pktlen) && (i < 50);
  262. resplen += NE_ENTRYSIZE, i++) {
  263. // check if there is an entry left in the packet
  264. if(resplen + NE_ENTRYSIZE > pktlen) {
  265. Trace(RIP_ALERT, "RipResponse: Invalid length for last network entry in the packet, discard entry!\n");
  266. continue;
  267. }
  268. // check if it passes the acceptance filter
  269. if(!PassRipListenFilter(icbp, hdrp + resplen + NE_NETNUMBER)) {
  270. Trace(RIP_RESPONSE_TRACE,
  271. "RIP Response on if %d : do not accept net %.2x%.2x%.2x%.2x because of LISTEN filter\n",
  272. icbp->InterfaceIndex,
  273. *(hdrp + IPXH_SRCNET),
  274. *(hdrp + IPXH_SRCNET + 1),
  275. *(hdrp + IPXH_SRCNET + 2),
  276. *(hdrp + IPXH_SRCNET + 3));
  277. continue;
  278. }
  279. // check if the network route is up or down
  280. GETSHORT2USHORT(&nrofhops, hdrp + resplen + NE_NROFHOPS);
  281. if(nrofhops < 16) {
  282. // pmay: U270476. Disregard routes with 0 hop count
  283. //
  284. if (nrofhops == 0)
  285. {
  286. continue;
  287. }
  288. // if there is a bogus network number advertised in this packet
  289. // like 0 or FFFFFFFF ignore it.
  290. if(!memcmp(hdrp + resplen + NE_NETNUMBER, nullnet, 4)) {
  291. continue;
  292. }
  293. if(!memcmp(hdrp + resplen + NE_NETNUMBER, bcastnet, 4)) {
  294. continue;
  295. }
  296. // should not accept route for a directly connected net
  297. if(IsRoute(hdrp + resplen + NE_NETNUMBER, &IpxRoute) &&
  298. (IpxRoute.Protocol == IPX_PROTOCOL_LOCAL)) {
  299. continue;
  300. }
  301. // should not accept the route if it has a bad number of ticks
  302. // like 0 or > 60000.
  303. GETSHORT2USHORT(&IpxRoute.TickCount, hdrp + resplen + NE_NROFTICKS);
  304. if((IpxRoute.TickCount == 0) ||
  305. (IpxRoute.TickCount > 60000)) {
  306. continue;
  307. }
  308. // Add (update) this route to the routing table
  309. IpxRoute.InterfaceIndex = icbp->InterfaceIndex;
  310. IpxRoute.Protocol = IPX_PROTOCOL_RIP;
  311. memcpy(IpxRoute.Network, hdrp + resplen + NE_NETNUMBER, 4);
  312. // if this route is learned over a point to point wan, next hop doesn't
  313. // make sense
  314. if(icbp->InterfaceType == PERMANENT) {
  315. memcpy(IpxRoute.NextHopMacAddress, hdrp + IPXH_SRCNODE, 6);
  316. }
  317. else
  318. {
  319. memcpy(IpxRoute.NextHopMacAddress, bcastnode, 6);
  320. }
  321. GETSHORT2USHORT(&IpxRoute.HopCount, hdrp + resplen + NE_NROFHOPS);
  322. if(IpxRoute.HopCount == 15) {
  323. IpxRoute.Flags = DO_NOT_ADVERTISE_ROUTE;
  324. AddRipRoute(&IpxRoute, RouteTimeToLiveSecs(icbp));
  325. }
  326. else
  327. {
  328. IpxRoute.Flags = 0;
  329. // add it to the table
  330. switch(icbp->InterfaceType) {
  331. case REMOTE_WORKSTATION_DIAL:
  332. // this RIP advertisment comes from a remote client
  333. // we should accept it only if this is its internal net and if
  334. // it doesn't conflict with a network we already have
  335. if ((memcmp(icbp->RemoteWkstaInternalNet, nullnet, 4)==0)
  336. || (memcmp(icbp->RemoteWkstaInternalNet, IpxRoute.Network, 4)==0)) {
  337. // none added so far as internal net for this client
  338. if (!IsRoute(IpxRoute.Network, NULL)) {
  339. // we assume this is its internal net and it will be
  340. // cleaned up when interface is disconnected
  341. AddRipRoute(&IpxRoute, INFINITE);
  342. memcpy(icbp->RemoteWkstaInternalNet,
  343. IpxRoute.Network,
  344. 4);
  345. }
  346. }
  347. // do not accept any more advertisments from this client
  348. return;
  349. case LOCAL_WORKSTATION_DIAL:
  350. // the interface is the local host dialed out.
  351. // routes received by it should not be advertised over any
  352. // interface but kept only for internal routing
  353. if (!IsRoute(IpxRoute.Network, NULL)) {
  354. IpxRoute.Flags = DO_NOT_ADVERTISE_ROUTE;
  355. AddRipRoute(&IpxRoute, INFINITE);
  356. }
  357. break;
  358. default:
  359. AddRipRoute(&IpxRoute, RouteTimeToLiveSecs(icbp));
  360. break;
  361. }
  362. }
  363. }
  364. else
  365. {
  366. // Delete this route from the routing table
  367. IpxRoute.InterfaceIndex = icbp->InterfaceIndex;
  368. IpxRoute.Protocol = IPX_PROTOCOL_RIP;
  369. memcpy(IpxRoute.Network, hdrp + resplen + NE_NETNUMBER, 4);
  370. memcpy(IpxRoute.NextHopMacAddress, hdrp + IPXH_SRCNODE, 6);
  371. GETSHORT2USHORT(&IpxRoute.TickCount, hdrp + resplen + NE_NROFTICKS);
  372. GETSHORT2USHORT(&IpxRoute.HopCount, hdrp + resplen + NE_NROFHOPS);
  373. // delete it from the table
  374. DeleteRipRoute(&IpxRoute);
  375. }
  376. }
  377. }
  378. /*++
  379. Function: StartGenResponse
  380. Descr: Creates a work item (packet) of type general response
  381. Creates a RTM enumeration handle
  382. Starts filling in a packet from RTM using split horizon
  383. Sends the packet
  384. --*/
  385. VOID
  386. StartGenResponse(PICB icbp,
  387. PUCHAR dstnodep, // dst node to send gen resp
  388. PUCHAR dstsocket) // dst socket to send gen resp
  389. {
  390. PWORK_ITEM wip;
  391. HANDLE EnumHandle;
  392. PUCHAR hdrp; // gen resp ipx packet header
  393. // allocate a work item
  394. if((wip = AllocateWorkItem(GEN_RESPONSE_PACKET_TYPE)) == NULL) {
  395. return;
  396. }
  397. // init the work item
  398. wip->icbp = icbp;
  399. wip->AdapterIndex = icbp->AdapterBindingInfo.AdapterIndex;
  400. // create an RTM enumeration handle
  401. if((EnumHandle = CreateBestRoutesEnumHandle()) == NULL) {
  402. FreeWorkItem(wip);
  403. return;
  404. }
  405. wip->WorkItemSpecific.WIS_EnumRoutes.RtmEnumerationHandle = EnumHandle;
  406. // make the first gen response packet
  407. if(MakeRipGenResponsePacket(wip,
  408. dstnodep,
  409. dstsocket) == EMPTY_PACKET) {
  410. // no routes to advertise for this general response
  411. CloseEnumHandle(EnumHandle);
  412. FreeWorkItem(wip);
  413. return;
  414. }
  415. // Send the gen response on the associated adapter
  416. if(IfRefSendSubmit(wip) != NO_ERROR) {
  417. // !!!
  418. CloseEnumHandle(EnumHandle);
  419. FreeWorkItem(wip);
  420. }
  421. }
  422. /*++
  423. Function: IfCompleteGenResponse
  424. Descr: Completes the gen response work item either by terminating it
  425. if no more routes to advertise or by
  426. getting the rest of the routes up to one packet and sending
  427. the packet
  428. --*/
  429. VOID
  430. IfCompleteGenResponse(PWORK_ITEM wip)
  431. {
  432. USHORT opcode;
  433. PICB icbp;
  434. HANDLE EnumHandle;
  435. USHORT pktlen;
  436. EnumHandle = wip->WorkItemSpecific.WIS_EnumRoutes.RtmEnumerationHandle;
  437. // first off - check the interface status
  438. icbp = wip->icbp;
  439. GETSHORT2USHORT(&pktlen, wip->Packet + IPXH_LENGTH);
  440. // check that:
  441. // 1. the interface is up
  442. // 2. this was not the last packet in the response
  443. if((icbp->IfStats.RipIfOperState != OPER_STATE_UP) ||
  444. (pktlen < FULL_PACKET)) {
  445. CloseEnumHandle(EnumHandle);
  446. FreeWorkItem(wip);
  447. return;
  448. }
  449. // make the next gen response packet
  450. if(MakeRipGenResponsePacket(wip,
  451. wip->Packet + IPXH_DESTNODE,
  452. wip->Packet + IPXH_DESTSOCK) == EMPTY_PACKET) {
  453. // no more routes to advertise in this gen response
  454. CloseEnumHandle(EnumHandle);
  455. FreeWorkItem(wip);
  456. return;
  457. }
  458. // Send the gen response on the associated adapter
  459. if(IfRefSendSubmit(wip) != NO_ERROR) {
  460. CloseEnumHandle(EnumHandle);
  461. FreeWorkItem(wip);
  462. }
  463. }
  464. ULONG
  465. RouteTimeToLiveSecs(PICB icbp)
  466. {
  467. if(icbp->IfConfigInfo.PeriodicUpdateInterval == MAXULONG) {
  468. return INFINITE;
  469. }
  470. else
  471. {
  472. return (AGE_INTERVAL_MULTIPLIER(icbp)) * (PERIODIC_UPDATE_INTERVAL_SECS(icbp));
  473. }
  474. }