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.

1814 lines
44 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\routing\ip\rtrmgr\rtrdisc.c
  5. Abstract:
  6. Router Discover code
  7. Revision History:
  8. Amritansh Raghav 20th March 1996 Created
  9. --*/
  10. #include "allinc.h"
  11. VOID
  12. DeleteSockets(
  13. IN PICB picb
  14. );
  15. VOID
  16. InitializeRouterDiscoveryInfo(
  17. IN PICB picb,
  18. IN PRTR_INFO_BLOCK_HEADER pInfoHdr
  19. )
  20. /*++
  21. Routine Description
  22. Sets router discovery information passed in the ICB. If none is passed,
  23. sets to RFC 1256 defaults
  24. Locks
  25. Must be called with ICB_LIST lock held as WRITER
  26. Arguments
  27. picb The ICB of the interface for whom the router discovery
  28. related variables have to be set
  29. Return Value
  30. None
  31. --*/
  32. {
  33. PROUTER_DISC_CB pDiscCb;
  34. PRTR_DISC_INFO pInfo = NULL;
  35. PRTR_TOC_ENTRY pToc;
  36. LONG lMilliSec;
  37. TraceEnter("InitializeRouterDiscovery");
  38. pToc = GetPointerToTocEntry(IP_ROUTER_DISC_INFO,
  39. pInfoHdr);
  40. if(!pToc)
  41. {
  42. //
  43. // Leave things as they are
  44. //
  45. TraceLeave("InitializeRouterDiscoveryInfo");
  46. return;
  47. }
  48. pDiscCb = &picb->rdcRtrDiscInfo;
  49. //
  50. // First set everything to defaults, then if any info is valid, reset
  51. // those fields
  52. //
  53. pDiscCb->wMaxAdvtInterval = DEFAULT_MAX_ADVT_INTERVAL;
  54. pDiscCb->lPrefLevel = DEFAULT_PREF_LEVEL;
  55. pDiscCb->dwNumAdvtsSent = pDiscCb->dwNumSolicitationsSeen = 0;
  56. pDiscCb->liMaxMinDiff.HighPart =
  57. pDiscCb->liMaxMinDiff.LowPart = 0;
  58. pDiscCb->liMinAdvtIntervalInSysUnits.HighPart =
  59. pDiscCb->liMinAdvtIntervalInSysUnits.LowPart = 0;
  60. pDiscCb->pRtrDiscSockets = NULL;
  61. //
  62. // RFC 1256 says default should be true, so there will be traffic on the
  63. // net if the user does not explicitly set this to false. We diverge from
  64. // the RFC and default to FALSE
  65. //
  66. pDiscCb->bAdvertise = FALSE;
  67. pDiscCb->bActive = FALSE;
  68. if(pToc and (pToc->InfoSize > 0) and (pToc->Count > 0))
  69. {
  70. pInfo = (PRTR_DISC_INFO) GetInfoFromTocEntry(pInfoHdr,pToc);
  71. if(pInfo isnot NULL)
  72. {
  73. //
  74. // Ok, so we were passed some info
  75. //
  76. if((pInfo->wMaxAdvtInterval >= MIN_MAX_ADVT_INTERVAL) and
  77. (pInfo->wMaxAdvtInterval <= MAX_MAX_ADVT_INTERVAL))
  78. {
  79. pDiscCb->wMaxAdvtInterval = pInfo->wMaxAdvtInterval;
  80. }
  81. if((pInfo->wMinAdvtInterval >= MIN_MIN_ADVT_INTERVAL) and
  82. (pInfo->wMinAdvtInterval <= pDiscCb->wMaxAdvtInterval))
  83. {
  84. pDiscCb->liMinAdvtIntervalInSysUnits = SecsToSysUnits(pInfo->wMinAdvtInterval);
  85. }
  86. else
  87. {
  88. lMilliSec = (LONG)(DEFAULT_MIN_ADVT_INTERVAL_RATIO * pDiscCb->wMaxAdvtInterval * 1000);
  89. pDiscCb->liMinAdvtIntervalInSysUnits = RtlEnlargedIntegerMultiply(lMilliSec,10000);
  90. }
  91. if((pInfo->wAdvtLifetime >= pDiscCb->wMaxAdvtInterval) and
  92. (pInfo->wAdvtLifetime <= MAX_ADVT_LIFETIME))
  93. {
  94. pDiscCb->wAdvtLifetime = pInfo->wAdvtLifetime;
  95. }
  96. else
  97. {
  98. pDiscCb->wAdvtLifetime = DEFAULT_ADVT_LIFETIME_RATIO * pDiscCb->wMaxAdvtInterval;
  99. }
  100. pDiscCb->bAdvertise = pInfo->bAdvertise;
  101. pDiscCb->lPrefLevel = pInfo->lPrefLevel;
  102. }
  103. }
  104. if(pInfo is NULL)
  105. {
  106. //
  107. // default case, in case no router disc. info. is specified.
  108. //
  109. lMilliSec = (LONG)(DEFAULT_MIN_ADVT_INTERVAL_RATIO * pDiscCb->wMaxAdvtInterval * 1000);
  110. pDiscCb->liMinAdvtIntervalInSysUnits = RtlEnlargedIntegerMultiply(lMilliSec,10000);
  111. pDiscCb->wAdvtLifetime = DEFAULT_ADVT_LIFETIME_RATIO * pDiscCb->wMaxAdvtInterval;
  112. }
  113. pDiscCb->liMaxMinDiff = RtlLargeIntegerSubtract(SecsToSysUnits(pDiscCb->wMaxAdvtInterval),
  114. pDiscCb->liMinAdvtIntervalInSysUnits);
  115. TraceLeave("InitializeRouterDiscovery");
  116. }
  117. VOID
  118. SetRouterDiscoveryInfo(
  119. IN PICB picb,
  120. IN PRTR_INFO_BLOCK_HEADER pInfoHdr
  121. )
  122. /*++
  123. Routine Description
  124. Sets router discovery information passed in the ICB. If none is passed,
  125. sets to RFC 1256 defaults
  126. Locks
  127. Must be called with ICB_LIST lock held as WRITER
  128. Arguments
  129. picb The ICB of the interface for whom the router discovery related
  130. variables have to be set
  131. pInfoHdr Interface Info header
  132. Return Value
  133. None
  134. --*/
  135. {
  136. PROUTER_DISC_CB pDiscCb;
  137. PRTR_DISC_INFO pInfo;
  138. PRTR_TOC_ENTRY pToc;
  139. LONG lMilliSec;
  140. BOOL bOriginalStatus;
  141. TraceEnter("SetRouterDiscoveryInfo");
  142. pDiscCb = &picb->rdcRtrDiscInfo;
  143. pToc = GetPointerToTocEntry(IP_ROUTER_DISC_INFO,
  144. pInfoHdr);
  145. if(!pToc)
  146. {
  147. //
  148. // Leave things as they are
  149. //
  150. TraceLeave("SetRouterDiscoveryInfo");
  151. return;
  152. }
  153. pInfo = (PRTR_DISC_INFO) GetInfoFromTocEntry(pInfoHdr,pToc);
  154. bOriginalStatus = pDiscCb->bAdvertise;
  155. if((pToc->InfoSize is 0) or (pInfo is NULL))
  156. {
  157. //
  158. // If the size is zero, stop advertising
  159. //
  160. DeActivateRouterDiscovery(picb);
  161. //
  162. // Instead of returning, we go through and set defaults so that the info
  163. // looks good when someone does a get info
  164. //
  165. }
  166. //
  167. // First set everything to defaults, then if any info is valid, reset
  168. // those fields
  169. //
  170. pDiscCb->wMaxAdvtInterval = DEFAULT_MAX_ADVT_INTERVAL;
  171. pDiscCb->lPrefLevel = DEFAULT_PREF_LEVEL;
  172. //
  173. // We reset the counters
  174. //
  175. pDiscCb->dwNumAdvtsSent = pDiscCb->dwNumSolicitationsSeen = 0;
  176. pDiscCb->liMaxMinDiff.HighPart =
  177. pDiscCb->liMaxMinDiff.LowPart = 0;
  178. pDiscCb->liMinAdvtIntervalInSysUnits.HighPart =
  179. pDiscCb->liMinAdvtIntervalInSysUnits.LowPart = 0;
  180. //
  181. // We DONT mess with the sockets
  182. //
  183. if((pToc->InfoSize) and (pInfo isnot NULL))
  184. {
  185. if(!pInfo->bAdvertise)
  186. {
  187. DeActivateRouterDiscovery(picb);
  188. }
  189. if((pInfo->wMaxAdvtInterval > MIN_MAX_ADVT_INTERVAL) and
  190. (pInfo->wMaxAdvtInterval < MAX_MAX_ADVT_INTERVAL))
  191. {
  192. pDiscCb->wMaxAdvtInterval = pInfo->wMaxAdvtInterval;
  193. }
  194. if((pInfo->wMinAdvtInterval > MIN_MIN_ADVT_INTERVAL) and
  195. (pInfo->wMinAdvtInterval < pDiscCb->wMaxAdvtInterval))
  196. {
  197. pDiscCb->liMinAdvtIntervalInSysUnits =
  198. SecsToSysUnits(pInfo->wMinAdvtInterval);
  199. }
  200. else
  201. {
  202. lMilliSec = (LONG)(DEFAULT_MIN_ADVT_INTERVAL_RATIO * pDiscCb->wMaxAdvtInterval * 1000);
  203. pDiscCb->liMinAdvtIntervalInSysUnits =
  204. RtlEnlargedIntegerMultiply(lMilliSec,10000);
  205. }
  206. if((pInfo->wAdvtLifetime > pDiscCb->wMaxAdvtInterval) and
  207. (pInfo->wAdvtLifetime < MAX_ADVT_LIFETIME))
  208. {
  209. pDiscCb->wAdvtLifetime = pInfo->wAdvtLifetime;
  210. }
  211. else
  212. {
  213. pDiscCb->wAdvtLifetime =
  214. DEFAULT_ADVT_LIFETIME_RATIO * pDiscCb->wMaxAdvtInterval;
  215. }
  216. pDiscCb->bAdvertise = pInfo->bAdvertise;
  217. pDiscCb->lPrefLevel = pInfo->lPrefLevel;
  218. }
  219. else
  220. {
  221. lMilliSec = (LONG)(DEFAULT_MIN_ADVT_INTERVAL_RATIO * pDiscCb->wMaxAdvtInterval * 1000);
  222. pDiscCb->liMinAdvtIntervalInSysUnits =
  223. RtlEnlargedIntegerMultiply(lMilliSec,10000);
  224. pDiscCb->wAdvtLifetime =
  225. DEFAULT_ADVT_LIFETIME_RATIO * pDiscCb->wMaxAdvtInterval;
  226. }
  227. if(pDiscCb->bAdvertise is TRUE)
  228. {
  229. if(bOriginalStatus is FALSE)
  230. {
  231. //
  232. // If we were originally not advertising but are advertising now,
  233. // then start router discovery
  234. //
  235. ActivateRouterDiscovery(picb);
  236. }
  237. else
  238. {
  239. //
  240. // Else just update the fields in the advertisement
  241. //
  242. UpdateAdvertisement(picb);
  243. }
  244. }
  245. TraceLeave("SetRouterDiscoveryInfo");
  246. }
  247. DWORD
  248. GetInterfaceRouterDiscoveryInfo(
  249. PICB picb,
  250. PRTR_TOC_ENTRY pToc,
  251. PBYTE pbDataPtr,
  252. PRTR_INFO_BLOCK_HEADER pInfoHdr,
  253. PDWORD pdwSize
  254. )
  255. /*++
  256. Routine Description
  257. Gets router discovery information related to an interface
  258. Locks
  259. Called with ICB_LIST lock held as READER
  260. Arguments
  261. picb The ICB of the interface whose router discovery information is
  262. being retrieved
  263. pToc Pointer to TOC for router discovery info
  264. pbDataPtr Pointer to start of data buffer
  265. pInfoHdr Pointer to the header of the whole info
  266. pdwSize [IN] Size of data buffer
  267. [OUT] Size of buffer consumed
  268. Return Value
  269. --*/
  270. {
  271. PRTR_DISC_INFO pInfo;
  272. DWORD dwRem;
  273. LARGE_INTEGER liQuotient;
  274. TraceEnter("GetInterfaceRouterDiscoveryInfo");
  275. if(*pdwSize < sizeof(RTR_DISC_INFO))
  276. {
  277. *pdwSize = sizeof(RTR_DISC_INFO);
  278. TraceLeave("GetInterfaceRouterDiscoveryInfo");
  279. return ERROR_INSUFFICIENT_BUFFER;
  280. }
  281. *pdwSize = pToc->InfoSize = sizeof(RTR_DISC_INFO);
  282. //pToc->InfoVersion = IP_ROUTER_DISC_INFO;
  283. pToc->InfoType = IP_ROUTER_DISC_INFO;
  284. pToc->Count = 1;
  285. pToc->Offset = (ULONG)(pbDataPtr - (PBYTE) pInfoHdr);
  286. pInfo = (PRTR_DISC_INFO)pbDataPtr;
  287. pInfo->wMaxAdvtInterval = picb->rdcRtrDiscInfo.wMaxAdvtInterval;
  288. liQuotient = RtlExtendedLargeIntegerDivide(picb->rdcRtrDiscInfo.liMinAdvtIntervalInSysUnits,
  289. SYS_UNITS_IN_1_SEC,
  290. &dwRem);
  291. pInfo->wMinAdvtInterval = LOWORD(liQuotient.LowPart);
  292. pInfo->wAdvtLifetime = picb->rdcRtrDiscInfo.wAdvtLifetime;
  293. pInfo->bAdvertise = picb->rdcRtrDiscInfo.bAdvertise;
  294. pInfo->lPrefLevel = picb->rdcRtrDiscInfo.lPrefLevel;
  295. TraceLeave("GetInterfaceRouterDiscoveryInfo");
  296. return NO_ERROR;
  297. }
  298. DWORD
  299. ActivateRouterDiscovery(
  300. IN PICB picb
  301. )
  302. /*++
  303. Routine Description
  304. Activates router discovery messages on an interface. The interface must
  305. already be bound.
  306. Locks
  307. Called with the ICB_LIST lock held as WRITER
  308. Arguments
  309. picb The ICB of the interface to activate
  310. Return Value
  311. NO_ERROR or some error code
  312. --*/
  313. {
  314. PROUTER_DISC_CB pDiscCb;
  315. PROUTER_DISC_CB pDiscCb2;
  316. DWORD dwResult,i,dwNumAddrs,dwNumOldAddrs,dwSize;
  317. LARGE_INTEGER liTimer;
  318. PTIMER_QUEUE_ITEM pTimer;
  319. BOOL bReset;
  320. TraceEnter("ActivateRouterDiscovery");
  321. //
  322. // The SetInterfaceInfo call takes into account whether our
  323. // admin state is UP or down. Here we only check if our oper
  324. // state allows us to come up
  325. //
  326. if(picb->dwOperationalState < IF_OPER_STATUS_CONNECTING)
  327. {
  328. TraceLeave("ActivateRouterDiscovery");
  329. return NO_ERROR;
  330. }
  331. pDiscCb = &picb->rdcRtrDiscInfo;
  332. if(!pDiscCb->bAdvertise)
  333. {
  334. //
  335. // Since we dont have to advertise on this interface, we are done
  336. //
  337. TraceLeave("ActivateRouterDiscovery");
  338. return NO_ERROR;
  339. }
  340. dwResult = CreateSockets(picb);
  341. if(dwResult isnot NO_ERROR)
  342. {
  343. Trace2(ERR,
  344. "ActivateRouterDiscovery: Couldnt create sockets for interface %S. Error %d",
  345. picb->pwszName,
  346. dwResult);
  347. TraceLeave("ActivateRouterDiscovery");
  348. return dwResult;
  349. }
  350. dwResult = UpdateAdvertisement(picb);
  351. if(dwResult isnot NO_ERROR)
  352. {
  353. DeleteSockets(picb);
  354. Trace1(ERR,
  355. "ActivateRouterDiscovery: Couldnt update Icmp Advt. Error %d",
  356. dwResult);
  357. TraceLeave("ActivateRouterDiscovery");
  358. return dwResult;
  359. }
  360. //
  361. // Ok so we have a valid CB and we have the sockets all set up.
  362. //
  363. bReset = SetFiringTimeForAdvt(picb);
  364. if(bReset)
  365. {
  366. if(!SetWaitableTimer(g_hRtrDiscTimer,
  367. &(pDiscCb->tqiTimer.liFiringTime),
  368. 0,
  369. NULL,
  370. NULL,
  371. FALSE))
  372. {
  373. dwResult = GetLastError();
  374. Trace1(ERR,
  375. "ActivateRouterDiscovery: Error %d setting timer",
  376. dwResult);
  377. DeleteSockets(picb);
  378. TraceLeave("ActivateRouterDiscovery");
  379. return ERROR_CAN_NOT_COMPLETE;
  380. }
  381. }
  382. //
  383. // Yes we are active
  384. //
  385. pDiscCb->bActive = TRUE;
  386. TraceLeave("ActivateRouterDiscovery");
  387. return NO_ERROR;
  388. }
  389. DWORD
  390. UpdateAdvertisement(
  391. IN PICB picb
  392. )
  393. /*++
  394. Routine Description
  395. Updates the Router discovery advertisement. If none exists, creates one
  396. Locks
  397. ICB lock as writer
  398. Arguments
  399. picb ICB to update
  400. Return Value
  401. NO_ERROR
  402. --*/
  403. {
  404. DWORD dwResult,i;
  405. PROUTER_DISC_CB pDiscCb;
  406. TraceEnter("UpdateAdvertisement");
  407. pDiscCb = &picb->rdcRtrDiscInfo;
  408. if(picb->pRtrDiscAdvt)
  409. {
  410. //
  411. // If we have an old advertisement
  412. //
  413. if(picb->dwRtrDiscAdvtSize < SIZEOF_RTRDISC_ADVT(picb->dwNumAddresses))
  414. {
  415. //
  416. // Too small, cannot reuse the old advert
  417. //
  418. HeapFree(IPRouterHeap,
  419. 0,
  420. picb->pRtrDiscAdvt);
  421. picb->pRtrDiscAdvt = NULL;
  422. picb->dwRtrDiscAdvtSize = 0;
  423. }
  424. }
  425. if(!picb->pRtrDiscAdvt)
  426. {
  427. picb->pRtrDiscAdvt = HeapAlloc(IPRouterHeap,
  428. HEAP_ZERO_MEMORY,
  429. SIZEOF_RTRDISC_ADVT(picb->dwNumAddresses));
  430. if(picb->pRtrDiscAdvt is NULL)
  431. {
  432. //
  433. // Set advertise to FALSE so that no one uses the
  434. // NULL pointer by mistake
  435. //
  436. pDiscCb->bAdvertise = FALSE;
  437. picb->dwRtrDiscAdvtSize = 0;
  438. Trace1(ERR,
  439. "UpdateAdvertisement: Cant allocate %d bytes for Icmp Msg",
  440. SIZEOF_RTRDISC_ADVT(picb->dwNumAddresses));
  441. return ERROR_NOT_ENOUGH_MEMORY;
  442. }
  443. picb->dwRtrDiscAdvtSize = SIZEOF_RTRDISC_ADVT(picb->dwNumAddresses);
  444. }
  445. picb->pRtrDiscAdvt->byType = ICMP_ROUTER_DISCOVERY_TYPE;
  446. picb->pRtrDiscAdvt->byCode = ICMP_ROUTER_DISCOVERY_CODE;
  447. picb->pRtrDiscAdvt->wLifeTime = htons(pDiscCb->wAdvtLifetime);
  448. picb->pRtrDiscAdvt->byAddrEntrySize = ICMP_ROUTER_DISCOVERY_ADDR_SIZE;
  449. picb->pRtrDiscAdvt->wXSum = 0;
  450. //
  451. // Add the interface's addresses to the advertisement.
  452. //
  453. picb->wsAdvtWSABuffer.buf = (PBYTE)picb->pRtrDiscAdvt;
  454. picb->wsAdvtWSABuffer.len = SIZEOF_RTRDISC_ADVT(picb->dwNumAddresses);
  455. picb->pRtrDiscAdvt->byNumAddrs = LOBYTE(LOWORD(picb->dwNumAddresses));
  456. for(i = 0; i < picb->dwNumAddresses; i++)
  457. {
  458. picb->pRtrDiscAdvt->iaAdvt[i].dwRtrIpAddr = picb->pibBindings[i].dwAddress;
  459. picb->pRtrDiscAdvt->iaAdvt[i].lPrefLevel =
  460. htonl(picb->rdcRtrDiscInfo.lPrefLevel);
  461. }
  462. picb->pRtrDiscAdvt->wXSum = Compute16BitXSum((PVOID)picb->pRtrDiscAdvt,
  463. SIZEOF_RTRDISC_ADVT(picb->dwNumAddresses));
  464. //
  465. // Note: TBD: If the advertising times have changed we should
  466. // change the timer queue. However we let the timer fire and the
  467. // next time we set the timer we will pick up the correct
  468. // time
  469. //
  470. TraceLeave("UpdateAdvertisement");
  471. return NO_ERROR;
  472. }
  473. BOOL
  474. SetFiringTimeForAdvt(
  475. IN PICB picb
  476. )
  477. /*++
  478. Routine Description
  479. Locks
  480. ICB_LIST lock must be held as WRITER
  481. Arguments
  482. picb The ICB of the interface to activate
  483. Return Value
  484. TRUE if calling the function caused the timer to be reset
  485. --*/
  486. {
  487. PROUTER_DISC_CB pDiscCb;
  488. DWORD dwResult;
  489. LARGE_INTEGER liCurrentTime, liRandomTime;
  490. INT iRand;
  491. ULONG ulRem;
  492. PLIST_ENTRY pleNode;
  493. PTIMER_QUEUE_ITEM pOldTime;
  494. TraceEnter("SetFiringTimeForAdvt");
  495. //
  496. // Figure out the next time this interface should advertise
  497. //
  498. iRand = rand();
  499. pDiscCb = &picb->rdcRtrDiscInfo;
  500. liRandomTime = RtlExtendedLargeIntegerDivide(RtlExtendedIntegerMultiply(pDiscCb->liMaxMinDiff,
  501. iRand),
  502. RAND_MAX,
  503. &ulRem);
  504. liRandomTime = RtlLargeIntegerAdd(liRandomTime,
  505. pDiscCb->liMinAdvtIntervalInSysUnits);
  506. if((pDiscCb->dwNumAdvtsSent <= MAX_INITIAL_ADVTS) and
  507. RtlLargeIntegerGreaterThan(liRandomTime,SecsToSysUnits(MAX_INITIAL_ADVT_TIME)))
  508. {
  509. liRandomTime = SecsToSysUnits(MAX_INITIAL_ADVT_TIME);
  510. }
  511. NtQuerySystemTime(&liCurrentTime);
  512. picb->rdcRtrDiscInfo.tqiTimer.liFiringTime = RtlLargeIntegerAdd(liCurrentTime,liRandomTime);
  513. //
  514. // Insert into sorted list
  515. //
  516. for(pleNode = g_leTimerQueueHead.Flink;
  517. pleNode isnot &g_leTimerQueueHead;
  518. pleNode = pleNode->Flink)
  519. {
  520. pOldTime = CONTAINING_RECORD(pleNode,TIMER_QUEUE_ITEM,leTimerLink);
  521. if(RtlLargeIntegerGreaterThan(pOldTime->liFiringTime,
  522. picb->rdcRtrDiscInfo.tqiTimer.liFiringTime))
  523. {
  524. break;
  525. }
  526. }
  527. //
  528. // Now pleNode points to first Node whose time is greater than ours, so
  529. // we insert ourselves before pleNode. Since RTL doesnt supply us with
  530. // an InsertAfter function, we go back on and use the previous node as a
  531. // list head and call InsertHeadList
  532. //
  533. pleNode = pleNode->Blink;
  534. InsertHeadList(pleNode,
  535. &(picb->rdcRtrDiscInfo.tqiTimer.leTimerLink));
  536. if(pleNode is &g_leTimerQueueHead)
  537. {
  538. //
  539. // We inserted ourselves at the head of the queue
  540. //
  541. TraceLeave("SetFiringTimeForAdvt");
  542. return TRUE;
  543. }
  544. TraceLeave("SetFiringTimeForAdvt");
  545. return FALSE;
  546. }
  547. DWORD
  548. CreateSockets(
  549. IN PICB picb
  550. )
  551. /*++
  552. Routine Description
  553. Activates router discovery messages on an interface. The interface must
  554. already be bound
  555. Locks
  556. ICB_LIST lock must be held as WRITER
  557. Arguments
  558. picb The ICB of the interface for which the sockets have to be created
  559. Return Value
  560. NO_ERROR or some error code
  561. --*/
  562. {
  563. PROUTER_DISC_CB pDiscCb;
  564. DWORD i, dwResult, dwBytesReturned;
  565. struct linger lingerOption;
  566. BOOL bOption, bLoopback;
  567. SOCKADDR_IN sinSockAddr;
  568. struct ip_mreq imOption;
  569. INT iScope;
  570. TraceEnter("CreateSockets");
  571. dwResult = NO_ERROR;
  572. if(picb->dwNumAddresses is 0)
  573. {
  574. Trace1(ERR,
  575. "CreateSockets: Can not activate router discovery on %S as it has no addresses",
  576. picb->pwszName);
  577. TraceLeave("CreateSockets");
  578. return ERROR_CAN_NOT_COMPLETE;
  579. }
  580. //
  581. // Create the sockets for the interface
  582. //
  583. pDiscCb = &(picb->rdcRtrDiscInfo);
  584. pDiscCb->pRtrDiscSockets = HeapAlloc(IPRouterHeap,
  585. 0,
  586. (picb->dwNumAddresses) * sizeof(SOCKET));
  587. if(pDiscCb->pRtrDiscSockets is NULL)
  588. {
  589. Trace1(ERR,
  590. "CreateSockets: Error allocating %d bytes for sockets",
  591. (picb->dwNumAddresses) * sizeof(SOCKET));
  592. return ERROR_NOT_ENOUGH_MEMORY;
  593. }
  594. for(i = 0; i < picb->dwNumAddresses; i++)
  595. {
  596. pDiscCb->pRtrDiscSockets[i] = INVALID_SOCKET;
  597. }
  598. for(i = 0; i < picb->dwNumAddresses; i++)
  599. {
  600. pDiscCb->pRtrDiscSockets[i] = WSASocket(AF_INET,
  601. SOCK_RAW,
  602. IPPROTO_ICMP,
  603. NULL,
  604. 0,
  605. RTR_DISC_SOCKET_FLAGS);
  606. if(pDiscCb->pRtrDiscSockets[i] is INVALID_SOCKET)
  607. {
  608. dwResult = WSAGetLastError();
  609. Trace3(ERR,
  610. "CreateSockets: Couldnt create socket number %d on %S. Error %d",
  611. i,
  612. picb->pwszName,
  613. dwResult);
  614. continue;
  615. }
  616. #if 0
  617. //
  618. // Set to SO_DONTLINGER
  619. //
  620. bOption = TRUE;
  621. if(setsockopt(pDiscCb->pRtrDiscSockets[i],
  622. SOL_SOCKET,
  623. SO_DONTLINGER,
  624. (const char FAR*)&bOption,
  625. sizeof(BOOL)) is SOCKET_ERROR)
  626. {
  627. Trace1(ERR,
  628. "CreateSockets: Couldnt set linger option - continuing. Error %d",
  629. WSAGetLastError());
  630. }
  631. #endif
  632. //
  633. // Set to SO_REUSEADDR
  634. //
  635. bOption = TRUE;
  636. if(setsockopt(pDiscCb->pRtrDiscSockets[i],
  637. SOL_SOCKET,
  638. SO_REUSEADDR,
  639. (const char FAR*)&bOption,
  640. sizeof(BOOL)) is SOCKET_ERROR)
  641. {
  642. Trace1(ERR,
  643. "CreateSockets: Couldnt set reuse option - continuing. Error %d",
  644. WSAGetLastError());
  645. }
  646. if(WSAEventSelect(pDiscCb->pRtrDiscSockets[i],
  647. g_hRtrDiscSocketEvent,
  648. FD_READ) is SOCKET_ERROR)
  649. {
  650. Trace2(ERR,
  651. "CreateSockets: WSAEventSelect() failed for socket on %S.Error %d",
  652. picb->pwszName,
  653. WSAGetLastError());
  654. closesocket(pDiscCb->pRtrDiscSockets[i]);
  655. pDiscCb->pRtrDiscSockets[i] = INVALID_SOCKET;
  656. continue;
  657. }
  658. //
  659. // TBD: Set scope/TTL to 1 since we always multicast the responses
  660. // Also set Loopback to ignore self generated packets
  661. //
  662. //
  663. // Bind to the addresses on the interface
  664. //
  665. sinSockAddr.sin_family = AF_INET;
  666. sinSockAddr.sin_addr.s_addr = picb->pibBindings[i].dwAddress;
  667. sinSockAddr.sin_port = 0;
  668. if(bind(pDiscCb->pRtrDiscSockets[i],
  669. (const struct sockaddr FAR*)&sinSockAddr,
  670. sizeof(SOCKADDR_IN)) is SOCKET_ERROR)
  671. {
  672. dwResult = WSAGetLastError();
  673. Trace3(ERR,
  674. "CreateSockets: Couldnt bind to %d.%d.%d.%d on interface %S. Error %d",
  675. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  676. picb->pwszName,
  677. dwResult);
  678. closesocket(pDiscCb->pRtrDiscSockets[i]);
  679. pDiscCb->pRtrDiscSockets[i] = INVALID_SOCKET;
  680. continue;
  681. }
  682. bLoopback = FALSE;
  683. dwResult = WSAIoctl(pDiscCb->pRtrDiscSockets[i],
  684. SIO_MULTIPOINT_LOOPBACK,
  685. (PVOID)&bLoopback,
  686. sizeof(BOOL),
  687. NULL,
  688. 0,
  689. &dwBytesReturned,
  690. NULL,
  691. NULL);
  692. if(dwResult is SOCKET_ERROR)
  693. {
  694. Trace1(ERR,
  695. "CreateSockets: Error %d setting loopback to FALSE",
  696. WSAGetLastError());
  697. }
  698. iScope = 1;
  699. dwResult = WSAIoctl(pDiscCb->pRtrDiscSockets[i],
  700. SIO_MULTICAST_SCOPE,
  701. (PVOID)&iScope,
  702. sizeof(INT),
  703. NULL,
  704. 0,
  705. &dwBytesReturned,
  706. NULL,
  707. NULL);
  708. if(dwResult is SOCKET_ERROR)
  709. {
  710. Trace1(ERR,
  711. "CreateSockets: Error %d setting multicast scope to 1",
  712. WSAGetLastError());
  713. }
  714. #if 0
  715. //
  716. // Join the multicast session on ALL_ROUTERS_MULTICAST
  717. //
  718. sinSockAddr.sin_family = AF_INET;
  719. sinSockAddr.sin_addr.s_addr = ALL_ROUTERS_MULTICAST_GROUP;
  720. sinSockAddr.sin_port = 0;
  721. if(WSAJoinLeaf(pDiscCb->pRtrDiscSockets[i],
  722. (const struct sockaddr FAR*)&sinSockAddr,
  723. sizeof(SOCKADDR_IN),
  724. NULL,
  725. NULL,
  726. NULL,
  727. NULL,
  728. JL_BOTH) is INVALID_SOCKET)
  729. {
  730. dwResult = WSAGetLastError();
  731. Trace2(ERR,
  732. "CreateSockets: Couldnt join multicast group on socket for %d.%d.%d.%d on %S",
  733. PRINT_IPADDR(picb->pibBindings[i].dwAddress)),
  734. picb->pwszName);
  735. closesocket(pDiscCb->pRtrDiscSockets[i]);
  736. pDiscCb->pRtrDiscSockets[i] = INVALID_SOCKET;
  737. continue;
  738. }
  739. //
  740. // Join the multicast session on ALL_SYSTEMS_MULTICAST
  741. //
  742. sinSockAddr.sin_family = AF_INET;
  743. sinSockAddr.sin_addr.s_addr = ALL_SYSTEMS_MULTICAST_GROUP;
  744. sinSockAddr.sin_port = 0;
  745. if(WSAJoinLeaf(pDiscCb->pRtrDiscSockets[i],
  746. (const struct sockaddr FAR*)&sinSockAddr,
  747. sizeof(SOCKADDR_IN),
  748. NULL,
  749. NULL,
  750. NULL,
  751. NULL,
  752. JL_BOTH) is INVALID_SOCKET)
  753. {
  754. dwResult = WSAGetLastError();
  755. Trace2(ERR,
  756. "CreateSockets: Couldnt join all systems multicast group on socket for %d.%d.%d.%d on %S",
  757. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  758. picb->pwszName);
  759. }
  760. #endif
  761. sinSockAddr.sin_addr.s_addr = picb->pibBindings[i].dwAddress;
  762. if(setsockopt(pDiscCb->pRtrDiscSockets[i],
  763. IPPROTO_IP,
  764. IP_MULTICAST_IF,
  765. (PBYTE)&sinSockAddr.sin_addr,
  766. sizeof(IN_ADDR)) is SOCKET_ERROR)
  767. {
  768. dwResult = WSAGetLastError();
  769. Trace2(ERR,
  770. "CreateSockets: Couldnt join multicast group on socket for %d.%d.%d.%d on %S",
  771. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  772. picb->pwszName);
  773. closesocket(pDiscCb->pRtrDiscSockets[i]);
  774. pDiscCb->pRtrDiscSockets[i] = INVALID_SOCKET;
  775. continue;
  776. }
  777. Trace2(RTRDISC,
  778. "CreateSockets: Joining ALL_ROUTERS on %d.%d.%d.%d over %S",
  779. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  780. picb->pwszName);
  781. imOption.imr_multiaddr.s_addr = ALL_ROUTERS_MULTICAST_GROUP;
  782. imOption.imr_interface.s_addr = picb->pibBindings[i].dwAddress;
  783. if(setsockopt(pDiscCb->pRtrDiscSockets[i],
  784. IPPROTO_IP,
  785. IP_ADD_MEMBERSHIP,
  786. (PBYTE)&imOption,
  787. sizeof(imOption)) is SOCKET_ERROR)
  788. {
  789. dwResult = WSAGetLastError();
  790. Trace2(ERR,
  791. "CreateSockets: Couldnt join multicast group on socket for %d.%d.%d.%d on %S",
  792. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  793. picb->pwszName);
  794. closesocket(pDiscCb->pRtrDiscSockets[i]);
  795. pDiscCb->pRtrDiscSockets[i] = INVALID_SOCKET;
  796. continue;
  797. }
  798. }
  799. TraceLeave("CreateSockets");
  800. return dwResult;
  801. }
  802. VOID
  803. DeleteSockets(
  804. IN PICB picb
  805. )
  806. /*++
  807. Routine Description
  808. Deletes the sockets (if any) created for running Router Discovery
  809. Locks
  810. Arguments
  811. picb The interface whose sockets need to be deleted
  812. Return Value
  813. --*/
  814. {
  815. PROUTER_DISC_CB pDiscCb;
  816. DWORD i;
  817. //
  818. // Cloese the sockets, free the memory
  819. //
  820. pDiscCb = &(picb->rdcRtrDiscInfo);
  821. for(i = 0; i < picb->dwNumAddresses; i++)
  822. {
  823. if(pDiscCb->pRtrDiscSockets[i] isnot INVALID_SOCKET)
  824. {
  825. closesocket(pDiscCb->pRtrDiscSockets[i]);
  826. }
  827. }
  828. HeapFree(IPRouterHeap,
  829. 0,
  830. pDiscCb->pRtrDiscSockets);
  831. pDiscCb->pRtrDiscSockets = NULL;
  832. }
  833. VOID
  834. HandleRtrDiscTimer(
  835. VOID
  836. )
  837. /*++
  838. Routine Description
  839. Processes the firing of the Router Discovery Timer for an interface
  840. Locks
  841. Called with ICB_LIST held as WRITER. This is needed because ICB_LIST
  842. protects timer queue, etc. This may seem inefficient, but the Timer will
  843. go off once in 5 minutes or so, so its worth reducing Kernel Mode footprint
  844. by reusing the lock
  845. Arguments
  846. None
  847. Return Value
  848. None
  849. --*/
  850. {
  851. LARGE_INTEGER liCurrentTime;
  852. PICB picb;
  853. PLIST_ENTRY pleNode;
  854. PTIMER_QUEUE_ITEM pTimer;
  855. BOOL bReset;
  856. DWORD dwResult;
  857. PROUTER_DISC_CB pInfo;
  858. TraceEnter("HandleRtrDiscTimer");
  859. while(!IsListEmpty(&g_leTimerQueueHead))
  860. {
  861. pleNode = g_leTimerQueueHead.Flink;
  862. pTimer = CONTAINING_RECORD(pleNode, TIMER_QUEUE_ITEM, leTimerLink);
  863. NtQuerySystemTime(&liCurrentTime);
  864. if(RtlLargeIntegerGreaterThan(pTimer->liFiringTime,liCurrentTime))
  865. {
  866. break;
  867. }
  868. RemoveHeadList(&g_leTimerQueueHead);
  869. //
  870. // We have the pointer to the timer element. From that
  871. // we get the pointer to the Router Discovery Info container
  872. //
  873. pInfo = CONTAINING_RECORD(pTimer, ROUTER_DISC_CB, tqiTimer);
  874. //
  875. // From the rtrdisc info we get to the ICB which contains it
  876. //
  877. picb = CONTAINING_RECORD(pInfo, ICB, rdcRtrDiscInfo);
  878. //
  879. // Send advt for this interface
  880. //
  881. if((picb->rdcRtrDiscInfo.bAdvertise is FALSE) or
  882. (picb->dwAdminState is IF_ADMIN_STATUS_DOWN) or
  883. (picb->dwOperationalState < CONNECTED))
  884. {
  885. Trace3(ERR,
  886. "HandleRtrDiscTimer: Router Discovery went off for interface %S, but current state (%d/%d) doesnt allow tx",
  887. picb->pwszName,
  888. picb->dwAdminState,
  889. picb->dwOperationalState);
  890. continue;
  891. }
  892. IpRtAssert(picb->pRtrDiscAdvt);
  893. AdvertiseInterface(picb);
  894. //
  895. // Insert the next time this interface needs to advt into the queue.
  896. // Reset the timer
  897. //
  898. SetFiringTimeForAdvt(picb);
  899. }
  900. //
  901. // We have to reset the timer
  902. //
  903. if(!IsListEmpty(&g_leTimerQueueHead))
  904. {
  905. pleNode = g_leTimerQueueHead.Flink;
  906. pTimer = CONTAINING_RECORD(pleNode, TIMER_QUEUE_ITEM, leTimerLink);
  907. if(!SetWaitableTimer(g_hRtrDiscTimer,
  908. &pTimer->liFiringTime,
  909. 0,
  910. NULL,
  911. NULL,
  912. FALSE))
  913. {
  914. dwResult = GetLastError();
  915. Trace1(ERR,
  916. "HandleRtrDiscTimer: Couldnt set waitable timer",
  917. dwResult);
  918. }
  919. }
  920. TraceLeave("HandleRtrDiscTimer");
  921. }
  922. VOID
  923. AdvertiseInterface(
  924. IN PICB picb
  925. )
  926. /*++
  927. Routine Description
  928. Locks
  929. Arguments
  930. picb ICB of the interface on which to send out the advertisement
  931. Return Value
  932. None
  933. --*/
  934. {
  935. DWORD i,dwResult,dwNumBytesSent;
  936. TraceEnter("AdvertiseInterface");
  937. //
  938. // If any replies were pending, they are deemed to be sent even if
  939. // the send fails
  940. //
  941. picb->rdcRtrDiscInfo.bReplyPending = FALSE;
  942. for(i = 0; i < picb->dwNumAddresses; i++)
  943. {
  944. #if DBG
  945. Trace2(RTRDISC,
  946. "Advertising from %d.%d.%d.%d on %S",
  947. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  948. picb->pwszName);
  949. TraceDumpEx(TraceHandle,
  950. IPRTRMGR_TRACE_RTRDISC,
  951. picb->wsAdvtWSABuffer.buf,
  952. picb->wsAdvtWSABuffer.len,
  953. 4,
  954. FALSE,
  955. "ICMP Advt");
  956. #endif
  957. if(WSASendTo(picb->rdcRtrDiscInfo.pRtrDiscSockets[i],
  958. &picb->wsAdvtWSABuffer,
  959. 1,
  960. &dwNumBytesSent,
  961. MSG_DONTROUTE,
  962. (const struct sockaddr FAR*)&g_sinAllSystemsAddr,
  963. sizeof(SOCKADDR_IN),
  964. NULL,
  965. NULL
  966. ) is SOCKET_ERROR)
  967. {
  968. dwResult = WSAGetLastError();
  969. Trace3(ERR,
  970. "AdvertiseInterface: Couldnt send from %d.%d.%d.%d on %S. Error %d",
  971. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  972. picb->pwszName,
  973. dwResult);
  974. }
  975. else
  976. {
  977. picb->rdcRtrDiscInfo.dwNumAdvtsSent++;
  978. }
  979. }
  980. TraceLeave("AdvertiseInterface");
  981. }
  982. DWORD
  983. DeActivateRouterDiscovery(
  984. IN PICB picb
  985. )
  986. {
  987. PROUTER_DISC_CB pDiscCb;
  988. DWORD i;
  989. PTIMER_QUEUE_ITEM pTimer;
  990. PLIST_ENTRY pleNode;
  991. TraceEnter("DeActivateRouterDiscovery");
  992. pDiscCb = &(picb->rdcRtrDiscInfo);
  993. if(!pDiscCb->bActive)
  994. {
  995. return NO_ERROR;
  996. }
  997. DeleteSockets(picb);
  998. //
  999. // Check to see if our advertisement is in the front of the queue
  1000. //
  1001. if(&(pDiscCb->tqiTimer.leTimerLink) is &g_leTimerQueueHead)
  1002. {
  1003. RemoveHeadList(&g_leTimerQueueHead);
  1004. if(!IsListEmpty(&g_leTimerQueueHead))
  1005. {
  1006. pleNode = g_leTimerQueueHead.Flink;
  1007. pTimer = CONTAINING_RECORD(pleNode, TIMER_QUEUE_ITEM, leTimerLink);
  1008. if(!SetWaitableTimer(g_hRtrDiscTimer,
  1009. &pTimer->liFiringTime,
  1010. 0,
  1011. NULL,
  1012. NULL,
  1013. FALSE))
  1014. {
  1015. Trace1(ERR,
  1016. "DeActivateRouterDiscovery: Couldnt set waitable timer",
  1017. GetLastError());
  1018. }
  1019. }
  1020. }
  1021. else
  1022. {
  1023. //
  1024. // Just remove the timer element from the queue
  1025. //
  1026. RemoveEntryList(&(pDiscCb->tqiTimer.leTimerLink));
  1027. }
  1028. pDiscCb->bActive = FALSE;
  1029. TraceLeave("DeActivateRouterDiscovery");
  1030. return NO_ERROR;
  1031. }
  1032. VOID
  1033. HandleSolicitations(
  1034. VOID
  1035. )
  1036. /*++
  1037. Routine Description
  1038. Locks
  1039. Arguments
  1040. Return Value
  1041. --*/
  1042. {
  1043. PLIST_ENTRY pleNode;
  1044. PICB picb;
  1045. DWORD i, dwResult, dwRcvAddrLen, dwSizeOfHeader, dwBytesRead, dwFlags;
  1046. WSANETWORKEVENTS wsaNetworkEvents;
  1047. SOCKADDR_IN sinFrom;
  1048. PICMP_ROUTER_SOL_MSG pIcmpMsg;
  1049. TraceEnter("HandleSolicitations");
  1050. for(pleNode = ICBList.Flink;
  1051. pleNode isnot &ICBList;
  1052. pleNode = pleNode->Flink)
  1053. {
  1054. picb = CONTAINING_RECORD(pleNode, ICB, leIfLink);
  1055. //
  1056. // If the interface has no bindings, or isnot involved in Router Discovery, we wouldnt have
  1057. // opened a socket on it so the FD_READ notification cant be for it
  1058. //
  1059. if((picb->dwNumAddresses is 0) or
  1060. (picb->rdcRtrDiscInfo.bActive is FALSE))
  1061. {
  1062. continue;
  1063. }
  1064. for(i = 0; i < picb->dwNumAddresses; i++)
  1065. {
  1066. if(picb->rdcRtrDiscInfo.pRtrDiscSockets[i] is INVALID_SOCKET)
  1067. {
  1068. continue;
  1069. }
  1070. if(WSAEnumNetworkEvents(picb->rdcRtrDiscInfo.pRtrDiscSockets[i],
  1071. NULL,
  1072. &wsaNetworkEvents) is SOCKET_ERROR)
  1073. {
  1074. dwResult = GetLastError();
  1075. Trace1(ERR,
  1076. "HandleSolicitations: WSAEnumNetworkEvents() returned %d",
  1077. dwResult);
  1078. continue;
  1079. }
  1080. if(!(wsaNetworkEvents.lNetworkEvents & FD_READ))
  1081. {
  1082. //
  1083. // Read bit isnot set and we arent interested in anything else
  1084. //
  1085. continue;
  1086. }
  1087. if(wsaNetworkEvents.iErrorCode[FD_READ_BIT] isnot NO_ERROR)
  1088. {
  1089. Trace3(ERR,
  1090. "HandleSolicitations: Error %d associated with socket %s on %S for FD_READ",
  1091. wsaNetworkEvents.iErrorCode[FD_READ_BIT],
  1092. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  1093. picb->pwszName);
  1094. continue;
  1095. }
  1096. dwRcvAddrLen = sizeof(SOCKADDR_IN);
  1097. dwFlags = 0;
  1098. dwResult = WSARecvFrom(picb->rdcRtrDiscInfo.pRtrDiscSockets[i],
  1099. &g_wsaIpRcvBuf,
  1100. 1,
  1101. &dwBytesRead,
  1102. &dwFlags,
  1103. (struct sockaddr FAR*)&sinFrom,
  1104. &dwRcvAddrLen,
  1105. NULL,
  1106. NULL);
  1107. if(dwResult is SOCKET_ERROR)
  1108. {
  1109. dwResult = WSAGetLastError();
  1110. Trace4(ERR,
  1111. "HandleSolicitations: Error %d in WSARecvFrom on socket %d.%d.%d.%d over %S. Bytes read %d",
  1112. dwResult,
  1113. PRINT_IPADDR(picb->pibBindings[i].dwAddress),
  1114. picb->pwszName,
  1115. dwBytesRead);
  1116. continue;
  1117. }
  1118. Trace2(RTRDISC,
  1119. "HandleSolicitations: Received %d bytes on %d.%d.%d.%d",
  1120. dwBytesRead,
  1121. PRINT_IPADDR(picb->pibBindings[i].dwAddress));
  1122. if(picb->rdcRtrDiscInfo.bReplyPending)
  1123. {
  1124. //
  1125. // Well the reply is pending so we dont need to do anything other than go
  1126. // through the sockets for this interface and do a recvfrom to clear out the
  1127. // FD_READ bit
  1128. //
  1129. continue;
  1130. }
  1131. dwSizeOfHeader = ((g_pIpHeader->byVerLen)&0x0f)<<2;
  1132. pIcmpMsg = (PICMP_ROUTER_SOL_MSG)(((PBYTE)g_pIpHeader) + dwSizeOfHeader);
  1133. #if DBG
  1134. Trace6(RTRDISC,
  1135. "HandleSolicitations: Type is %d, code %d. IP Length is %d. \n\t\tHeader Length is %d Src is %d.%d.%d.%d dest is %d.%d.%d.%d",
  1136. (DWORD)pIcmpMsg->byType,
  1137. (DWORD)pIcmpMsg->byCode,
  1138. ntohs(g_pIpHeader->wLength),
  1139. (DWORD)dwSizeOfHeader,
  1140. PRINT_IPADDR(g_pIpHeader->dwSrc),
  1141. PRINT_IPADDR(g_pIpHeader->dwDest));
  1142. #endif
  1143. if((pIcmpMsg->byType isnot 0xA) or
  1144. (pIcmpMsg->byCode isnot 0x0))
  1145. {
  1146. //
  1147. // Can not be a valid ICMP Router Solicitation packet
  1148. //
  1149. continue;
  1150. }
  1151. if((ntohs(g_pIpHeader->wLength) - dwSizeOfHeader) < 8)
  1152. {
  1153. Trace0(RTRDISC,
  1154. "HandleSolicitations: Received ICMP packet of length less than 8, discarding");
  1155. continue;
  1156. }
  1157. if(Compute16BitXSum((PVOID)pIcmpMsg,
  1158. 8) isnot 0x0000)
  1159. {
  1160. Trace0(ERR,
  1161. "HandleSolicitations: ICMP packet checksum wrong");
  1162. continue;
  1163. }
  1164. //
  1165. // Check for valid neighbour
  1166. //
  1167. if((g_pIpHeader->dwSrc isnot 0) and
  1168. ((g_pIpHeader->dwSrc & picb->pibBindings[i].dwMask) isnot
  1169. (picb->pibBindings[i].dwAddress & picb->pibBindings[i].dwMask)))
  1170. {
  1171. Trace1(ERR,
  1172. "HandleSolicitations: Received ICMP solicitation from invalid neigbour %d.%d.%d.%d",
  1173. PRINT_IPADDR(g_pIpHeader->dwDest));
  1174. continue;
  1175. }
  1176. //
  1177. // Since we always Multicast, if the destination addresses was a
  1178. // broadcast, log an error
  1179. //
  1180. if((g_pIpHeader->dwDest is 0xFFFFFFFF) or
  1181. (g_pIpHeader->dwDest is (picb->pibBindings[i].dwMask | ~picb->pibBindings[i].dwMask)))
  1182. {
  1183. Trace0(ERR,
  1184. "HandleSolicitations: Received a broadcast ICMP solicitation");
  1185. }
  1186. //
  1187. // So insert a reply for this interface. We multicast the replies
  1188. // too.
  1189. //
  1190. picb->rdcRtrDiscInfo.bReplyPending = TRUE;
  1191. SetFiringTimeForReply(picb);
  1192. }
  1193. }
  1194. TraceLeave("HandleSolicitations");
  1195. }
  1196. VOID
  1197. SetFiringTimeForReply(
  1198. IN PICB picb
  1199. )
  1200. /*++
  1201. Routine Description
  1202. Locks
  1203. Arguments
  1204. Return Value
  1205. --*/
  1206. {
  1207. LARGE_INTEGER liCurrentTime, liRandomTime;
  1208. INT iRand;
  1209. ULONG ulRem;
  1210. PLIST_ENTRY pleNode;
  1211. PTIMER_QUEUE_ITEM pOldTime;
  1212. BOOL bReset = FALSE;
  1213. DWORD dwResult;
  1214. TraceEnter("SetFiringTimeForReply");
  1215. //
  1216. // We remove the timer the interface has queued up
  1217. //
  1218. if(g_leTimerQueueHead.Flink is &(picb->rdcRtrDiscInfo.tqiTimer.leTimerLink))
  1219. {
  1220. //
  1221. // Since this timer was the first one, it determined the firing time of the timer.
  1222. //
  1223. bReset = TRUE;
  1224. }
  1225. RemoveEntryList(&(picb->rdcRtrDiscInfo.tqiTimer.leTimerLink));
  1226. iRand = rand();
  1227. liRandomTime = RtlExtendedLargeIntegerDivide(SecsToSysUnits(RESPONSE_DELAY_INTERVAL * iRand),
  1228. RAND_MAX,
  1229. &ulRem);
  1230. liRandomTime = RtlLargeIntegerAdd(liRandomTime,SecsToSysUnits(MIN_RESPONSE_DELAY));
  1231. NtQuerySystemTime(&liCurrentTime);
  1232. picb->rdcRtrDiscInfo.tqiTimer.liFiringTime = RtlLargeIntegerAdd(liCurrentTime,liRandomTime);
  1233. //
  1234. // Insert into sorted list
  1235. //
  1236. for(pleNode = g_leTimerQueueHead.Flink;
  1237. pleNode isnot &g_leTimerQueueHead;
  1238. pleNode = pleNode->Flink)
  1239. {
  1240. pOldTime = CONTAINING_RECORD(pleNode,TIMER_QUEUE_ITEM,leTimerLink);
  1241. if(RtlLargeIntegerGreaterThan(pOldTime->liFiringTime,
  1242. picb->rdcRtrDiscInfo.tqiTimer.liFiringTime))
  1243. {
  1244. break;
  1245. }
  1246. }
  1247. pleNode = pleNode->Blink;
  1248. InsertHeadList(pleNode,
  1249. &(picb->rdcRtrDiscInfo.tqiTimer.leTimerLink));
  1250. if((pleNode is &g_leTimerQueueHead) or bReset)
  1251. {
  1252. //
  1253. // We inserted ourselves at the head of the queue, or took the timer off the front of the
  1254. // queue
  1255. //
  1256. pOldTime = CONTAINING_RECORD(g_leTimerQueueHead.Flink,TIMER_QUEUE_ITEM,leTimerLink);
  1257. if(!SetWaitableTimer(g_hRtrDiscTimer,
  1258. &pOldTime->liFiringTime,
  1259. 0,
  1260. NULL,
  1261. NULL,
  1262. FALSE))
  1263. {
  1264. dwResult = GetLastError();
  1265. Trace1(ERR,
  1266. "SetFiringTimeForReply: Error %d setting waitable timer",
  1267. dwResult);
  1268. }
  1269. }
  1270. }
  1271. WORD
  1272. Compute16BitXSum(
  1273. IN VOID UNALIGNED *pvData,
  1274. IN DWORD dwNumBytes
  1275. )
  1276. /*++
  1277. Routine Description
  1278. Locks
  1279. Arguments
  1280. Return Value
  1281. 16 Bit one's complement of the one's complement sum of dwNumBytes starting
  1282. at pData
  1283. --*/
  1284. {
  1285. REGISTER WORD UNALIGNED *pwStart;
  1286. REGISTER DWORD dwNumWords,i;
  1287. REGISTER DWORD dwSum = 0;
  1288. pwStart = (PWORD)pvData;
  1289. //
  1290. // If there are odd numbered bytes, that has to be handled differently
  1291. // However we can never have odd numbered bytes in our case so we optimize.
  1292. //
  1293. dwNumWords = dwNumBytes/2;
  1294. for(i = 0; i < dwNumWords; i++)
  1295. {
  1296. dwSum += pwStart[i];
  1297. }
  1298. //
  1299. // Add any carry
  1300. //
  1301. dwSum = (dwSum & 0x0000FFFF) + (dwSum >> 16);
  1302. dwSum = dwSum + (dwSum >> 16);
  1303. return LOWORD((~(DWORD_PTR)dwSum));
  1304. }