Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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