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.

2790 lines
70 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. mcmisc.c
  5. Abstract:
  6. This module implements routines associated with mrinfo and mtrace
  7. functionality.
  8. Author:
  9. dthaler@microsoft.com 2-9-98
  10. Revision History:
  11. --*/
  12. #include "allinc.h"
  13. #include <iptypes.h>
  14. #include <dsrole.h>
  15. #pragma hdrstop
  16. //
  17. // Undefine this if we can't bind/set oif by IfIndex.
  18. // This can be turned on if Bug #208359 gets fixed.
  19. //
  20. #define RAW_UNNUMBERED_SUPPORT
  21. #undef UDP_UNNUMBERED_SUPPORT
  22. // Miscellaneous IGMP socket used for mrinfo, mtrace, etc.
  23. SOCKET McMiscSocket = INVALID_SOCKET;
  24. // Miscellaneous UDP socket used for RAS advertisements, etc.
  25. // Note that no event is currently associated with this socket,
  26. // since it's currently only used for sending.
  27. SOCKET g_UDPMiscSocket = INVALID_SOCKET;
  28. //
  29. // Set this to >0 to generate extra logging information
  30. //
  31. DWORD g_mcastDebugLevel = 0;
  32. //
  33. // This is an array mapping an error code in priority order
  34. // (MFE_...) to the actual value which goes in a packet.
  35. //
  36. //
  37. // MFE_NO_ERROR 0x00
  38. // MFE_REACHED_CORE 0x08
  39. // MFE_NOT_FORWARDING 0x07
  40. // MFE_WRONG_IF 0x01
  41. // MFE_PRUNED_UPSTREAM 0x02
  42. // MFE_OIF_PRUNED 0x03
  43. // MFE_BOUNDARY_REACHED 0x04
  44. // MFE_NO_MULTICAST 0x0A
  45. // MFE_IIF 0x09
  46. // MFE_NO_ROUTE 0x05 - set by rtrmgr
  47. // MFE_NOT_LAST_HOP 0x06 - set by rtrmgr
  48. // MFE_OLD_ROUTER 0x82
  49. // MFE_PROHIBITED 0x83
  50. // MFE_NO_SPACE 0x81
  51. //
  52. static int mtraceErrCode[MFE_NO_SPACE+1] =
  53. {
  54. 0x00,
  55. 0x08,
  56. 0x07,
  57. 0x01,
  58. 0x02,
  59. 0x03,
  60. 0x04,
  61. 0x0A,
  62. 0x09,
  63. 0x05,
  64. 0x06,
  65. 0x82,
  66. 0x83,
  67. 0x81
  68. };
  69. DWORD
  70. MulticastOwner(
  71. PICB picb,
  72. PPROTO_CB *pcbOwner,
  73. PPROTO_CB *pcbQuerier
  74. )
  75. /*++
  76. Routine Description:
  77. Looks up which protocol instance "owns" a given interface, and which
  78. is the IGMP querying instance.
  79. Locks:
  80. Assumes caller holds read lock on ICB list
  81. Arguments:
  82. Return Value:
  83. --*/
  84. {
  85. PLIST_ENTRY pleNode;
  86. PPROTO_CB pOwner = NULL,
  87. pQuerier = NULL;
  88. if (g_mcastDebugLevel > 0) {
  89. Trace1(MCAST, "MulticastOwner: Looking for owner of %x", picb);
  90. if ( picb->leProtocolList.Flink == &(picb->leProtocolList))
  91. {
  92. Trace0(MCAST, "MulticastOwner: Protocol list is empty.");
  93. }
  94. }
  95. for (pleNode = picb->leProtocolList.Flink;
  96. pleNode isnot &(picb->leProtocolList);
  97. pleNode = pleNode->Flink)
  98. {
  99. PIF_PROTO pProto;
  100. pProto = CONTAINING_RECORD(pleNode,
  101. IF_PROTO,
  102. leIfProtoLink);
  103. if (!(pProto->pActiveProto->fSupportedFunctionality & RF_MULTICAST)
  104. //|| pProto->bPromiscuous
  105. || !(pProto->pActiveProto->pfnGetNeighbors))
  106. {
  107. continue;
  108. }
  109. if (!pOwner || pOwner->dwProtocolId==MS_IP_IGMP)
  110. {
  111. pOwner = pProto->pActiveProto;
  112. }
  113. if (pProto->pActiveProto->dwProtocolId==MS_IP_IGMP)
  114. {
  115. pQuerier = pProto->pActiveProto;
  116. }
  117. }
  118. if (pcbOwner)
  119. {
  120. (*pcbOwner) = pOwner;
  121. }
  122. if (pcbQuerier)
  123. {
  124. (*pcbQuerier) = pQuerier;
  125. }
  126. return NO_ERROR;
  127. }
  128. IPV4_ADDRESS
  129. defaultSourceAddress(
  130. PICB picb
  131. )
  132. /*++
  133. Routine Description:
  134. Look up the default source address for an interface
  135. For now, we need to special case IP-in-IP since at least
  136. the local address is available SOMEWHERE, unlike other
  137. unnumbered interfaces!
  138. Locks:
  139. Arguments:
  140. Return Value:
  141. --*/
  142. {
  143. if (picb->dwNumAddresses > 0)
  144. {
  145. //
  146. // report 1st binding
  147. //
  148. return picb->pibBindings[0].dwAddress;
  149. }
  150. else
  151. {
  152. if ((picb->ritType is ROUTER_IF_TYPE_TUNNEL1) &&
  153. (picb->pIpIpInfo->dwLocalAddress != 0))
  154. {
  155. return picb->pIpIpInfo->dwLocalAddress;
  156. }
  157. else
  158. {
  159. // XXX fill in 0.0.0.0 until this is fixed
  160. return 0;
  161. }
  162. }
  163. }
  164. BOOL
  165. McIsMyAddress(
  166. IPV4_ADDRESS dwAddr
  167. )
  168. {
  169. // XXX test whether dwAddr is bound to any interface.
  170. // If we return FALSE, then an mtrace with this destination address
  171. // will be reinjected to be forwarded.
  172. return FALSE;
  173. }
  174. DWORD
  175. McSetRouterAlert(
  176. SOCKET s,
  177. BOOL bEnabled
  178. )
  179. {
  180. DWORD dwErr = NO_ERROR;
  181. int StartSnooping = bEnabled;
  182. int cbReturnedBytes;
  183. if ( WSAIoctl( s,
  184. SIO_ABSORB_RTRALERT,
  185. (char *)&StartSnooping,
  186. sizeof(StartSnooping),
  187. NULL,
  188. 0,
  189. &cbReturnedBytes,
  190. NULL,
  191. NULL) )
  192. {
  193. dwErr = WSAGetLastError();
  194. }
  195. return dwErr;
  196. }
  197. DWORD
  198. StartMcMisc(
  199. VOID
  200. )
  201. {
  202. DWORD dwErr = NO_ERROR, dwRetval;
  203. SOCKADDR_IN saLocalIf;
  204. Trace1(MCAST,
  205. "StartMcMisc() initiated with filever=%d",
  206. VER_PRODUCTBUILD);
  207. InitializeBoundaryTable();
  208. do
  209. {
  210. //
  211. // create input socket
  212. //
  213. McMiscSocket = WSASocket(AF_INET,
  214. SOCK_RAW,
  215. IPPROTO_IGMP,
  216. NULL,
  217. 0,
  218. 0);
  219. if (McMiscSocket == INVALID_SOCKET)
  220. {
  221. dwErr = WSAGetLastError();
  222. Trace1(MCAST,
  223. "error %d creating mrinfo/mtrace socket",
  224. dwErr);
  225. // LogErr1(CREATE_SOCKET_FAILED_2, lpszAddr, dwErr);
  226. break;
  227. }
  228. //
  229. // bind socket to any interface and port 0 (0 => doesnt matter)
  230. //
  231. saLocalIf.sin_family = PF_INET;
  232. saLocalIf.sin_addr.s_addr = INADDR_ANY;
  233. saLocalIf.sin_port = 0;
  234. //
  235. // bind the input socket
  236. //
  237. dwErr = bind(McMiscSocket,
  238. (SOCKADDR FAR *)&saLocalIf,
  239. sizeof(SOCKADDR));
  240. if (dwErr == SOCKET_ERROR)
  241. {
  242. dwErr = WSAGetLastError();
  243. Trace1(MCAST,
  244. "error %d binding on mrinfo/mtrace socket",
  245. dwErr);
  246. // LogErr1(BIND_FAILED, lpszAddr, dwErr);
  247. break;
  248. }
  249. Trace0(MCAST, "StartMcMisc: bind succeeded");
  250. //
  251. // to respond to mrinfo, and unicast mtraces, we don't need the
  252. // following.
  253. // To respond to mtrace queries which are multicast
  254. // (to the group being traced, to ALL-<proto>-ROUTERS, or
  255. // to ALL-ROUTERS), we do need this.
  256. //
  257. #if 0
  258. #ifdef SIO_RCVALL_HOST
  259. {
  260. //
  261. // put the socket in promiscuous igmp mode.
  262. // (no need to specify which protocol we want, as it's taken
  263. // from the protocol we used in the WSASocket() call above)
  264. //
  265. {
  266. DWORD dwEnable = 1;
  267. DWORD dwNum;
  268. dwRetval = WSAIoctl(McMiscSocket, SIO_RCVALL_HOST,
  269. (char *)&dwEnable, sizeof(dwEnable), NULL, 0, &dwNum,
  270. NULL, NULL);
  271. if (dwRetval !=0) {
  272. // LPSTR lpszAddr = "ANY";
  273. dwRetval = WSAGetLastError();
  274. Trace1(MCAST,
  275. "error %d setting mrinfo/mtrace socket as host-promiscuous IGMP",
  276. dwRetval);
  277. // LogErr1(SET_MCAST_IF_FAILED, lpszAddr, dwRetval);
  278. // Don't set dwErr in this case, since we can still
  279. // respond to unicast queries.
  280. break;
  281. } else {
  282. Trace0(MCAST, "host-promiscuous IGMP enabled on mrinfo/mtrace socket");
  283. }
  284. }
  285. }
  286. #endif
  287. #endif
  288. // Tell the kernel to hand us IGMP packets with the RouterAlert
  289. // option, even if they're not destined to us
  290. McSetRouterAlert( McMiscSocket, TRUE );
  291. //
  292. // Associate an event with the socket
  293. //
  294. if (WSAEventSelect(McMiscSocket,
  295. g_hMcMiscSocketEvent,
  296. FD_READ | FD_ADDRESS_LIST_CHANGE) == SOCKET_ERROR)
  297. {
  298. Trace1(MCAST,
  299. "StartMcMisc: WSAEventSelect() failed. Error %d",
  300. WSAGetLastError());
  301. closesocket(McMiscSocket);
  302. McMiscSocket = INVALID_SOCKET;
  303. continue;
  304. }
  305. } while(0);
  306. if (dwErr!=NO_ERROR)
  307. {
  308. StopMcMisc();
  309. }
  310. return dwErr;
  311. }
  312. VOID
  313. StopMcMisc(
  314. VOID
  315. )
  316. {
  317. Trace0(MCAST,
  318. "StopMcMisc() initiated");
  319. //
  320. // close input socket
  321. //
  322. if (McMiscSocket!=INVALID_SOCKET)
  323. {
  324. if (closesocket(McMiscSocket) == SOCKET_ERROR) {
  325. Trace1(MCAST,
  326. "error %d closing socket",
  327. WSAGetLastError());
  328. }
  329. McMiscSocket = INVALID_SOCKET;
  330. }
  331. Trace0(MCAST, "StopMcMisc() complete");
  332. return;
  333. }
  334. VOID
  335. HandleMcMiscMessages(
  336. VOID
  337. )
  338. /*++
  339. Routine Description:
  340. Accepts mrinfo and mtrace messages and hands them off to the appropriate
  341. routine.
  342. Also called to handle address change notification
  343. Locks:
  344. Acquires the ICB lock as reader if processing Mc messages
  345. Arguments:
  346. None
  347. Return Value:
  348. None
  349. --*/
  350. {
  351. DWORD dwErr, dwNumBytes, dwFlags, dwAddrLen, dwSizeOfHeader;
  352. DWORD dwDataLen;
  353. SOCKADDR_IN sinFrom;
  354. PIGMP_HEADER pIgmpMsg;
  355. PIP_HEADER pIpHeader;
  356. BOOL bSetIoctl, bUnlock;
  357. WSANETWORKEVENTS NetworkEvents;
  358. bSetIoctl = FALSE;
  359. bUnlock = FALSE;
  360. do
  361. {
  362. //
  363. // Figure out if its an address change or read
  364. //
  365. dwErr = WSAEnumNetworkEvents(McMiscSocket,
  366. g_hMcMiscSocketEvent,
  367. &NetworkEvents);
  368. if(dwErr isnot NO_ERROR)
  369. {
  370. bSetIoctl = TRUE;
  371. Trace1(ERR,
  372. "HandleMcMiscMessages: Error %d from WSAEnumNetworkEvents",
  373. WSAGetLastError());
  374. break;
  375. }
  376. if(NetworkEvents.lNetworkEvents & FD_ADDRESS_LIST_CHANGE)
  377. {
  378. bSetIoctl = TRUE;
  379. dwErr = NetworkEvents.iErrorCode[FD_ADDRESS_LIST_CHANGE_BIT];
  380. Trace0(GLOBAL,
  381. "HandleMcMiscMessages: Received Address change notification");
  382. if(dwErr isnot NO_ERROR)
  383. {
  384. Trace1(ERR,
  385. "HandleMcMiscMessages: ErrorCode %d",
  386. dwErr);
  387. break;
  388. }
  389. //
  390. // All's good, handle the binding change
  391. //
  392. HandleAddressChangeNotification();
  393. break;
  394. }
  395. ENTER_READER(ICB_LIST);
  396. bUnlock = TRUE;
  397. //
  398. // read the incoming packet
  399. //
  400. dwAddrLen = sizeof(sinFrom);
  401. dwFlags = 0;
  402. dwErr = WSARecvFrom(McMiscSocket,
  403. &g_wsaMcRcvBuf,
  404. 1,
  405. &dwNumBytes,
  406. &dwFlags,
  407. (SOCKADDR FAR *)&sinFrom,
  408. &dwAddrLen,
  409. NULL,
  410. NULL);
  411. //
  412. // check if any error in reading packet
  413. //
  414. if ((dwErr!=0) || (dwNumBytes==0))
  415. {
  416. // LPSTR lpszAddr = "ANY";
  417. dwErr = WSAGetLastError();
  418. Trace1(MCAST,
  419. "HandleMcMiscMessages: Error %d receiving IGMP packet",
  420. dwErr);
  421. // LogErr1(RECVFROM_FAILED, lpszAddr, dwErr);
  422. break;
  423. }
  424. pIpHeader = (PIP_HEADER)g_wsaMcRcvBuf.buf;
  425. dwSizeOfHeader = ((pIpHeader->byVerLen)&0x0f)<<2;
  426. pIgmpMsg = (PIGMP_HEADER)(((PBYTE)pIpHeader) + dwSizeOfHeader);
  427. dwDataLen = ntohs(pIpHeader->wLength) - dwSizeOfHeader;
  428. if (g_mcastDebugLevel > 0)
  429. {
  430. Trace4(MCAST,
  431. "HandleMcMiscMessages: Type is %d (0x%x), code %d (0x%x).",
  432. (DWORD)pIgmpMsg->byType,
  433. (DWORD)pIgmpMsg->byType,
  434. (DWORD)pIgmpMsg->byCode,
  435. (DWORD)pIgmpMsg->byCode);
  436. Trace2(MCAST,
  437. "HandleMcMiscMessages: IP Length is %d. Header Length %d",
  438. ntohs(pIpHeader->wLength),
  439. dwSizeOfHeader);
  440. Trace2(MCAST,
  441. "HandleMcMiscMessages: Src: %d.%d.%d.%d dest: %d.%d.%d.%d",
  442. PRINT_IPADDR(pIpHeader->dwSrc),
  443. PRINT_IPADDR(pIpHeader->dwDest));
  444. TraceDump(TRACEID,(PBYTE)pIpHeader,dwNumBytes,2,FALSE,NULL);
  445. }
  446. //
  447. // Verify minimum length
  448. //
  449. if (dwNumBytes < MIN_IGMP_PACKET_SIZE)
  450. {
  451. Trace2(MCAST,
  452. "%d-byte packet from %d.%d.%d.%d is too small",
  453. dwNumBytes,
  454. PRINT_IPADDR(pIpHeader->dwSrc));
  455. break;
  456. }
  457. //
  458. // Check for mal-formed packets that might report bad lengths
  459. //
  460. if (dwDataLen > (dwNumBytes - dwSizeOfHeader))
  461. {
  462. Trace3(MCAST,
  463. "%d-byte packet from %d.%d.%d.%d is smaller than "
  464. "indicated length %d", dwNumBytes,
  465. PRINT_IPADDR(pIpHeader->dwSrc),
  466. dwDataLen);
  467. break;
  468. }
  469. //
  470. // Verify IGMP checksum
  471. //
  472. if (Compute16BitXSum((PVOID)pIgmpMsg, dwDataLen) != 0)
  473. {
  474. Trace4( MCAST,
  475. "Wrong IGMP checksum %d-byte packet received from %d.%d.%d.%d, type %d.%d",
  476. dwDataLen,
  477. PRINT_IPADDR(pIpHeader->dwSrc),
  478. pIgmpMsg->byType, pIgmpMsg->byCode );
  479. break;
  480. }
  481. if (pIgmpMsg->byType is IGMP_DVMRP
  482. && pIgmpMsg->byCode is DVMRP_ASK_NEIGHBORS2)
  483. {
  484. SOCKADDR_IN sinDestAddr;
  485. sinDestAddr.sin_family = PF_INET;
  486. sinDestAddr.sin_addr.s_addr = pIpHeader->dwSrc;
  487. sinDestAddr.sin_port = 0;
  488. HandleMrinfoRequest((IPV4_ADDRESS)pIpHeader->dwDest,
  489. &sinDestAddr
  490. );
  491. }
  492. else
  493. {
  494. if (pIgmpMsg->byType is IGMP_MTRACE_REQUEST)
  495. {
  496. HandleMtraceRequest(&g_wsaMcRcvBuf);
  497. }
  498. }
  499. } while (FALSE);
  500. if(bSetIoctl)
  501. {
  502. dwErr = WSAIoctl(McMiscSocket,
  503. SIO_ADDRESS_LIST_CHANGE,
  504. NULL,
  505. 0,
  506. NULL,
  507. 0,
  508. &dwNumBytes,
  509. NULL,
  510. NULL);
  511. if(dwErr is SOCKET_ERROR)
  512. {
  513. dwErr = WSAGetLastError();
  514. if((dwErr isnot WSAEWOULDBLOCK) and
  515. (dwErr isnot WSA_IO_PENDING) and
  516. (dwErr isnot NO_ERROR))
  517. {
  518. Trace1(ERR,
  519. "HandleMcMiscMessages: Error %d from SIO_ADDRESS_LIST_CHANGE",
  520. dwErr);
  521. }
  522. }
  523. }
  524. if(bUnlock)
  525. {
  526. EXIT_LOCK(ICB_LIST);
  527. }
  528. }
  529. DWORD
  530. FindBindingWithLocalAddress(
  531. OUT PICB *ppicb,
  532. OUT PIPV4_ADDRESS pdwIfAddress,
  533. IN IPV4_ADDRESS dwAddress
  534. )
  535. {
  536. BOOL bFound = FALSE;
  537. PLIST_ENTRY pleNode;
  538. IPV4_ADDRESS ipFoundMask;
  539. //
  540. // Lock the ICBList for reading
  541. //
  542. ENTER_READER(ICB_LIST);
  543. for (pleNode = ICBList.Flink;
  544. pleNode isnot &ICBList && !bFound;
  545. pleNode = pleNode->Flink)
  546. {
  547. DWORD dwIndex;
  548. PICB picb;
  549. picb = CONTAINING_RECORD(pleNode,
  550. ICB,
  551. leIfLink);
  552. for (dwIndex=0;
  553. dwIndex<picb->dwNumAddresses && !bFound;
  554. dwIndex++)
  555. {
  556. PICB_BINDING pb = &picb->pibBindings[dwIndex];
  557. if (dwAddress == pb->dwAddress)
  558. {
  559. *pdwIfAddress = pb->dwAddress;
  560. *ppicb = picb;
  561. bFound = TRUE;
  562. }
  563. }
  564. }
  565. EXIT_LOCK(ICB_LIST);
  566. if (bFound)
  567. {
  568. return NO_ERROR;
  569. }
  570. *ppicb = NULL;
  571. return ERROR_INVALID_PARAMETER;
  572. }
  573. BOOL
  574. IsConnectedTo(
  575. IN PICB picb,
  576. IN IPV4_ADDRESS ipAddress,
  577. OUT PIPV4_ADDRESS pipLocalAddress OPTIONAL,
  578. OUT PIPV4_ADDRESS pipMask OPTIONAL
  579. )
  580. {
  581. DWORD dwIndex;
  582. BOOL bFound = FALSE;
  583. IPV4_ADDRESS ipFoundMask = 0;
  584. if (picb->dwRemoteAddress is ipAddress)
  585. {
  586. if (pipLocalAddress)
  587. {
  588. *pipLocalAddress = defaultSourceAddress(picb);
  589. }
  590. if (pipMask)
  591. {
  592. *pipMask = ALL_ONES_MASK;
  593. }
  594. return TRUE;
  595. }
  596. // Find interface with longest match
  597. for (dwIndex=0;
  598. dwIndex<picb->dwNumAddresses && !bFound;
  599. dwIndex++)
  600. {
  601. PICB_BINDING pb = &picb->pibBindings[dwIndex];
  602. if (((ipAddress & pb->dwMask) is (pb->dwAddress & pb->dwMask))
  603. && (!bFound || (pb->dwMask > ipFoundMask)))
  604. {
  605. if (pipLocalAddress)
  606. {
  607. *pipLocalAddress = pb->dwAddress;
  608. }
  609. bFound = TRUE;
  610. ipFoundMask = pb->dwMask;
  611. }
  612. }
  613. if (pipMask)
  614. {
  615. *pipMask = ipFoundMask;
  616. }
  617. return bFound;
  618. }
  619. DWORD
  620. FindBindingWithRemoteAddress(
  621. OUT PICB *ppicb,
  622. OUT PIPV4_ADDRESS pdwIfAddress,
  623. IN IPV4_ADDRESS dwAddress
  624. )
  625. {
  626. BOOL bFound = FALSE;
  627. PLIST_ENTRY pleNode;
  628. IPV4_ADDRESS ipFoundMask, ipMask, ipLocalAddress;
  629. //
  630. // Lock the ICBList for reading
  631. //
  632. ENTER_READER(ICB_LIST);
  633. for (pleNode = ICBList.Flink;
  634. pleNode isnot &ICBList;
  635. pleNode = pleNode->Flink)
  636. {
  637. DWORD dwIndex;
  638. PICB picb;
  639. picb = CONTAINING_RECORD(pleNode,
  640. ICB,
  641. leIfLink);
  642. if (IsConnectedTo(picb, dwAddress, &ipLocalAddress, &ipMask)
  643. && (!bFound || (ipMask > ipFoundMask)))
  644. {
  645. *pdwIfAddress = ipLocalAddress;
  646. *ppicb = picb;
  647. bFound = TRUE;
  648. ipFoundMask = ipMask;
  649. }
  650. }
  651. EXIT_LOCK(ICB_LIST);
  652. if (bFound)
  653. {
  654. return NO_ERROR;
  655. }
  656. *ppicb = NULL;
  657. return ERROR_INVALID_PARAMETER;
  658. }
  659. DWORD
  660. FindBindingForPacket(
  661. IN PIP_HEADER pIpHeader,
  662. OUT PICB *ppicb,
  663. OUT IPV4_ADDRESS *pdwIfAddr
  664. )
  665. {
  666. DWORD dwResult;
  667. dwResult = FindBindingWithRemoteAddress(ppicb,
  668. pdwIfAddr,
  669. pIpHeader->dwSrc);
  670. if (dwResult == NO_ERROR)
  671. {
  672. return dwResult;
  673. }
  674. dwResult = FindBindingWithRemoteAddress(ppicb,
  675. pdwIfAddr,
  676. pIpHeader->dwDest);
  677. return dwResult;
  678. }
  679. VOID
  680. HandleMrinfoRequest(
  681. IPV4_ADDRESS dwLocalAddr,
  682. SOCKADDR_IN *sinDestAddr
  683. )
  684. /*++
  685. Routine Description:
  686. Accepts an mrinfo request and sends a reply.
  687. Locks:
  688. Arguments:
  689. Return Value:
  690. --*/
  691. {
  692. DWORD dwNumBytesSent, dwResult, dwSize = sizeof(MRINFO_HEADER);
  693. WSABUF wsMrinfoBuffer;
  694. MRINFO_HEADER *mriHeader;
  695. DWORD dwBufSize;
  696. IPV4_ADDRESS dwIfAddr;
  697. PLIST_ENTRY pleNode, pleNode2;
  698. PICB picb;
  699. PBYTE pb;
  700. BYTE byIfFlags;
  701. BOOL bForMe;
  702. //
  703. // If the query was not destined to me, drop it.
  704. //
  705. dwResult = FindBindingWithLocalAddress(&picb,
  706. &dwIfAddr,
  707. dwLocalAddr);
  708. if (dwResult != NO_ERROR)
  709. {
  710. return;
  711. }
  712. //
  713. // Lock the ICBList for reading
  714. //
  715. ENTER_READER(ICB_LIST);
  716. do
  717. {
  718. //
  719. // Calculate required size of response packet
  720. //
  721. for (pleNode = ICBList.Flink;
  722. pleNode isnot &ICBList;
  723. pleNode = pleNode->Flink)
  724. {
  725. PPROTO_CB pOwner, pQuerier;
  726. picb = CONTAINING_RECORD(pleNode,
  727. ICB,
  728. leIfLink);
  729. dwResult = MulticastOwner(picb,
  730. &pOwner,
  731. &pQuerier);
  732. //
  733. // If we didn't find an owner, then we can skip this
  734. // interface, since we're not doing multicast routing on it.
  735. //
  736. if (!pOwner)
  737. {
  738. continue;
  739. }
  740. if (picb->dwNumAddresses > 0)
  741. {
  742. //
  743. // add iface size per address
  744. //
  745. dwSize += 8+4*picb->dwNumAddresses;
  746. }
  747. else
  748. {
  749. //
  750. // add single address size for unnumbered iface
  751. //
  752. dwSize += 12;
  753. }
  754. //
  755. // Call the owner's GetNeighbors() entrypoint
  756. // with a NULL buffer. This will cause it to tell us the size of
  757. // its neighbor set
  758. //
  759. dwBufSize = 0;
  760. byIfFlags = 0;
  761. //
  762. // mrouted doesn't report multiple subnets,
  763. // so neither do we. Just group all neighbors
  764. // together on an interface.
  765. //
  766. dwResult = (pOwner->pfnGetNeighbors)(picb->dwIfIndex,
  767. NULL,
  768. &dwBufSize,
  769. &byIfFlags);
  770. if ((dwResult isnot NO_ERROR) and
  771. (dwResult isnot ERROR_INSUFFICIENT_BUFFER))
  772. {
  773. //
  774. // The only errors which will tell us the size needed are
  775. // NO_ERROR and ERROR_INSUFFICIENT_BUFFER. Anything else
  776. // means we didn't get the right size
  777. //
  778. Trace2(MCAST,
  779. "HandleMrinfoRequest: Error %d in GetNeighbours for %S",
  780. dwResult,
  781. pOwner->pwszDisplayName);
  782. continue;
  783. }
  784. dwSize += dwBufSize;
  785. }
  786. //
  787. // We can now malloc a buffer and fill in the info
  788. //
  789. wsMrinfoBuffer.len = dwSize;
  790. wsMrinfoBuffer.buf = HeapAlloc(IPRouterHeap,
  791. 0,
  792. dwSize);
  793. if(wsMrinfoBuffer.buf is NULL)
  794. {
  795. EXIT_LOCK(ICB_LIST);
  796. return;
  797. }
  798. mriHeader = (PMRINFO_HEADER)wsMrinfoBuffer.buf;
  799. mriHeader->byType = IGMP_DVMRP;
  800. mriHeader->byCode = DVMRP_NEIGHBORS2;
  801. mriHeader->wChecksum = 0;
  802. mriHeader->byReserved = 0;
  803. //
  804. // MRINFO_CAP_MTRACE - set if mtrace handler is available
  805. // MRINFO_CAP_SNMP - set if public IP Multicast MIB is available
  806. // MRINFO_CAP_GENID - set if DVMRP 3.255 is available
  807. // MRINFO_CAP_PRUNE - set if DVMRP 3.255 is available
  808. //
  809. mriHeader->byCapabilities = MRINFO_CAP_MTRACE | MRINFO_CAP_SNMP;
  810. mriHeader->byMinor = VER_PRODUCTBUILD % 100;
  811. mriHeader->byMajor = VER_PRODUCTBUILD / 100;
  812. //
  813. // Need to get a list of interfaces, and a list of neighbors
  814. // (and their info) per interface, updating dwSize as we go.
  815. //
  816. pb = ((PBYTE) wsMrinfoBuffer.buf) + sizeof(MRINFO_HEADER);
  817. for (pleNode = ICBList.Flink;
  818. pleNode isnot &ICBList;
  819. pleNode = pleNode->Flink)
  820. {
  821. PBYTE pbNbrCount, pfIfFlags;
  822. PPROTO_CB pOwner, pQuerier;
  823. picb = CONTAINING_RECORD(pleNode,
  824. ICB,
  825. leIfLink);
  826. dwResult = MulticastOwner(picb,
  827. &pOwner,
  828. &pQuerier);
  829. //
  830. // If we didn't find an owner, then we can skip this
  831. // interface, since we're not doing multicast routing on it.
  832. //
  833. if (!pOwner)
  834. {
  835. continue;
  836. }
  837. //
  838. // Fill in interface info
  839. //
  840. *(PIPV4_ADDRESS)pb = defaultSourceAddress(picb);
  841. pb += 4;
  842. *pb++ = 1; // currently metric must be 1
  843. *pb++ = (BYTE)picb->dwMcastTtl; // threshold
  844. *pb = 0;
  845. //
  846. // Right now, we only report IP-in-IP tunnels with the tunnel flag
  847. // In the future, a tunnel should have its own MIB-II ifType
  848. // value, which should be stored in the ICB structure so we can
  849. // get at it.
  850. //
  851. if (picb->ritType is ROUTER_IF_TYPE_TUNNEL1)
  852. {
  853. //
  854. // neighbor reached via tunnel
  855. //
  856. *pb |= MRINFO_TUNNEL_FLAG;
  857. }
  858. if (picb->dwOperationalState < IF_OPER_STATUS_CONNECTED)
  859. {
  860. //
  861. // operational status down
  862. //
  863. *pb |= MRINFO_DOWN_FLAG;
  864. }
  865. if (picb->dwAdminState is IF_ADMIN_STATUS_DOWN)
  866. {
  867. //
  868. // administrative status down
  869. //
  870. *pb |= MRINFO_DISABLED_FLAG;
  871. }
  872. pfIfFlags = pb++; // save pointer for later updating
  873. pbNbrCount = pb++; // save pointer to neighbor count location
  874. *pbNbrCount = 0;
  875. //
  876. // Call the routing protocol's GetNeighbors() entrypoint
  877. // with a pointer into the middle of the current packet buffer.
  878. //
  879. dwBufSize = dwSize - (DWORD)(pb-(PBYTE)wsMrinfoBuffer.buf);
  880. byIfFlags = 0;
  881. dwResult = (pOwner->pfnGetNeighbors)(picb->dwIfIndex,
  882. (PDWORD)pb,
  883. &dwBufSize,
  884. &byIfFlags);
  885. if (dwBufSize>0)
  886. {
  887. pb += dwBufSize;
  888. (*pbNbrCount)+= (BYTE)(dwBufSize / sizeof(DWORD));
  889. }
  890. else
  891. {
  892. //
  893. // If the protocol has no neighbors, we fill in 0.0.0.0
  894. // because the mrinfo client most people use
  895. // won't display the flags, metric, and threshold
  896. // unless the neighbors count is non-zero. 0.0.0.0
  897. // is legal according to the spec.
  898. //
  899. *(PDWORD)pb = 0;
  900. pb += sizeof(DWORD);
  901. (*pbNbrCount)++;
  902. }
  903. //
  904. // set pim/querier/whatever bits
  905. //
  906. *pfIfFlags |= byIfFlags;
  907. //
  908. // Get querier flag
  909. //
  910. if (pQuerier isnot NULL && pQuerier isnot pOwner)
  911. {
  912. byIfFlags = 0;
  913. dwBufSize = 0;
  914. dwResult = (pQuerier->pfnGetNeighbors)(picb->dwIfIndex,
  915. NULL,
  916. &dwBufSize,
  917. &byIfFlags);
  918. *pfIfFlags |= byIfFlags;
  919. }
  920. }
  921. } while (FALSE);
  922. EXIT_LOCK(ICB_LIST);
  923. //
  924. // Fill in Checksum
  925. //
  926. mriHeader->wChecksum = Compute16BitXSum(wsMrinfoBuffer.buf,
  927. dwSize);
  928. if (g_mcastDebugLevel > 0)
  929. {
  930. Trace2(MCAST,
  931. "HandleMrinfoRequest: sending reply to %d.%d.%d.%d. Len %d",
  932. PRINT_IPADDR(sinDestAddr->sin_addr.s_addr),
  933. wsMrinfoBuffer.len);
  934. }
  935. //
  936. // Send it off
  937. //
  938. if(WSASendTo(McMiscSocket,
  939. &wsMrinfoBuffer,
  940. 1,
  941. &dwNumBytesSent,
  942. 0,
  943. (const struct sockaddr *)sinDestAddr,
  944. sizeof(SOCKADDR_IN),
  945. NULL,
  946. NULL) == SOCKET_ERROR)
  947. {
  948. dwResult = WSAGetLastError();
  949. Trace2(MCAST,
  950. "HandleMrinfoRequest: Err %d sending reply to %d.%d.%d.%d",
  951. dwResult,
  952. PRINT_IPADDR(sinDestAddr->sin_addr.s_addr));
  953. }
  954. //
  955. // Free the buffer
  956. //
  957. HeapFree(IPRouterHeap,
  958. 0,
  959. wsMrinfoBuffer.buf);
  960. }
  961. //
  962. // This function is derived from NTTimeToNTPTime() in
  963. // src\sockets\tcpcmd\iphlpapi\mscapis.cxx
  964. //
  965. DWORD
  966. GetCurrentNTP32Time(
  967. VOID
  968. )
  969. /*++
  970. Routine Description:
  971. Get current 32-bit NTP timestamp. The 32-bit form of an NTP timestamp
  972. consists of the middle 32 bits of the full 64-bit form; that is, the low
  973. 16 bits of the integer part and the high 16 bits of the fractional part.
  974. Locks:
  975. Arguments:
  976. Return Value:
  977. --*/
  978. {
  979. static LARGE_INTEGER li1900 = {0xfde04000, 0x14f373b};
  980. LARGE_INTEGER liTime;
  981. DWORD dwMs;
  982. ULONG hi, lo;
  983. GetSystemTimeAsFileTime((LPFILETIME)&liTime);
  984. //
  985. // Seconds is simply the time difference
  986. //
  987. hi = htonl((ULONG)((liTime.QuadPart - li1900.QuadPart) / 10000000));
  988. //
  989. // Ms is the residue from the seconds calculation.
  990. //
  991. dwMs = (DWORD)(((liTime.QuadPart - li1900.QuadPart) % 10000000) / 10000);
  992. //
  993. // time base in the beginning of the year 1900
  994. //
  995. lo = htonl((unsigned long)(.5+0xFFFFFFFF*(double)(dwMs/1000.0)));
  996. return (hi << 16) | (lo >> 16);
  997. }
  998. IPV4_ADDRESS
  999. IfIndexToIpAddress(
  1000. DWORD dwIfIndex
  1001. )
  1002. {
  1003. // Locate picb
  1004. PICB picb = InterfaceLookupByIfIndex(dwIfIndex);
  1005. return (picb)? defaultSourceAddress(picb) : 0;
  1006. }
  1007. DWORD
  1008. McSetMulticastIfByIndex(
  1009. SOCKET s,
  1010. DWORD dwSockType,
  1011. DWORD dwIfIndex
  1012. )
  1013. {
  1014. DWORD dwNum, dwErr;
  1015. IPV4_ADDRESS ipAddr;
  1016. #ifdef RAW_UNNUMBERED_SUPPORT
  1017. if ((dwSockType is SOCK_RAW)
  1018. #ifdef UDP_UNNUMBERED_SUPPORT
  1019. || (dwSockType is SOCK_DGRAM)
  1020. #endif
  1021. )
  1022. {
  1023. dwErr = WSAIoctl( s,
  1024. SIO_INDEX_MCASTIF,
  1025. (char*)&dwIfIndex,
  1026. sizeof(dwIfIndex),
  1027. NULL,
  1028. 0,
  1029. &dwNum,
  1030. NULL,
  1031. NULL );
  1032. return dwErr;
  1033. }
  1034. #endif
  1035. //
  1036. // If we can't set oif to an ifIndex yet, then we
  1037. // attempt to map it to some IP address
  1038. //
  1039. ipAddr = IfIndexToIpAddress(dwIfIndex);
  1040. if (!ipAddr)
  1041. return ERROR_INVALID_PARAMETER;
  1042. return McSetMulticastIf( s, ipAddr );
  1043. }
  1044. DWORD
  1045. McSetMulticastIf(
  1046. SOCKET s,
  1047. IPV4_ADDRESS ipAddr
  1048. )
  1049. {
  1050. SOCKADDR_IN saSrcAddr;
  1051. saSrcAddr.sin_family = AF_INET;
  1052. saSrcAddr.sin_port = 0;
  1053. saSrcAddr.sin_addr.s_addr = ipAddr;
  1054. return setsockopt( s,
  1055. IPPROTO_IP,
  1056. IP_MULTICAST_IF,
  1057. (char *)&saSrcAddr.sin_addr,
  1058. sizeof(IN_ADDR) );
  1059. }
  1060. DWORD
  1061. McSetMulticastTtl(
  1062. SOCKET s,
  1063. DWORD dwTtl
  1064. )
  1065. {
  1066. return setsockopt( s,
  1067. IPPROTO_IP,
  1068. IP_MULTICAST_TTL,
  1069. (char *)&dwTtl,
  1070. sizeof(dwTtl) );
  1071. }
  1072. DWORD
  1073. McJoinGroupByIndex(
  1074. IN SOCKET s,
  1075. IN DWORD dwSockType,
  1076. IN IPV4_ADDRESS ipGroup,
  1077. IN DWORD dwIfIndex
  1078. )
  1079. {
  1080. struct ip_mreq imOption;
  1081. IPV4_ADDRESS ipInterface;
  1082. #ifdef RAW_UNNUMBERED_SUPPORT
  1083. if ((dwSockType is SOCK_RAW)
  1084. #ifdef UDP_UNNUMBERED_SUPPORT
  1085. || (dwSockType is SOCK_DGRAM)
  1086. #endif
  1087. )
  1088. {
  1089. DWORD dwNum, dwErr;
  1090. imOption.imr_multiaddr.s_addr = ipGroup;
  1091. imOption.imr_interface.s_addr = dwIfIndex;
  1092. dwErr = WSAIoctl( s,
  1093. SIO_INDEX_ADD_MCAST,
  1094. (char*)&imOption,
  1095. sizeof(imOption),
  1096. NULL,
  1097. 0,
  1098. &dwNum,
  1099. NULL,
  1100. NULL );
  1101. return dwErr;
  1102. }
  1103. #endif
  1104. ipInterface = IfIndexToIpAddress(ntohl(dwIfIndex));
  1105. if (!ipInterface)
  1106. {
  1107. Trace1(MCAST, "McJoinGroup: bad IfIndex 0x%x", ntohl(ipInterface));
  1108. return ERROR_INVALID_PARAMETER;
  1109. }
  1110. return McJoinGroup( s, ipGroup, ipInterface );
  1111. }
  1112. DWORD
  1113. McJoinGroup(
  1114. IN SOCKET s,
  1115. IN IPV4_ADDRESS ipGroup,
  1116. IN IPV4_ADDRESS ipInterface
  1117. )
  1118. /*++
  1119. Description:
  1120. Joins a group on a given interface.
  1121. Called by:
  1122. Locks:
  1123. None
  1124. --*/
  1125. {
  1126. struct ip_mreq imOption;
  1127. imOption.imr_multiaddr.s_addr = ipGroup;
  1128. imOption.imr_interface.s_addr = ipInterface;
  1129. return setsockopt( s,
  1130. IPPROTO_IP,
  1131. IP_ADD_MEMBERSHIP,
  1132. (PBYTE)&imOption,
  1133. sizeof(imOption));
  1134. }
  1135. DWORD
  1136. McSendPacketTo(
  1137. SOCKET s,
  1138. WSABUF *pWsabuf,
  1139. IPV4_ADDRESS dest
  1140. )
  1141. {
  1142. DWORD dwSent, dwRet;
  1143. int iSetIp = 1;
  1144. SOCKADDR_IN to;
  1145. // Set header include
  1146. setsockopt( s,
  1147. IPPROTO_IP,
  1148. IP_HDRINCL,
  1149. (char *) &iSetIp,
  1150. sizeof(int) );
  1151. // Send the packet
  1152. to.sin_family = AF_INET;
  1153. to.sin_port = 0;
  1154. to.sin_addr.s_addr = dest;
  1155. dwRet = WSASendTo( s,
  1156. pWsabuf,
  1157. 1,
  1158. &dwSent,
  1159. 0,
  1160. (const struct sockaddr FAR *)&to,
  1161. sizeof(to),
  1162. NULL, NULL );
  1163. // Clear header include
  1164. iSetIp = 0;
  1165. setsockopt( s,
  1166. IPPROTO_IP,
  1167. IP_HDRINCL,
  1168. (char *) &iSetIp,
  1169. sizeof(int) );
  1170. return dwRet;
  1171. }
  1172. DWORD
  1173. ForwardMtraceRequest(
  1174. IPV4_ADDRESS dwForwardDest,
  1175. IPV4_ADDRESS dwForwardSrc,
  1176. PMTRACE_HEADER pMtraceMsg,
  1177. DWORD dwMessageLength
  1178. )
  1179. /*++
  1180. Routine Description:
  1181. Pass an mtrace request to the next router upstream
  1182. Locks:
  1183. Arguments:
  1184. Return Value:
  1185. --*/
  1186. {
  1187. SOCKADDR_IN saDestAddr;
  1188. INT iLength;
  1189. DWORD dwErr = NO_ERROR;
  1190. //
  1191. // Recalculate Checksum
  1192. //
  1193. pMtraceMsg->wChecksum = 0;
  1194. pMtraceMsg->wChecksum = Compute16BitXSum((PVOID)pMtraceMsg,
  1195. dwMessageLength);
  1196. if (dwForwardSrc && IN_MULTICAST(ntohl(dwForwardDest)))
  1197. {
  1198. dwErr = McSetMulticastIf( McMiscSocket, dwForwardSrc );
  1199. }
  1200. //
  1201. // Send it off
  1202. //
  1203. saDestAddr.sin_family = AF_INET;
  1204. saDestAddr.sin_port = 0;
  1205. saDestAddr.sin_addr.s_addr = dwForwardDest;
  1206. iLength = sendto(McMiscSocket,
  1207. (PBYTE)pMtraceMsg,
  1208. dwMessageLength,
  1209. 0,
  1210. (PSOCKADDR) &saDestAddr,
  1211. sizeof(SOCKADDR_IN));
  1212. return dwErr;
  1213. }
  1214. VOID
  1215. SendMtraceResponse(
  1216. IPV4_ADDRESS dwForwardDest,
  1217. IPV4_ADDRESS dwForwardSrc,
  1218. PMTRACE_HEADER pMtraceMsg,
  1219. DWORD dwMessageLength
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. Send a reply to the response address
  1224. Locks:
  1225. Arguments:
  1226. Return Value:
  1227. --*/
  1228. {
  1229. SOCKADDR_IN saDestAddr;
  1230. INT iLength;
  1231. //
  1232. // Source Address can be any of our addresses, but should
  1233. // be one which is in the multicast routing table if that
  1234. // can be determined.
  1235. // XXX
  1236. //
  1237. //
  1238. // If the response address is multicast, use the TTL supplied in the header
  1239. //
  1240. if (IN_MULTICAST(ntohl(dwForwardDest)))
  1241. {
  1242. DWORD dwTtl, dwErr;
  1243. //
  1244. // Copy Response TTL from traceroute header into IP header
  1245. //
  1246. dwErr = McSetMulticastTtl( McMiscSocket, (DWORD)pMtraceMsg->byRespTtl );
  1247. }
  1248. //
  1249. // Change message type to response
  1250. //
  1251. pMtraceMsg->byType = IGMP_MTRACE_RESPONSE;
  1252. ForwardMtraceRequest(dwForwardDest,
  1253. dwForwardSrc,
  1254. pMtraceMsg,
  1255. dwMessageLength);
  1256. }
  1257. BYTE
  1258. MaskToMaskLen(
  1259. IPV4_ADDRESS dwMask
  1260. )
  1261. {
  1262. register int i;
  1263. dwMask = ntohl(dwMask);
  1264. for (i=0; i<32 && !(dwMask & (1<<i)); i++);
  1265. return 32-i;
  1266. }
  1267. //
  1268. // Test whether an interface is a p2p interface.
  1269. //
  1270. DWORD
  1271. IsPointToPoint(
  1272. PICB picb
  1273. )
  1274. {
  1275. // all tunnels are p2p
  1276. if (picb->ritType == ROUTER_IF_TYPE_TUNNEL1)
  1277. return 1;
  1278. // all unnumbered interfaces are p2p
  1279. if (! picb->dwNumAddresses)
  1280. return 1;
  1281. // a numbered interface with a /32 mask is p2p
  1282. if (picb->pibBindings[0].dwMask == 0xFFFFFFFF)
  1283. return 1;
  1284. // everything else isn't
  1285. return 0;
  1286. }
  1287. //
  1288. // Look up route to S or G ***in the M-RIB***
  1289. // XXX We actually need to query the MGM to get the right route
  1290. // from the routing protocol. Since the MGM doesn't let us do
  1291. // this yet, we'll make a good guess for now. This will work for
  1292. // BGMP but not for PIM-SM (*,G) or CBT.
  1293. //
  1294. BOOL
  1295. McLookupRoute(
  1296. IN IPV4_ADDRESS ipAddress,
  1297. IN BOOL bSkipFirst,
  1298. OUT PBYTE pbySrcMaskLength,
  1299. OUT PIPV4_ADDRESS pipNextHopAddress,
  1300. OUT PDWORD pdwNextHopIfIndex,
  1301. OUT PDWORD pdwNextHopProtocol
  1302. )
  1303. #ifdef HAVE_RTMV2
  1304. {
  1305. RTM_DEST_INFO rdi, rdi2;
  1306. PRTM_ROUTE_INFO pri;
  1307. RTM_NEXTHOP_INFO nhi;
  1308. RTM_ENTITY_INFO rei;
  1309. RTM_NET_ADDRESS naAddress;
  1310. BOOL bRouteFound = FALSE;
  1311. DWORD dwErr;
  1312. pri = HeapAlloc(
  1313. IPRouterHeap,
  1314. 0,
  1315. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  1316. );
  1317. if (pri == NULL)
  1318. {
  1319. return FALSE;
  1320. }
  1321. RTM_IPV4_MAKE_NET_ADDRESS(&naAddress, ipAddress, 32);
  1322. dwErr = RtmGetMostSpecificDestination( g_hLocalRoute,
  1323. &naAddress,
  1324. RTM_BEST_PROTOCOL,
  1325. RTM_VIEW_MASK_MCAST,
  1326. &rdi );
  1327. if (bSkipFirst)
  1328. {
  1329. dwErr = RtmGetLessSpecificDestination( g_hLocalRoute,
  1330. rdi.DestHandle,
  1331. RTM_BEST_PROTOCOL,
  1332. RTM_VIEW_MASK_MCAST,
  1333. &rdi2 );
  1334. RtmReleaseDestInfo( g_hLocalRoute, &rdi);
  1335. memcpy(&rdi, &rdi2, sizeof(rdi));
  1336. }
  1337. if (dwErr is NO_ERROR)
  1338. {
  1339. ASSERT( rdi.ViewInfo[0].ViewId is RTM_VIEW_ID_MCAST);
  1340. dwErr = RtmGetRouteInfo( g_hLocalRoute,
  1341. rdi.ViewInfo[0].Route,
  1342. pri,
  1343. NULL );
  1344. if (dwErr is NO_ERROR)
  1345. {
  1346. ULONG ulNHopIdx;
  1347. ULONG ulDummyLen;
  1348. bRouteFound = TRUE;
  1349. RtmGetEntityInfo( g_hLocalRoute,
  1350. pri->RouteOwner,
  1351. &rei );
  1352. // XXX Use 1st next hop for now. Should query MGM.
  1353. ulNHopIdx = 0;
  1354. if (RtmGetNextHopInfo( g_hLocalRoute,
  1355. pri->NextHopsList.NextHops[ulNHopIdx],
  1356. &nhi ) is NO_ERROR )
  1357. {
  1358. RTM_IPV4_GET_ADDR_AND_LEN( *pipNextHopAddress,
  1359. ulDummyLen,
  1360. &nhi.NextHopAddress );
  1361. *pbySrcMaskLength = (BYTE)rdi.DestAddress.NumBits;
  1362. *pdwNextHopIfIndex = nhi.InterfaceIndex;
  1363. *pdwNextHopProtocol= PROTO_FROM_PROTO_ID(
  1364. rei.EntityId.EntityProtocolId );
  1365. RtmReleaseNextHopInfo( g_hLocalRoute, &nhi );
  1366. }
  1367. RtmReleaseRouteInfo( g_hLocalRoute, pri );
  1368. }
  1369. if (g_mcastDebugLevel > 0)
  1370. {
  1371. Trace6(MCAST,
  1372. "%d.%d.%d.%d matched %d.%d.%d.%d/%x",
  1373. PRINT_IPADDR(ipAddress),
  1374. rdi.DestAddress.AddrBits[0],
  1375. rdi.DestAddress.AddrBits[1],
  1376. rdi.DestAddress.AddrBits[2],
  1377. rdi.DestAddress.AddrBits[3],
  1378. rdi.DestAddress.NumBits);
  1379. // XXX Get and show next hop
  1380. }
  1381. RtmReleaseDestInfo( g_hLocalRoute, &rdi);
  1382. }
  1383. HeapFree(IPRouterHeap, 0, pri);
  1384. return bRouteFound;
  1385. }
  1386. #else
  1387. {
  1388. // RTMV1 has no multicast RIB, and the unicast RIB may be wrong.
  1389. return FALSE;
  1390. }
  1391. #endif
  1392. VOID
  1393. HandleMtraceRequest(
  1394. WSABUF *pWsabuf
  1395. )
  1396. /*++
  1397. Locks:
  1398. Assumes caller holds read lock on ICB list
  1399. --*/
  1400. {
  1401. DWORD dwSizeOfHeader, dwBlocks, dwOutBufferSize, dwSize;
  1402. DWORD dwProtocolGroup, dwResult, dwErr;
  1403. IPV4_ADDRESS dwForwardDest = 0;
  1404. BYTE byStatusCode = MFE_NO_ERROR;
  1405. BYTE byProtoStatusCode = MFE_NO_ERROR;
  1406. BYTE byProtocol;
  1407. PICB picbIif, picbOif;
  1408. IPV4_ADDRESS dwIifAddr, dwOifAddr;
  1409. WSABUF wsMtraceBuffer;
  1410. BOOL bRouteFound;
  1411. MIB_IPMCAST_MFE mimInMfe;
  1412. PPROTO_CB pOifOwner, pIifOwner;
  1413. PMTRACE_HEADER pMtraceMsg;
  1414. PMTRACE_RESPONSE_BLOCK pBlock;
  1415. PMIB_IPMCAST_MFE_STATS mfeStats;
  1416. PIP_HEADER pIpHeader = (PIP_HEADER)pWsabuf->buf;
  1417. //
  1418. // Route fields independent of which version of RTM we're using
  1419. //
  1420. BYTE bySrcMaskLength = 0;
  1421. IPV4_ADDRESS ipNextHopAddress = 0;
  1422. DWORD dwNextHopIfIndex = 0;
  1423. DWORD dwNextHopProtocol= 0;
  1424. dwSizeOfHeader = ((pIpHeader->byVerLen)&0x0f)<<2;
  1425. pMtraceMsg = (PMTRACE_HEADER)(((PBYTE)pIpHeader) + dwSizeOfHeader);
  1426. dwBlocks = (ntohs(pIpHeader->wLength) - dwSizeOfHeader
  1427. - sizeof(MTRACE_HEADER)) / sizeof(MTRACE_RESPONSE_BLOCK);
  1428. //
  1429. // If Query (no response blocks) received via routeralert and we're
  1430. // not lasthop router, then silently drop it.
  1431. //
  1432. if (!dwBlocks)
  1433. {
  1434. BOOL isLastHop;
  1435. //
  1436. // Check whether we're the last-hop router by seeing if we
  1437. // have a multicast-capable interface on the same subnet as
  1438. // the destination address, and we are the router that would
  1439. // forward traffic from the given source onto the oif.
  1440. //
  1441. dwResult = FindBindingWithRemoteAddress(&picbOif,
  1442. &dwOifAddr,
  1443. pMtraceMsg->dwDestAddress);
  1444. isLastHop = (dwResult == NO_ERROR);
  1445. if (!isLastHop)
  1446. {
  1447. // If multicast, or if unicast but not to us, reinject
  1448. if (IN_MULTICAST(ntohl(pIpHeader->dwDest))
  1449. || !McIsMyAddress(pMtraceMsg->dwDestAddress))
  1450. {
  1451. Trace1(MCAST, "Mtrace: reinjecting packet to %d.%d.%d.%d",
  1452. PRINT_IPADDR(pIpHeader->dwDest));
  1453. McSendPacketTo( McMiscSocket,
  1454. pWsabuf,
  1455. pMtraceMsg->dwDestAddress);
  1456. return;
  1457. }
  1458. //
  1459. // Ok, this was received via unicast to us, and we want to
  1460. // trace starting from this router, but we don't
  1461. // know what oif would be used, so we need to put
  1462. // 0 in the message.
  1463. //
  1464. picbOif = NULL;
  1465. dwOifAddr = 0;
  1466. //
  1467. // note error code of 0x06
  1468. //
  1469. byStatusCode = MFE_NOT_LAST_HOP;
  1470. }
  1471. }
  1472. else
  1473. {
  1474. //
  1475. // If Request (response blocks exist) received via non-link-local
  1476. // multicast, drop it.
  1477. //
  1478. if (IN_MULTICAST(ntohl(pIpHeader->dwDest)) &&
  1479. ((pIpHeader->dwDest & LOCAL_NET_MULTICAST_MASK) != LOCAL_NET_MULTICAST))
  1480. {
  1481. return;
  1482. }
  1483. //
  1484. // Match interface on which request arrived
  1485. //
  1486. dwResult = FindBindingForPacket(pIpHeader,
  1487. &picbOif,
  1488. &dwOifAddr);
  1489. if(dwResult != NO_ERROR)
  1490. {
  1491. //
  1492. // Drop it if we couldn't find the interface.
  1493. // Since it was received via link-local multicast,
  1494. // this should never happen.
  1495. //
  1496. if (g_mcastDebugLevel > 0)
  1497. {
  1498. Trace0(MCAST, "Mtrace: no matching interface");
  1499. }
  1500. return;
  1501. }
  1502. }
  1503. //
  1504. // 1) Insert a new response block into the packet and fill in the
  1505. // Query Arrival Time, Outgoing Interface Address, Output
  1506. // Packet Count, and FwdTTL.
  1507. // if (XXX can insert)
  1508. //
  1509. {
  1510. dwSize = sizeof(MTRACE_HEADER) + dwBlocks*sizeof(MTRACE_RESPONSE_BLOCK);
  1511. wsMtraceBuffer.len = dwSize + sizeof(MTRACE_RESPONSE_BLOCK);
  1512. wsMtraceBuffer.buf = HeapAlloc(IPRouterHeap, 0, wsMtraceBuffer.len);
  1513. if (wsMtraceBuffer.buf == NULL)
  1514. {
  1515. Trace0( MCAST, "Couldn't allocate memory for mtrace response" );
  1516. return;
  1517. }
  1518. CopyMemory(wsMtraceBuffer.buf, pMtraceMsg, dwSize);
  1519. pBlock = (PMTRACE_RESPONSE_BLOCK)(((PBYTE)wsMtraceBuffer.buf) + dwSize);
  1520. dwBlocks++;
  1521. ZeroMemory(pBlock, sizeof(MTRACE_RESPONSE_BLOCK));
  1522. pBlock->dwQueryArrivalTime = GetCurrentNTP32Time();
  1523. pBlock->dwOifAddr = dwOifAddr;
  1524. if (picbOif) {
  1525. IP_MCAST_COUNTER_INFO oifStats;
  1526. GetInterfaceMcastCounters(picbOif, &oifStats);
  1527. pBlock->dwOifPacketCount = htonl((ULONG)oifStats.OutMcastPkts);
  1528. if (g_mcastDebugLevel > 0)
  1529. Trace1(MCAST, "dwOifPacketCount = %d", oifStats.OutMcastPkts);
  1530. pBlock->byOifThreshold = (BYTE)picbOif->dwMcastTtl;
  1531. } else {
  1532. pBlock->dwOifPacketCount = 0;
  1533. pBlock->byOifThreshold = 0;
  1534. }
  1535. }
  1536. // else {
  1537. // byStatusCode = MFE_NO_SPACE;
  1538. // }
  1539. //
  1540. // 2) Attempt to determine the forwarding information for the
  1541. // source and group specified, using the same mechanisms as
  1542. // would be used when a packet is received from the source
  1543. // destined for the group. (State need not be initiated.)
  1544. //
  1545. ZeroMemory( &mimInMfe, sizeof(mimInMfe) );
  1546. mimInMfe.dwGroup = pMtraceMsg->dwGroupAddress;
  1547. mimInMfe.dwSource = pMtraceMsg->dwSourceAddress;
  1548. mimInMfe.dwSrcMask = 0xFFFFFFFF;
  1549. dwOutBufferSize = 0;
  1550. dwResult = MgmGetMfeStats(
  1551. &mimInMfe, &dwOutBufferSize, (PBYTE)NULL,
  1552. MGM_MFE_STATS_0
  1553. );
  1554. if (dwResult isnot NO_ERROR)
  1555. {
  1556. mfeStats = NULL;
  1557. }
  1558. else
  1559. {
  1560. mfeStats = HeapAlloc(IPRouterHeap,
  1561. 0,
  1562. dwOutBufferSize);
  1563. dwResult = MgmGetMfeStats(
  1564. &mimInMfe,
  1565. &dwOutBufferSize,
  1566. (PBYTE)mfeStats,
  1567. MGM_MFE_STATS_0
  1568. );
  1569. if (dwResult isnot NO_ERROR)
  1570. {
  1571. HeapFree(IPRouterHeap,
  1572. 0,
  1573. mfeStats);
  1574. mfeStats = NULL;
  1575. }
  1576. }
  1577. if (mfeStats)
  1578. {
  1579. //
  1580. // MFE was found...
  1581. //
  1582. dwNextHopProtocol = mfeStats->dwRouteProtocol;
  1583. dwNextHopIfIndex = mfeStats->dwInIfIndex;
  1584. ipNextHopAddress = mfeStats->dwUpStrmNgbr;
  1585. bySrcMaskLength = MaskToMaskLen(mfeStats->dwRouteMask);
  1586. bRouteFound = TRUE;
  1587. }
  1588. else
  1589. {
  1590. bRouteFound = FALSE;
  1591. if (pMtraceMsg->dwSourceAddress == 0xFFFFFFFF)
  1592. {
  1593. //
  1594. // G route
  1595. //
  1596. bRouteFound = McLookupRoute( pMtraceMsg->dwGroupAddress,
  1597. FALSE,
  1598. & bySrcMaskLength,
  1599. & ipNextHopAddress,
  1600. & dwNextHopIfIndex,
  1601. & dwNextHopProtocol );
  1602. if (ipNextHopAddress is IP_LOOPBACK_ADDRESS)
  1603. {
  1604. // It's one of our addresses, so switch to the interface
  1605. // route instead of the loopback one.
  1606. bRouteFound = McLookupRoute( pMtraceMsg->dwGroupAddress,
  1607. TRUE,
  1608. & bySrcMaskLength,
  1609. & ipNextHopAddress,
  1610. & dwNextHopIfIndex,
  1611. & dwNextHopProtocol );
  1612. }
  1613. bySrcMaskLength = 0; // force source mask length to 0
  1614. }
  1615. else
  1616. {
  1617. //
  1618. // S route
  1619. //
  1620. bRouteFound = McLookupRoute( pMtraceMsg->dwSourceAddress,
  1621. FALSE,
  1622. & bySrcMaskLength,
  1623. & ipNextHopAddress,
  1624. & dwNextHopIfIndex,
  1625. & dwNextHopProtocol );
  1626. if (ipNextHopAddress is IP_LOOPBACK_ADDRESS)
  1627. {
  1628. // It's one of our addresses, so switch to the interface
  1629. // route instead of the loopback one.
  1630. bRouteFound = McLookupRoute( pMtraceMsg->dwSourceAddress,
  1631. TRUE,
  1632. & bySrcMaskLength,
  1633. & ipNextHopAddress,
  1634. & dwNextHopIfIndex,
  1635. & dwNextHopProtocol );
  1636. }
  1637. }
  1638. }
  1639. picbIif = (dwNextHopIfIndex)? InterfaceLookupByIfIndex(dwNextHopIfIndex) : 0;
  1640. dwIifAddr = (picbIif)? defaultSourceAddress(picbIif) : 0;
  1641. // If the source is directly-connected, make sure the next hop
  1642. // address is equal to the source. Later on below, we'll set the
  1643. // forward destination to the response address
  1644. if (picbIif
  1645. && (pMtraceMsg->dwSourceAddress isnot 0xFFFFFFFF)
  1646. && IsConnectedTo(picbIif, pMtraceMsg->dwSourceAddress, NULL, NULL))
  1647. {
  1648. ipNextHopAddress = pMtraceMsg->dwSourceAddress;
  1649. }
  1650. //
  1651. // New Rule: if received via link-local multicast, then silently
  1652. // drop requests if we know we're not the forwarder
  1653. //
  1654. if ((pIpHeader->dwDest & LOCAL_NET_MULTICAST_MASK) == LOCAL_NET_MULTICAST)
  1655. {
  1656. // If we don't have a route to another iface, we're not forwarder
  1657. if (!picbIif || picbIif==picbOif)
  1658. {
  1659. return;
  1660. }
  1661. }
  1662. //
  1663. // Special case: if we matched a host route pointing back to us,
  1664. // then we've actually reached the source.
  1665. //
  1666. if (dwIifAddr == IP_LOOPBACK_ADDRESS)
  1667. {
  1668. dwIifAddr = pMtraceMsg->dwSourceAddress;
  1669. }
  1670. //
  1671. // Initialize all fields
  1672. // spec doesn't say what value to use as "other"
  1673. //
  1674. byProtocol = 0;
  1675. dwProtocolGroup = ALL_ROUTERS_MULTICAST_GROUP;
  1676. //
  1677. // 3) If no forwarding information can be determined, set error
  1678. // to MFE_NO_ROUTE, zero remaining fields, and forward to
  1679. // requester.
  1680. //
  1681. if (!picbIif)
  1682. {
  1683. if (byStatusCode < MFE_NO_ROUTE)
  1684. {
  1685. byStatusCode = MFE_NO_ROUTE;
  1686. }
  1687. dwForwardDest = pMtraceMsg->dwResponseAddress;
  1688. pIifOwner = NULL;
  1689. }
  1690. else
  1691. {
  1692. //
  1693. // Calculate Mtrace protocol ID and next hop group address
  1694. // (Yes, the protocol ID field in the spec really is one big
  1695. // hairy mess)
  1696. //
  1697. dwResult = MulticastOwner(picbIif,
  1698. &pIifOwner,
  1699. NULL);
  1700. if(pIifOwner)
  1701. {
  1702. switch(PROTO_FROM_PROTO_ID(pIifOwner->dwProtocolId))
  1703. {
  1704. //
  1705. // Fill this in for every new protocol added.
  1706. //
  1707. // We'll be nice and fill in code for protocols which aren't
  1708. // implemented yet.
  1709. //
  1710. #if defined(PROTO_IP_DVMRP) && defined(ALL_DVMRP_ROUTERS_MULTICAST_GROUP)
  1711. case PROTO_IP_DVMRP:
  1712. {
  1713. if (rir.RR_RoutingProtocol is PROTO_IP_LOCAL)
  1714. {
  1715. //
  1716. // Static route
  1717. //
  1718. byProtocol = 7;
  1719. }
  1720. else
  1721. {
  1722. //
  1723. // Non-static route
  1724. //
  1725. byProtocol = 1;
  1726. }
  1727. dwProtocolGroup = ALL_DVMRP_ROUTERS_MULTICAST_GROUP;
  1728. break;
  1729. }
  1730. #endif
  1731. #if defined(PROTO_IP_MOSPF) && defined(ALL_MOSPF_ROUTERS_MULTICAST_GROUP)
  1732. case PROTO_IP_MOSPF:
  1733. {
  1734. byProtocol = 2;
  1735. dwProtocolGroup = ALL_MOSPF_ROUTERS_MULTICAST_GROUP;
  1736. break;
  1737. }
  1738. #endif
  1739. #if defined(PROTO_IP_PIM) && defined(ALL_PIM_ROUTERS_MULTICAST_GROUP)
  1740. case PROTO_IP_PIM:
  1741. {
  1742. if (rir.RR_RoutingProtocol is PROTO_IP_LOCAL)
  1743. {
  1744. //
  1745. // Static route
  1746. //
  1747. byProtocol = 6;
  1748. }
  1749. else
  1750. {
  1751. if (0)
  1752. {
  1753. //
  1754. // XXX Non-static, M-RIB route!=U-RIB route
  1755. //
  1756. byProtocol = 5;
  1757. }
  1758. else
  1759. {
  1760. //
  1761. // Non-static, PIM over M-RIB==U-RIB
  1762. //
  1763. byProtocol = 3;
  1764. }
  1765. }
  1766. dwProtocolGroup = ALL_PIM_ROUTERS_MULTICAST_GROUP;
  1767. break;
  1768. }
  1769. #endif
  1770. #if defined(PROTO_IP_CBT) && defined(ALL_CBT_ROUTERS_MULTICAST_GROUP)
  1771. case PROTO_IP_CBT:
  1772. {
  1773. byProtocol = 4;
  1774. dwProtocolGroup = ALL_CBT_ROUTERS_MULTICAST_GROUP;
  1775. break;
  1776. }
  1777. #endif
  1778. }
  1779. }
  1780. //
  1781. // 4) Fill in more information
  1782. //
  1783. //
  1784. // Incoming Interface Address
  1785. //
  1786. pBlock->dwIifAddr = dwIifAddr;
  1787. if (mfeStats)
  1788. {
  1789. //
  1790. // Figure out Previous-Hop Router Address
  1791. //
  1792. dwForwardDest = mfeStats->dwUpStrmNgbr;
  1793. }
  1794. else
  1795. {
  1796. if ( IsPointToPoint(picbIif) && picbIif->dwRemoteAddress )
  1797. {
  1798. dwForwardDest = picbIif->dwRemoteAddress;
  1799. }
  1800. else if (bRouteFound && ipNextHopAddress)
  1801. {
  1802. dwForwardDest = ipNextHopAddress;
  1803. }
  1804. else
  1805. {
  1806. dwForwardDest = 0;
  1807. }
  1808. }
  1809. pBlock->dwPrevHopAddr = dwForwardDest;
  1810. // Okay, if the previous hop address is the source,
  1811. // set the forward destination to the response address
  1812. if (dwForwardDest is pMtraceMsg->dwSourceAddress)
  1813. {
  1814. ipNextHopAddress = 0;
  1815. dwForwardDest = pMtraceMsg->dwResponseAddress;
  1816. }
  1817. if (picbIif)
  1818. {
  1819. IP_MCAST_COUNTER_INFO iifStats;
  1820. GetInterfaceMcastCounters(picbIif, &iifStats);
  1821. pBlock->dwIifPacketCount = htonl((ULONG)iifStats.InMcastPkts);
  1822. }
  1823. else
  1824. {
  1825. pBlock->dwIifPacketCount = 0;
  1826. }
  1827. //
  1828. // Total Number of Packets
  1829. //
  1830. pBlock->dwSGPacketCount = (mfeStats)? htonl(mfeStats->ulInPkts) : 0;
  1831. pBlock->byIifProtocol = byProtocol; // Routing Protocol
  1832. //
  1833. // length of source mask for S route
  1834. //
  1835. if (bRouteFound)
  1836. {
  1837. pBlock->bySrcMaskLength = bySrcMaskLength;
  1838. }
  1839. else
  1840. {
  1841. pBlock->bySrcMaskLength = 0;
  1842. }
  1843. #if 0
  1844. if (XXX starG or better forwarding state)
  1845. {
  1846. pBlock->bySrcMaskLength = 63; // Smask from forwarding info
  1847. }
  1848. //
  1849. // Set S bit (64) if packet counts aren't (S,G)-specific
  1850. //
  1851. if (XXX)
  1852. {
  1853. pBlock->bySrcMaskLength |= 64;
  1854. }
  1855. #endif
  1856. }
  1857. //
  1858. // 5) Check if traceroute is administratively prohibited, or if
  1859. // previous hop router doesn't understand traceroute. If so,
  1860. // forward to requester.
  1861. //
  1862. #if 0
  1863. if (XXX) {
  1864. if (byStatusCode < MFE_PROHIBITED)
  1865. {
  1866. byStatusCode = MFE_PROHIBITED;
  1867. }
  1868. dwForwardDest = pMtraceMsg->dwResponseAddress;
  1869. }
  1870. #endif
  1871. //
  1872. // Check for MFE_OLD_ROUTER - set by routing protocol
  1873. //
  1874. // 6) If reception iface is non-multicast or iif, set appropriate error.
  1875. //
  1876. if (picbOif)
  1877. {
  1878. dwResult = MulticastOwner(picbOif,
  1879. &pOifOwner,
  1880. NULL);
  1881. if (pOifOwner == NULL)
  1882. {
  1883. if (byStatusCode < MFE_NO_MULTICAST)
  1884. {
  1885. byStatusCode = MFE_NO_MULTICAST;
  1886. }
  1887. }
  1888. else
  1889. {
  1890. if (picbOif == picbIif)
  1891. {
  1892. if (byStatusCode < MFE_IIF)
  1893. {
  1894. byStatusCode = MFE_IIF;
  1895. }
  1896. }
  1897. }
  1898. }
  1899. else
  1900. {
  1901. pOifOwner = NULL;
  1902. }
  1903. //
  1904. // Check for MFE_WRONG_IF - set by routing protocol
  1905. //
  1906. // 7) Check for admin scoping on either iif or oif.
  1907. //
  1908. if ((picbIif
  1909. && RmHasBoundary(picbIif->dwIfIndex, pMtraceMsg->dwGroupAddress))
  1910. || (picbOif
  1911. && RmHasBoundary(picbOif->dwIfIndex, pMtraceMsg->dwGroupAddress)))
  1912. {
  1913. if (byStatusCode < MFE_BOUNDARY_REACHED)
  1914. {
  1915. byStatusCode = MFE_BOUNDARY_REACHED;
  1916. }
  1917. }
  1918. //
  1919. // 8) Check for MFE_REACHED_CORE - set by routing protocol
  1920. // 9) Check for MFE_PRUNED_UPSTREAM - set by routing protocol
  1921. // Check for MFE_OIF_PRUNED - set by routing protocol
  1922. // Check for MFE_NOT_FORWARDING:
  1923. // Search for picbOif->(index) and picbOifAddr in oiflist
  1924. //
  1925. if (mfeStats && picbOif)
  1926. {
  1927. DWORD oifIndex;
  1928. for (oifIndex=0;
  1929. oifIndex < mfeStats->ulNumOutIf;
  1930. oifIndex++)
  1931. {
  1932. if (picbOif->dwIfIndex==mfeStats->rgmiosOutStats[oifIndex].dwOutIfIndex
  1933. && dwOifAddr == mfeStats->rgmiosOutStats[oifIndex].dwNextHopAddr)
  1934. {
  1935. break;
  1936. }
  1937. }
  1938. if (oifIndex >= mfeStats->ulNumOutIf)
  1939. {
  1940. if (byStatusCode < MFE_NOT_FORWARDING)
  1941. {
  1942. byStatusCode = MFE_NOT_FORWARDING;
  1943. }
  1944. }
  1945. }
  1946. //
  1947. // status code to add is highest value of what iif owner, oif owner,
  1948. // and rtrmgr say.
  1949. //
  1950. if (pOifOwner && pOifOwner->pfnGetMfeStatus)
  1951. {
  1952. dwResult = (pOifOwner->pfnGetMfeStatus)(picbOif->dwIfIndex,
  1953. pMtraceMsg->dwGroupAddress,
  1954. pMtraceMsg->dwSourceAddress,
  1955. &byProtoStatusCode);
  1956. if (byStatusCode < byProtoStatusCode)
  1957. {
  1958. byStatusCode = byProtoStatusCode;
  1959. }
  1960. }
  1961. if (pIifOwner && pIifOwner->pfnGetMfeStatus)
  1962. {
  1963. dwResult = (pIifOwner->pfnGetMfeStatus)(picbIif->dwIfIndex,
  1964. pMtraceMsg->dwGroupAddress,
  1965. pMtraceMsg->dwSourceAddress,
  1966. &byProtoStatusCode);
  1967. if (byStatusCode < byProtoStatusCode)
  1968. {
  1969. byStatusCode = byProtoStatusCode;
  1970. }
  1971. }
  1972. pBlock->byStatusCode = (char)mtraceErrCode[byStatusCode];
  1973. Trace5( MCAST,
  1974. "Mtrace: err %d blks %d maxhops %d iif %d prevhop %d.%d.%d.%d",
  1975. pBlock->byStatusCode,
  1976. dwBlocks,
  1977. pMtraceMsg->byHops,
  1978. ((picbIif)? picbIif->dwIfIndex : 0),
  1979. PRINT_IPADDR(pBlock->dwPrevHopAddr));
  1980. //
  1981. // 10) Send packet on to previous hop or to requester.
  1982. // If prev hop is not known, but iif is known, use a multicast group.
  1983. //
  1984. if (dwBlocks == pMtraceMsg->byHops)
  1985. {
  1986. dwForwardDest = pMtraceMsg->dwResponseAddress;
  1987. }
  1988. else
  1989. {
  1990. if (!dwForwardDest)
  1991. {
  1992. if (picbIif)
  1993. {
  1994. pBlock->dwPrevHopAddr = dwForwardDest = dwProtocolGroup;
  1995. }
  1996. else
  1997. {
  1998. dwForwardDest = pMtraceMsg->dwResponseAddress;
  1999. }
  2000. }
  2001. }
  2002. if (g_mcastDebugLevel > 0) {
  2003. Trace1(MCAST, " QueryArrivalTime = %08x", pBlock->dwQueryArrivalTime);
  2004. Trace2(MCAST, " IifAddr = %08x (%d.%d.%d.%d)", pBlock->dwIifAddr,
  2005. PRINT_IPADDR(pBlock->dwIifAddr));
  2006. Trace2(MCAST, " OifAddr = %08x (%d.%d.%d.%d)", pBlock->dwOifAddr,
  2007. PRINT_IPADDR(pBlock->dwOifAddr));
  2008. Trace2(MCAST, " PrevHopAddr = %08x (%d.%d.%d.%d)", pBlock->dwPrevHopAddr,
  2009. PRINT_IPADDR(pBlock->dwPrevHopAddr));
  2010. Trace1(MCAST, " IifPacketCount = %08x", pBlock->dwIifPacketCount );
  2011. Trace1(MCAST, " OifPacketCount = %08x", pBlock->dwOifPacketCount );
  2012. Trace1(MCAST, " SGPacketCount = %08x", pBlock->dwSGPacketCount );
  2013. Trace1(MCAST, " IifProtocol = %02x", pBlock->byIifProtocol );
  2014. Trace1(MCAST, " OifThreshold = %02x", pBlock->byOifThreshold );
  2015. Trace1(MCAST, " SrcMaskLength = %02x", pBlock->bySrcMaskLength );
  2016. Trace1(MCAST, " StatusCode = %02x", pBlock->byStatusCode );
  2017. }
  2018. if (dwForwardDest is pMtraceMsg->dwResponseAddress)
  2019. {
  2020. Trace2(MCAST,
  2021. "Sending mtrace response to %d.%d.%d.%d from %d.%d.%d.%d",
  2022. PRINT_IPADDR(dwForwardDest),
  2023. PRINT_IPADDR(dwOifAddr));
  2024. SendMtraceResponse(dwForwardDest,
  2025. dwOifAddr,
  2026. (PMTRACE_HEADER)wsMtraceBuffer.buf,
  2027. dwSize + sizeof(MTRACE_RESPONSE_BLOCK));
  2028. }
  2029. else
  2030. {
  2031. Trace2(MCAST,
  2032. "Forwarding mtrace request to %d.%d.%d.%d from %d.%d.%d.%d",
  2033. PRINT_IPADDR(dwForwardDest),
  2034. PRINT_IPADDR(dwIifAddr));
  2035. ForwardMtraceRequest(dwForwardDest,
  2036. dwIifAddr,
  2037. (PMTRACE_HEADER)wsMtraceBuffer.buf,
  2038. dwSize + sizeof(MTRACE_RESPONSE_BLOCK));
  2039. }
  2040. //
  2041. // Free the buffers
  2042. //
  2043. if (mfeStats)
  2044. {
  2045. HeapFree(IPRouterHeap,
  2046. 0,
  2047. mfeStats);
  2048. }
  2049. HeapFree(IPRouterHeap,
  2050. 0,
  2051. wsMtraceBuffer.buf);
  2052. }
  2053. ///////////////////////////////////////////////////////////////////////////////
  2054. // Functions to deal with RAS Server advertisements
  2055. ///////////////////////////////////////////////////////////////////////////////
  2056. static BOOL g_bRasAdvEnabled = FALSE;
  2057. DWORD
  2058. SetRasAdvEnable(
  2059. BOOL bEnabled
  2060. )
  2061. {
  2062. LARGE_INTEGER liExpiryTime;
  2063. DWORD dwErr = NO_ERROR;
  2064. if (bEnabled == g_bRasAdvEnabled)
  2065. return dwErr;
  2066. g_bRasAdvEnabled = bEnabled;
  2067. if (bEnabled)
  2068. {
  2069. //
  2070. // create input socket
  2071. //
  2072. g_UDPMiscSocket = WSASocket(AF_INET,
  2073. SOCK_DGRAM,
  2074. 0,
  2075. NULL,
  2076. 0,
  2077. 0);
  2078. // Start timer
  2079. liExpiryTime = RtlConvertUlongToLargeInteger(RASADV_STARTUP_DELAY);
  2080. if (!SetWaitableTimer( g_hRasAdvTimer,
  2081. &liExpiryTime,
  2082. RASADV_PERIOD,
  2083. NULL,
  2084. NULL,
  2085. FALSE))
  2086. {
  2087. dwErr = GetLastError();
  2088. Trace1(ERR,
  2089. "SetRasAdvEnable: Error %d setting waitable timer",
  2090. dwErr);
  2091. }
  2092. }
  2093. else
  2094. {
  2095. // Stop timer
  2096. dwErr = CancelWaitableTimer( g_hRasAdvTimer );
  2097. }
  2098. return dwErr;
  2099. }
  2100. VOID
  2101. HandleRasAdvTimer()
  2102. {
  2103. BYTE bHostName[MAX_HOSTNAME_LEN];
  2104. BYTE bMessage[MAX_HOSTNAME_LEN + 80], *p;
  2105. SOCKADDR_IN sinAddr, srcAddr;
  2106. PICB picb = NULL;
  2107. PLIST_ENTRY pleNode;
  2108. DWORD dwErr;
  2109. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pGlobalDomainInfo = NULL;
  2110. if (!g_bRasAdvEnabled)
  2111. return;
  2112. // Compose message
  2113. gethostname(bHostName, sizeof(bHostName));
  2114. sprintf(bMessage, "Hostname=%s\n", bHostName);
  2115. p = bMessage + strlen(bMessage);
  2116. // Get the name of the domain this machine is a member of
  2117. dwErr = DsRoleGetPrimaryDomainInformation(
  2118. NULL,
  2119. DsRolePrimaryDomainInfoBasic,
  2120. (LPBYTE *) &pGlobalDomainInfo );
  2121. if ((dwErr is NO_ERROR) and
  2122. (pGlobalDomainInfo->DomainNameDns isnot NULL))
  2123. {
  2124. char *pType;
  2125. char buff[257];
  2126. WideCharToMultiByte( CP_ACP,
  2127. 0,
  2128. pGlobalDomainInfo->DomainNameDns,
  2129. wcslen(pGlobalDomainInfo->DomainNameDns)+1,
  2130. buff,
  2131. sizeof(buff),
  2132. NULL,
  2133. NULL );
  2134. if (pGlobalDomainInfo->MachineRole is DsRole_RoleStandaloneWorkstation
  2135. or pGlobalDomainInfo->MachineRole is DsRole_RoleStandaloneServer)
  2136. pType = "Workgroup";
  2137. else
  2138. pType = "Domain";
  2139. sprintf(p, "%s=%s\n", pType, buff);
  2140. // Trace1(MCAST, "Sending !%s!", bMessage);
  2141. }
  2142. sinAddr.sin_family = AF_INET;
  2143. sinAddr.sin_port = htons(RASADV_PORT);
  2144. sinAddr.sin_addr.s_addr = inet_addr(RASADV_GROUP);
  2145. dwErr = McSetMulticastTtl( g_UDPMiscSocket, RASADV_TTL );
  2146. // Find a dedicated interface (if any)
  2147. ENTER_READER(ICB_LIST);
  2148. {
  2149. for (pleNode = ICBList.Flink;
  2150. pleNode isnot &ICBList;
  2151. pleNode = pleNode->Flink)
  2152. {
  2153. DWORD dwIndex;
  2154. picb = CONTAINING_RECORD(pleNode,
  2155. ICB,
  2156. leIfLink);
  2157. if (! picb->bBound)
  2158. continue;
  2159. if (picb->ritType == ROUTER_IF_TYPE_DEDICATED)
  2160. {
  2161. dwErr = McSetMulticastIfByIndex( g_UDPMiscSocket,
  2162. SOCK_DGRAM,
  2163. picb->dwIfIndex );
  2164. // Send a Ras Adv message
  2165. sendto(g_UDPMiscSocket, bMessage, strlen(bMessage)+1, 0,
  2166. (struct sockaddr *)&sinAddr, sizeof(sinAddr));
  2167. // If multicast forwarding is enabled, then
  2168. // a single send will get forwarded out all
  2169. // interfaces, so we can stop after the first send
  2170. if (McMiscSocket != INVALID_SOCKET)
  2171. break;
  2172. }
  2173. }
  2174. }
  2175. EXIT_LOCK(ICB_LIST);
  2176. }