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.

1254 lines
39 KiB

  1. #define UNICODE
  2. #include <nt.h>
  3. #include <ntrtl.h>
  4. #include <nturtl.h>
  5. #define NOGDI
  6. #define NOMINMAX
  7. #include <windows.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <io.h>
  12. #include <winsock2.h>
  13. #include <ws2tcpip.h>
  14. #include <nls.h>
  15. #include <ntddip6.h>
  16. #include "pathqos.h"
  17. #include "ipexport.h"
  18. #include "icmpapi.h"
  19. #include "nlstxt.h"
  20. #include "pathping.h"
  21. #include <qos.h>
  22. #include <ntddndis.h>
  23. #include <traffic.h>
  24. #define ICMP_MSG 1
  25. #define RSVP_MSG 2
  26. u_char Router_alert[4] = {148, 4, 0, 0};
  27. uchar RsvpPathTearMsg[] =
  28. {
  29. 0x10, 0x05, 0xB6, 0x38, 0x80, 0x00, 0x00, 0x50, 0x00, 0x0C,
  30. 0x01, 0x01, 0x0F, 0x19, 0x05, 0x71, 0x11, 0x01, 0x15, 0xB3, 0x00, 0x0C, 0x03, 0x01, 0x0F, 0x19,
  31. 0x08, 0x7F, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0C, 0x0B, 0x01, 0x0F, 0x19, 0x08, 0x7F, 0x00, 0x00,
  32. 0x15, 0xB3, 0x00, 0x24, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x06, 0x7F, 0x00,
  33. 0x00, 0x05, 0x42, 0x82, 0x63, 0xAB, 0x44, 0xBF, 0x00, 0x00, 0x43, 0x02, 0x63, 0xAB, 0x00, 0x00,
  34. 0x05, 0xF8, 0x00, 0x00, 0x06, 0x5C
  35. };
  36. uchar RsvpPathMsg[] =
  37. {
  38. 0x10, 0x01, 0x14, 0x04, 0x80, 0x00, 0x00, 0x88, 0x00, 0x0C, 0x01, 0x01, 0x0F, 0x19, 0x08, 0x01,
  39. 0x11, 0x01, 0x15, 0xB3, 0x00, 0x0C, 0x03, 0x01, 0x0F, 0x19, 0x08, 0x7F, 0x00, 0x01, 0x00, 0x01,
  40. 0x00, 0x08, 0x05, 0x01, 0x00, 0x00, 0x75, 0x30, 0x00, 0x0C, 0x0B, 0x01, 0x0F, 0x19, 0x08, 0x7F,
  41. 0x00, 0x00, 0x15, 0xB3, 0x00, 0x24, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x06,
  42. 0x7F, 0x00, 0x00, 0x05, 0x42, 0x82, 0x63, 0xAB, 0x44, 0xBF, 0x00, 0x00, 0x43, 0x02, 0x63, 0xAB,
  43. 0x00, 0x00, 0x05, 0xF8, 0x00, 0x00, 0x06, 0x5C, 0x00, 0x30, 0x0D, 0x02, 0x00, 0x00, 0x00, 0x0A,
  44. 0x01, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01,
  45. 0x48, 0x74, 0x24, 0x00, 0x08, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x00, 0x00, 0x01,
  46. 0x00, 0x00, 0x05, 0xDC, 0x05, 0x00, 0x00, 0x00
  47. };
  48. uchar RsvpResvMsg[] =
  49. {
  50. // common_header
  51. 0x10, 0x02, 0x4D, 0xF8, 0xFF, 0x00, 0x00, 0x60,
  52. // session
  53. 0x00, 0x0C, 0x01, 0x01, 0xAC, 0x1F, 0x7A, 0x15, 0x11, 0x00, 0x15, 0xB3,
  54. // rsvp_hop
  55. 0x00, 0x0C, 0x03, 0x01, 0xC0, 0xA8, 0x1F, 0xE5, 0x00, 0x00, 0x00, 0x00,
  56. //
  57. 0x00, 0x08, 0x05, 0x01, 0x00, 0x00, 0x75, 0x30,
  58. // Style object
  59. 0x00, 0x08, 0x08, 0x01, 0x00, 0x00, 0x00, 0x0A,
  60. // flowspec
  61. 0x00, 0x24, 0x09, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, 0x00, 0x06,
  62. 0x7F, 0x00, 0x00, 0x05, 0x42, 0x82, 0x00, 0x00, 0x44, 0xBF, 0x00, 0x00,
  63. 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
  64. // filterspec
  65. 0x00, 0x0C, 0x0A, 0x01, 0xAC, 0x1F, 0x47, 0x90, 0x00, 0x00, 0x15, 0xB3
  66. };
  67. //
  68. // Utility functions
  69. //
  70. /*
  71. * The response is an IP packet. We must decode the IP header to locate
  72. * the ICMP data
  73. */
  74. void decode_msg(char *buf,
  75. int bytes,
  76. struct sockaddr_in *from,
  77. int code,
  78. Object_header *orisession)
  79. {
  80. IpHeader *orihdr, *iphdr;
  81. IcmpHeader *icmphdr;
  82. unsigned short iphdrlen;
  83. iphdr = (IpHeader *)buf;
  84. iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
  85. if(code == RSVP_MSG)
  86. {
  87. common_header *rsvphdr = (common_header *)(buf + iphdrlen);
  88. if(rsvphdr->rsvp_type == RSVP_RESV_ERR)
  89. {
  90. char *newbuf = (PCHAR) rsvphdr + sizeof(common_header);
  91. ULONG r = ntohs(rsvphdr->rsvp_length) - sizeof(common_header);
  92. Object_header *Sessobj = 0;
  93. while(r) {
  94. Object_header *obj = (Object_header *)(newbuf);
  95. switch(obj->obj_class)
  96. {
  97. case class_SESSION:
  98. Sessobj = obj;
  99. break;
  100. case class_ERROR_SPEC:
  101. {
  102. ERROR_SPEC *err = (ERROR_SPEC *)obj;
  103. //
  104. // Now make sure that the session object is the same as what we are sending.
  105. //
  106. while(r && !Sessobj)
  107. {
  108. newbuf = (PCHAR)newbuf + ntohs(obj->obj_length);
  109. r-=ntohs(obj->obj_length);
  110. obj = (Object_header *)(newbuf);
  111. if(obj->obj_class == class_SESSION)
  112. {
  113. Sessobj = obj;
  114. break;
  115. }
  116. }
  117. if(!Sessobj)
  118. {
  119. NlsPutMsg(STDOUT, PATHPING_BOGUSRESVERR_MSG);
  120. }
  121. else {
  122. // Make sure that the session obj is the same as what we passed in
  123. if(memcmp(orisession, Sessobj, ntohs(orisession->obj_length)) == 0)
  124. NlsPutMsg(STDOUT, PATHPING_RSVPAWARE_MSG);
  125. else NlsPutMsg(STDOUT, PATHPING_BOGUSRESVERR_MSG);
  126. }
  127. return;
  128. }
  129. }
  130. newbuf = (PCHAR)newbuf + ntohs(obj->obj_length);
  131. r -= ntohs(obj->obj_length);
  132. }
  133. NlsPutMsg(STDOUT, PATHPING_RSVPAWARE_MSG);
  134. }
  135. return;
  136. }
  137. else
  138. {
  139. if (bytes < iphdrlen + ICMP_MIN)
  140. {
  141. NlsPutMsg(STDOUT, PATHPING_ALIGN_IP_ADDRESS, inet_ntoa(from->sin_addr));
  142. NlsPutMsg(STDOUT, PATHPING_BUF_TOO_SMALL);
  143. }
  144. icmphdr = (IcmpHeader*)(buf + iphdrlen);
  145. switch(icmphdr->i_type)
  146. {
  147. default:
  148. printf("Unknown type %d \n", icmphdr->i_type);
  149. break;
  150. case 11:
  151. if(icmphdr->i_code == 0)
  152. {
  153. //
  154. // we have got TTL expired message.
  155. //
  156. orihdr = (IpHeader *)((PCHAR)icmphdr +sizeof(IcmpHeader));
  157. if(orihdr->proto == 46)
  158. {
  159. NlsPutMsg(STDOUT, PATHPING_QOS_SUCCESS);
  160. return;
  161. }
  162. }
  163. NlsPutMsg(STDOUT, PATHPING_ICMPTYPE11_MSG, icmphdr->i_code);
  164. break;
  165. case 3:
  166. if(icmphdr->i_code == 2)
  167. {
  168. //
  169. // This router has sent protocol unreachable. Make sure that it is protocol 46
  170. // before we print anything.
  171. //
  172. orihdr = (IpHeader *)((PCHAR)icmphdr + sizeof(IcmpHeader));
  173. if(orihdr->proto == 46)
  174. {
  175. NlsPutMsg(STDOUT, PATHPING_NONRSVPAWARE_MSG);
  176. return;
  177. }
  178. }
  179. NlsPutMsg(STDOUT, PATHPING_ICMPTYPE3_MSG, icmphdr->i_code);
  180. break;
  181. }
  182. }
  183. }
  184. /*
  185. * Compute TCP/UDP/IP checksum.
  186. * See p. 7 of RFC-1071.
  187. * This RFC indicates that the chksum calculation works equally well for both little
  188. * endian machines and big endian machines, hence there are no ifdefs here to
  189. * reflect the endian-ness of the machine.
  190. */
  191. u_int16_t
  192. in_cksum(unsigned char *bp, int n)
  193. {
  194. unsigned short *sp= (u_int16_t *) bp;
  195. unsigned long sum = 0;
  196. /* Sum half-words */
  197. while (n>1) {
  198. sum += *sp++;
  199. n -=2;
  200. }
  201. /* Add left-over byte, if any */
  202. if (n>0)
  203. sum += *(char *) sp;
  204. /* Fold 32-bit sum to 16 bits */
  205. sum = (sum & 0xFFFF) + (sum >> 16);
  206. sum = ~(sum + (sum >> 16)) & 0xFFFF;
  207. if (sum == 0xffff)
  208. sum = 0;
  209. return ((u_int16_t)sum);
  210. }
  211. void QoSNotifyHandler( HANDLE ClRegCtx, HANDLE ClIfcCtx, ULONG Event, HANDLE SubCode, ULONG BufSize, PVOID Buffer )
  212. {
  213. }
  214. //
  215. // Given destination address, this function returns the source address of the interface.
  216. //
  217. ULONG
  218. QoSGetSourceAddress(ULONG Destination)
  219. {
  220. SOCKET s;
  221. int err;
  222. DWORD dwBufferSize;
  223. SOCKADDR_IN remoteaddr, localaddr;
  224. ULONG Source = 0;
  225. s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
  226. if (INVALID_SOCKET != s)
  227. {
  228. memset(&remoteaddr, 0, sizeof(remoteaddr));
  229. remoteaddr.sin_family = AF_INET;
  230. remoteaddr.sin_port = 0;
  231. remoteaddr.sin_addr.S_un.S_addr = Destination;
  232. err = WSAIoctl(s,
  233. SIO_ROUTING_INTERFACE_QUERY,
  234. &remoteaddr,
  235. sizeof(remoteaddr),
  236. &localaddr,
  237. sizeof(localaddr),
  238. &dwBufferSize,
  239. NULL,
  240. NULL );
  241. if (0 == err)
  242. Source = localaddr.sin_addr.S_un.S_addr;
  243. closesocket(s);
  244. }
  245. return Source;
  246. }
  247. //
  248. // This function tests if 802.1p is misconfigured in the network. Enabling 802.1p causes packets
  249. // to go out with a 4 byte 802.1p tag. If a switch is present between a 802.1p aware network and
  250. // a legacy network (no 802.1p devices), then it should strip the tag before forwarding packets
  251. // on the legacy network. Otherwise, the legacy devices will toss the tagged ethernet packet assuming
  252. // that it is malformed (because of the 4 byte tag).
  253. //
  254. //
  255. // This function creates a besteffort flow with a TCLASS and DCLASS and adds a filter for ping packets
  256. // It then sends pings to the destinations. This causes the ping packets to go out with a 802.1p tag.
  257. // If 802.1p is misconfigured, the router that sees the tagged packet will fail the ping.
  258. //
  259. #define PATHPING_QOS_TRAFFIC_CLASS 7
  260. #define PATHPING_QOS_DS_CLASS 0x28
  261. void
  262. QoSCheck8021P(
  263. ULONG DstAddr,
  264. ULONG ulHopCount
  265. )
  266. {
  267. PICMP_ECHO_REPLY reply;
  268. ULONG i, numberOfReplies, SrcAddr, h, q;
  269. int lost, rcvd, linklost, nodelost, sent, len;
  270. TCI_CLIENT_FUNC_LIST ClientHandlerList;
  271. ULONG Size = 100 * sizeof(TC_IFC_DESCRIPTOR);
  272. PTC_IFC_DESCRIPTOR pTcIfcBuffer = 0;
  273. ULONG Status;
  274. HANDLE hClientHandle = 0, hInterfaceHandle = 0, hFlowHandle = 0, hFilterHandle = 0;
  275. PTC_GEN_FLOW pTcFlowSpec = 0;
  276. LPQOS_TRAFFIC_CLASS pTclass;
  277. LPQOS_DS_CLASS pDclass;
  278. char SendBuffer[DEFAULT_SEND_SIZE];
  279. char RcvBuffer[DEFAULT_RECEIVE_SIZE];
  280. NlsPutMsg(STDOUT, PATHPING_LAYER2_CONNECT_MSG);
  281. memset( &ClientHandlerList, 0, sizeof(ClientHandlerList) );
  282. ClientHandlerList.ClNotifyHandler = QoSNotifyHandler;
  283. SrcAddr = QoSGetSourceAddress(DstAddr);
  284. //
  285. // Register the TC client.
  286. //
  287. Status = TcRegisterClient(CURRENT_TCI_VERSION,
  288. NULL,
  289. &ClientHandlerList,
  290. &hClientHandle);
  291. if(Status != ERROR_SUCCESS)
  292. {
  293. NlsPutMsg(STDOUT, PATHPING_TCREGISTERCLIENT_FAILED, Status);
  294. return ;
  295. }
  296. //
  297. // Enumerate TC interfaces.
  298. //
  299. pTcIfcBuffer = (PTC_IFC_DESCRIPTOR) LocalAlloc(LMEM_FIXED, Size);
  300. Status = TcEnumerateInterfaces(
  301. hClientHandle,
  302. &Size,
  303. pTcIfcBuffer);
  304. if(ERROR_INSUFFICIENT_BUFFER == Status)
  305. {
  306. LocalFree(pTcIfcBuffer);
  307. pTcIfcBuffer = (PTC_IFC_DESCRIPTOR) LocalAlloc(LMEM_FIXED, Size);
  308. Status = TcEnumerateInterfaces(hClientHandle,
  309. &Size,
  310. pTcIfcBuffer);
  311. if(Status != ERROR_SUCCESS)
  312. {
  313. NlsPutMsg(STDOUT, PATHPING_TCENUMERATEINTERFACES_FAILED, Status);
  314. goto QoSCleanup;
  315. }
  316. }
  317. else
  318. {
  319. if(Status != ERROR_SUCCESS)
  320. {
  321. NlsPutMsg(STDOUT, PATHPING_TCENUMERATEINTERFACES_FAILED, Status);
  322. goto QoSCleanup;
  323. }
  324. }
  325. if(Size)
  326. {
  327. //
  328. // Based on the IP address, get the TC Interface.
  329. //
  330. PTC_IFC_DESCRIPTOR pCurrentIfc;
  331. ULONG cIfcRemaining;
  332. for ( pCurrentIfc = pTcIfcBuffer, cIfcRemaining = Size;
  333. cIfcRemaining > 0;
  334. cIfcRemaining -= pCurrentIfc->Length, pCurrentIfc = ((PTC_IFC_DESCRIPTOR)((PBYTE)pCurrentIfc +
  335. pCurrentIfc->Length))
  336. )
  337. {
  338. PNETWORK_ADDRESS_LIST pAddressList = &pCurrentIfc->AddressListDesc.AddressList;
  339. PNETWORK_ADDRESS pCurrentAddress;
  340. LONG iCurrentAddress;
  341. for ( iCurrentAddress = 0, pCurrentAddress = pAddressList->Address;
  342. iCurrentAddress < pAddressList->AddressCount;
  343. iCurrentAddress++, pCurrentAddress = ((PNETWORK_ADDRESS)((PBYTE) pCurrentAddress +
  344. FIELD_OFFSET(NETWORK_ADDRESS, Address)+
  345. pCurrentAddress->AddressLength))
  346. )
  347. {
  348. //
  349. // Make sure we've got the correct route
  350. //
  351. if ( pCurrentAddress!=0 &&
  352. pCurrentAddress->AddressType == NDIS_PROTOCOL_ID_TCP_IP &&
  353. ((PNETWORK_ADDRESS_IP)pCurrentAddress->Address)->in_addr == SrcAddr
  354. )
  355. {
  356. Status = TcOpenInterface(pCurrentIfc->pInterfaceName,
  357. hClientHandle,
  358. NULL,
  359. &hInterfaceHandle);
  360. if(Status != ERROR_SUCCESS)
  361. {
  362. NlsPutMsg(STDOUT, PATHPING_TCOPENINTERFACE_FAILED, Status, pCurrentIfc->pInterfaceName);
  363. goto QoSCleanup;
  364. }
  365. else
  366. {
  367. pTcFlowSpec = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(TC_GEN_FLOW, TcObjects) + sizeof(QOS_TRAFFIC_CLASS)
  368. + sizeof(QOS_DS_CLASS));
  369. if(pTcFlowSpec)
  370. {
  371. pTcFlowSpec->SendingFlowspec.TokenRate = QOS_NOT_SPECIFIED;
  372. pTcFlowSpec->SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
  373. pTcFlowSpec->SendingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
  374. pTcFlowSpec->SendingFlowspec.Latency = QOS_NOT_SPECIFIED;
  375. pTcFlowSpec->SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
  376. pTcFlowSpec->SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
  377. pTcFlowSpec->SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
  378. pTcFlowSpec->SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT;
  379. pTcFlowSpec->ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED;
  380. pTcFlowSpec->ReceivingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
  381. pTcFlowSpec->ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
  382. pTcFlowSpec->ReceivingFlowspec.Latency = QOS_NOT_SPECIFIED;
  383. pTcFlowSpec->ReceivingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
  384. pTcFlowSpec->ReceivingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
  385. pTcFlowSpec->ReceivingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
  386. pTcFlowSpec->ReceivingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT;
  387. pTcFlowSpec->TcObjectsLength = sizeof(QOS_DS_CLASS) + sizeof(QOS_TRAFFIC_CLASS);
  388. pTclass = (LPQOS_TRAFFIC_CLASS) (pTcFlowSpec->TcObjects);
  389. pTclass->ObjectHdr.ObjectType = QOS_OBJECT_TRAFFIC_CLASS;
  390. pTclass->ObjectHdr.ObjectLength = sizeof(QOS_TRAFFIC_CLASS);
  391. pTclass->TrafficClass = PATHPING_QOS_TRAFFIC_CLASS;
  392. pDclass = (LPQOS_DS_CLASS)((PCHAR)pTcFlowSpec->TcObjects +
  393. sizeof(QOS_TRAFFIC_CLASS));
  394. pDclass->ObjectHdr.ObjectType = QOS_OBJECT_DS_CLASS;
  395. pDclass->ObjectHdr.ObjectLength = sizeof(QOS_DS_CLASS);
  396. pDclass->DSField = PATHPING_QOS_DS_CLASS;
  397. Status = TcAddFlow(
  398. hInterfaceHandle,
  399. NULL,
  400. 0,
  401. pTcFlowSpec,
  402. &hFlowHandle);
  403. if(Status != ERROR_SUCCESS)
  404. {
  405. NlsPutMsg(STDOUT, PATHPING_TCADDFLOW_FAILED, Status, pCurrentIfc->pInterfaceName);
  406. goto QoSCleanup;
  407. }
  408. else
  409. {
  410. TC_GEN_FILTER FilterSpec;
  411. IP_PATTERN IpPattern;
  412. IP_PATTERN IpMask;
  413. FilterSpec.AddressType = NDIS_PROTOCOL_ID_TCP_IP;
  414. FilterSpec.PatternSize = sizeof(IP_PATTERN);
  415. FilterSpec.Pattern = &IpPattern;
  416. FilterSpec.Mask = &IpMask;
  417. memset (&IpPattern, 0, sizeof(IP_PATTERN) );
  418. memset (&IpMask, 0, sizeof(IP_PATTERN) );
  419. IpPattern.SrcAddr = SrcAddr;
  420. IpPattern.DstAddr = DstAddr;
  421. IpPattern.ProtocolId = 1;
  422. IpMask.SrcAddr = -1;
  423. IpMask.DstAddr = 0;
  424. IpMask.ProtocolId = -1;
  425. Status = TcAddFilter(hFlowHandle,
  426. &FilterSpec,
  427. &hFilterHandle);
  428. if(Status != ERROR_SUCCESS)
  429. {
  430. NlsPutMsg(STDOUT, PATHPING_TCADDFILTER_FAILED, Status, pCurrentIfc->pInterfaceName);
  431. goto QoSCleanup;
  432. }
  433. goto SendPings;
  434. }
  435. }
  436. else
  437. {
  438. NlsPutMsg(STDOUT, PATHPING_NO_RESOURCES);
  439. goto QoSCleanup;
  440. }
  441. }
  442. }
  443. }
  444. }
  445. NlsPutMsg(STDOUT, PATHPING_NOTRAFFICINTERFACES);
  446. NlsPutMsg( STDOUT, PATHPING_ALIGN_IP_ADDRESS, inet_ntoa(*(struct in_addr *)&SrcAddr) );
  447. goto QoSCleanup;
  448. }
  449. else
  450. {
  451. NlsPutMsg(STDOUT, PATHPING_NOTRAFFICINTERFACES);
  452. goto QoSCleanup;
  453. }
  454. SendPings:
  455. // Allocate memory for replies
  456. for (h=1; h<=ulHopCount; h++)
  457. hop[h].pReply = LocalAlloc(LMEM_FIXED, g_ulRcvBufSize);
  458. for (h=1; h<=ulHopCount; h++)
  459. {
  460. NlsPutMsg( STDOUT, PATHPING_MESSAGE_4, h);
  461. NlsPutMsg( STDOUT, PATHPING_ALIGN_IP_ADDRESS, inet_ntoa(*(struct in_addr *)&hop[h].sinAddr.sin_addr.s_addr));
  462. numberOfReplies = IcmpSendEcho2( g_hIcmp, // handle to icmp
  463. NULL, // no event
  464. NULL, // callback function
  465. NULL,
  466. hop[h].sinAddr.sin_addr.s_addr, // destination
  467. SendBuffer,
  468. DEFAULT_SEND_SIZE,
  469. NULL,
  470. hop[h].pReply,
  471. g_ulRcvBufSize,
  472. g_ulTimeout );
  473. if(numberOfReplies == 0)
  474. {
  475. Status = GetLastError();
  476. reply = NULL;
  477. }
  478. else
  479. {
  480. reply = hop[h].pReply4;
  481. Status = reply->Status;
  482. }
  483. if(Status == IP_SUCCESS)
  484. {
  485. NlsPutMsg(STDOUT, PATHPING_QOS_SUCCESS);
  486. }
  487. else
  488. {
  489. if(Status == IP_REQ_TIMED_OUT) {
  490. NlsPutMsg(STDOUT, PATHPING_QOS_FAILURE);
  491. }
  492. else {
  493. if (Status < IP_STATUS_BASE) {
  494. NlsPutMsg(STDOUT, PATHPING_MESSAGE_7);
  495. }
  496. else {
  497. //
  498. // Fatal error.
  499. //
  500. NlsPutMsg(STDOUT, PATHPING_BAD_REQ);
  501. }
  502. goto QoSCleanup;
  503. }
  504. }
  505. }
  506. QoSCleanup:
  507. for (h=1; h<=ulHopCount; h++)
  508. {
  509. if(hop[h].pReply)
  510. LocalFree(hop[h].pReply);
  511. }
  512. if(hFilterHandle)
  513. {
  514. TcDeleteFilter(hFilterHandle);
  515. }
  516. if(hFlowHandle)
  517. {
  518. TcDeleteFlow(hFlowHandle);
  519. }
  520. if(hInterfaceHandle)
  521. {
  522. TcCloseInterface(hInterfaceHandle);
  523. }
  524. if(hClientHandle)
  525. {
  526. TcDeregisterClient(hClientHandle);
  527. }
  528. if(pTcIfcBuffer)
  529. LocalFree(pTcIfcBuffer);
  530. if(pTcFlowSpec)
  531. LocalFree(pTcFlowSpec);
  532. }
  533. void QoSCheckRSVP(ULONG begin, ULONG end)
  534. {
  535. WSADATA wsaData;
  536. SOCKET sockRaw;
  537. struct sockaddr_in dest,from;
  538. struct hostent * hp;
  539. int bread,datasize;
  540. int fromlen = sizeof(from);
  541. char *buf, *dest_ip;
  542. char *icmp_data;
  543. char recvbuf[MAX_PACKET];
  544. unsigned int addr=0;
  545. USHORT seq_no = 0;
  546. ULONG h, bwrote;
  547. PULONG pDestIp;
  548. SOCKET sockIcmp;
  549. HANDLE hRSVP, hICMP;
  550. HANDLE hEvents[2];
  551. common_header *rsvphdr;
  552. ULONG Status;
  553. Object_header *orisession = 0;
  554. hICMP = hRSVP = WSA_INVALID_EVENT;
  555. sockIcmp = sockRaw = INVALID_SOCKET;
  556. NlsPutMsg(STDOUT, PATHPING_RSVPAWAREHDR_MSG);
  557. do
  558. {
  559. if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
  560. {
  561. NlsPutMsg(STDOUT, PATHPING_WSASTARTUP_FAILED, GetLastError());
  562. break;
  563. }
  564. if(WSA_INVALID_EVENT == (hRSVP = WSACreateEvent()))
  565. {
  566. NlsPutMsg(STDOUT, PATHPING_WSACREATEEVENT_FAILED, WSAGetLastError());
  567. break;
  568. }
  569. if(WSA_INVALID_EVENT == (hICMP = WSACreateEvent()))
  570. {
  571. NlsPutMsg(STDOUT, PATHPING_WSACREATEEVENT_FAILED, WSAGetLastError());
  572. break;
  573. }
  574. //
  575. // Open a socket for sending RSVP messages.
  576. //
  577. sockRaw = WSASocket (AF_INET,
  578. SOCK_RAW,
  579. 46,
  580. NULL, 0,0);
  581. if (sockRaw == INVALID_SOCKET)
  582. {
  583. NlsPutMsg(STDOUT, PATHPING_WSASOCKET_FAILED, WSAGetLastError());
  584. break;
  585. }
  586. //
  587. // open a socket for receiving ICMP data
  588. //
  589. sockIcmp = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
  590. if(INVALID_SOCKET == sockIcmp)
  591. {
  592. NlsPutMsg(STDOUT, PATHPING_WSASOCKET_FAILED, WSAGetLastError());
  593. break;
  594. }
  595. if(WSAEventSelect(sockIcmp, hICMP, FD_READ) == SOCKET_ERROR)
  596. {
  597. NlsPutMsg(STDOUT, PATHPING_WSAEVENTSELECT_FAILED, WSAGetLastError());
  598. break;
  599. }
  600. if(SOCKET_ERROR == WSAEventSelect(sockRaw, hRSVP, FD_READ|FD_WRITE))
  601. {
  602. NlsPutMsg(STDOUT, PATHPING_WSAEVENTSELECT_FAILED, WSAGetLastError());
  603. break;
  604. }
  605. hEvents[0] = hRSVP;
  606. hEvents[1] = hICMP;
  607. memset(&dest,0,sizeof(dest));
  608. dest.sin_family = AF_INET;
  609. memset(&from,0,sizeof(from));
  610. from.sin_family = AF_INET;
  611. for(h=begin; h<=end; h++)
  612. {
  613. //
  614. // Bind the ICMP socket. The RSVP socket gets bound implicitly when we do a sendto.
  615. //
  616. from.sin_addr.s_addr = QoSGetSourceAddress(hop[h].sinAddr.sin_addr.s_addr);
  617. bind(sockIcmp, (struct sockaddr *)&from, sizeof(from));
  618. NlsPutMsg( STDOUT, PATHPING_MESSAGE_4, h);
  619. NlsPutMsg( STDOUT, PATHPING_ALIGN_IP_ADDRESS, inet_ntoa(*(struct in_addr *)&hop[h].sinAddr.sin_addr));
  620. dest.sin_addr.s_addr = hop[h].sinAddr.sin_addr.s_addr;
  621. //
  622. // Now, let's muck around with the RESV message so that it is destined to the dest_ip
  623. //
  624. buf = (PCHAR)RsvpResvMsg + sizeof(common_header);
  625. bwrote = 0;
  626. while(bwrote != 3)
  627. {
  628. Object_header *obj = (Object_header *)buf;
  629. switch(obj->obj_class)
  630. {
  631. case class_SESSION:
  632. orisession = obj;
  633. pDestIp = (PULONG)((PCHAR)obj + sizeof(Object_header));
  634. *pDestIp = dest.sin_addr.s_addr;
  635. bwrote++;
  636. break;
  637. case class_RSVP_HOP:
  638. pDestIp = (PULONG)((PCHAR)obj + sizeof(Object_header));
  639. *pDestIp = from.sin_addr.s_addr;
  640. bwrote++;
  641. break;
  642. case class_FILTER_SPEC:
  643. pDestIp = (PULONG)((PCHAR)obj + sizeof(Object_header));
  644. *pDestIp = from.sin_addr.s_addr;
  645. bwrote++;
  646. break;
  647. }
  648. buf = (PCHAR)buf + ntohs(obj->obj_length);
  649. }
  650. //
  651. // Recompute the RSVP checksum
  652. //
  653. rsvphdr = (common_header *) RsvpResvMsg;
  654. rsvphdr->rsvp_cksum = 0;
  655. rsvphdr->rsvp_cksum = in_cksum(RsvpResvMsg, ntohs(rsvphdr->rsvp_length));
  656. bwrote = sendto(sockRaw,
  657. RsvpResvMsg,
  658. sizeof(RsvpResvMsg),
  659. 0,
  660. (struct sockaddr*)&dest,
  661. sizeof(dest));
  662. if (bwrote == SOCKET_ERROR)
  663. {
  664. NlsPutMsg(STDOUT, PATHPING_SENDTO_FAILED, WSAGetLastError());
  665. break;
  666. }
  667. //
  668. // Wait for ICMP protocol unreachable or a RESV-ERR message.
  669. //
  670. Status = WSAWaitForMultipleEvents(2,
  671. hEvents,
  672. FALSE,
  673. g_ulTimeout,
  674. TRUE);
  675. switch(Status)
  676. {
  677. case WSA_WAIT_FAILED:
  678. NlsPutMsg(STDOUT, PATHPING_WSAWAIT_FAILED, WSAGetLastError());
  679. break;
  680. case WSA_WAIT_EVENT_0:
  681. bread = recvfrom(sockRaw,
  682. recvbuf,
  683. MAX_PACKET,
  684. 0,
  685. (struct sockaddr*)&from,
  686. &fromlen);
  687. if (bread == SOCKET_ERROR)
  688. {
  689. if (WSAGetLastError() == WSAETIMEDOUT) {
  690. NlsPutMsg(STDOUT, PATHPING_REQ_TIMED_OUT);
  691. continue;
  692. }
  693. NlsPutMsg(STDOUT, PATHPING_RECVFROM_FAILED, WSAGetLastError());
  694. break;
  695. }
  696. decode_msg(recvbuf, bread, &from, RSVP_MSG, orisession);
  697. WSAResetEvent(hRSVP);
  698. continue;
  699. case WSA_WAIT_EVENT_0+1:
  700. bread = recvfrom(sockIcmp,
  701. recvbuf,
  702. MAX_PACKET,
  703. 0,
  704. (struct sockaddr *)&from,
  705. &fromlen);
  706. if(SOCKET_ERROR == bread)
  707. {
  708. if (WSAGetLastError() == WSAETIMEDOUT) {
  709. NlsPutMsg(STDOUT, PATHPING_REQ_TIMED_OUT);
  710. continue;
  711. }
  712. NlsPutMsg(STDOUT, PATHPING_RECVFROM_FAILED, WSAGetLastError());
  713. break;
  714. }
  715. else
  716. {
  717. decode_msg(recvbuf, bread, &from, ICMP_MSG, 0);
  718. }
  719. WSAResetEvent(hICMP);
  720. continue;
  721. case WSA_WAIT_TIMEOUT:
  722. NlsPutMsg(STDOUT, PATHPING_REQ_TIMED_OUT);
  723. continue;
  724. }
  725. break;
  726. }
  727. } while(0);
  728. if(hICMP != WSA_INVALID_EVENT) WSACloseEvent(hICMP);
  729. if(hRSVP != WSA_INVALID_EVENT) WSACloseEvent(hRSVP);
  730. WSACleanup();
  731. }
  732. void QoSDiagRSVP(ULONG begin, ULONG end, BOOLEAN RouterAlert)
  733. {
  734. #define RSVPPATH_STARTPORT 5555
  735. ULONG port;
  736. WSADATA wsaData;
  737. SOCKET sockRaw;
  738. struct sockaddr_in dest,from;
  739. struct hostent * hp;
  740. int bread,datasize;
  741. int fromlen = sizeof(from);
  742. char *buf, *dest_ip;
  743. char *icmp_data;
  744. char recvbuf[MAX_PACKET];
  745. unsigned int addr=0;
  746. USHORT seq_no = 0;
  747. ULONG len, h, bwrote;
  748. PULONG pDestIp;
  749. SOCKET sockIcmp;
  750. HANDLE hICMP;
  751. HANDLE hEvents[2];
  752. common_header *rsvphdr;
  753. ULONG Status;
  754. Object_header *orisession = 0;
  755. static char szAllSBMMcastAddr[] = "224.0.0.17";
  756. hICMP = WSA_INVALID_EVENT;
  757. sockIcmp = sockRaw = INVALID_SOCKET;
  758. NlsPutMsg(STDOUT, PATHPING_RSVPCONNECT_MSG);
  759. do
  760. {
  761. if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
  762. {
  763. NlsPutMsg(STDOUT, PATHPING_WSASTARTUP_FAILED, GetLastError());
  764. break;
  765. }
  766. if(WSA_INVALID_EVENT == (hICMP = WSACreateEvent()))
  767. {
  768. NlsPutMsg(STDOUT, PATHPING_WSACREATEEVENT_FAILED, GetLastError());
  769. break;
  770. }
  771. //
  772. // Open a socket for sending RSVP messages.
  773. //
  774. sockRaw = WSASocket (AF_INET,
  775. SOCK_RAW,
  776. 46,
  777. NULL, 0,0);
  778. if (sockRaw == INVALID_SOCKET)
  779. {
  780. NlsPutMsg(STDOUT, PATHPING_WSASOCKET_FAILED, GetLastError());
  781. break;
  782. }
  783. //
  784. // open a socket for receiving ICMP data
  785. //
  786. sockIcmp = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
  787. if(INVALID_SOCKET == sockIcmp)
  788. {
  789. NlsPutMsg(STDOUT, PATHPING_WSASOCKET_FAILED, GetLastError());
  790. break;
  791. }
  792. if(WSAEventSelect(sockIcmp, hICMP, FD_READ) == SOCKET_ERROR)
  793. {
  794. NlsPutMsg(STDOUT, PATHPING_WSAEVENTSELECT_FAILED, WSAGetLastError());
  795. break;
  796. }
  797. hEvents[0] = hICMP;
  798. memset(&dest,0,sizeof(dest));
  799. dest.sin_family = AF_INET;
  800. memset(&from,0,sizeof(from));
  801. from.sin_family = AF_INET;
  802. if(RouterAlert)
  803. {
  804. //
  805. // Add The RouterAlert option
  806. //
  807. Status = setsockopt( sockRaw,
  808. IPPROTO_IP,
  809. IP_OPTIONS,
  810. (void *)Router_alert,
  811. sizeof(Router_alert));
  812. }
  813. for(h=begin; h<=end; h++)
  814. {
  815. // We send out PATH messages with an expired TTL to each of the hops.
  816. // and wait for ICMP time exceeded message. Note that we have to change
  817. // the session every time. Otherwise, the first RSVP aware router will not
  818. // forward the PATH message, but rather trigger the PATH messages off its own
  819. // timer.
  820. //
  821. // Bind the ICMP socket.
  822. //
  823. from.sin_addr.s_addr = QoSGetSourceAddress(hop[h].sinAddr.sin_addr.s_addr);
  824. bind(sockIcmp, (struct sockaddr *)&from, sizeof(from));
  825. //
  826. // Now, let's muck around with the PATH message so that it is destined to the dest_ip
  827. //
  828. buf = (PCHAR)RsvpPathMsg + sizeof(common_header);
  829. rsvphdr = (common_header *) RsvpPathMsg;
  830. rsvphdr->rsvp_snd_TTL = (uchar) h;
  831. len = ntohs(rsvphdr->rsvp_length) - sizeof(common_header);
  832. bwrote = 0;
  833. while(len > 0 && bwrote != 3)
  834. {
  835. Object_header *obj = (Object_header *)buf;
  836. switch(obj->obj_class)
  837. {
  838. case class_SESSION:
  839. {
  840. SESSION *x = (SESSION *) obj;
  841. // change the session in the message.
  842. x->sess4_addr.s_addr = hop[end].sinAddr.sin_addr.s_addr;
  843. if(port == 0)
  844. {
  845. x->sess4_port = htons(RSVPPATH_STARTPORT);
  846. port = RSVPPATH_STARTPORT;
  847. }
  848. else
  849. {
  850. x->sess4_port = htons((ushort)(ntohs(x->sess4_port) + 1));
  851. }
  852. bwrote++;
  853. break;
  854. }
  855. case class_RSVP_HOP:
  856. {
  857. RSVP_HOP *pRsvpHop = (RSVP_HOP *) obj;
  858. pRsvpHop->hop4_addr = from.sin_addr;
  859. bwrote++;
  860. break;
  861. }
  862. case class_SENDER_TEMPLATE:
  863. {
  864. SENDER_TEMPLATE *t = (SENDER_TEMPLATE *) obj;
  865. t->filt_srcaddr = from.sin_addr;
  866. bwrote++;
  867. break;
  868. }
  869. }
  870. buf = (PCHAR)buf + ntohs(obj->obj_length);
  871. len -= ntohs(obj->obj_length);
  872. }
  873. //
  874. // Recompute the RSVP checksum
  875. //
  876. rsvphdr = (common_header *) RsvpPathMsg;
  877. rsvphdr->rsvp_cksum = 0;
  878. rsvphdr->rsvp_cksum = in_cksum(RsvpPathMsg, ntohs(rsvphdr->rsvp_length));
  879. NlsPutMsg( STDOUT, PATHPING_MESSAGE_4, h);
  880. NlsPutMsg( STDOUT, PATHPING_ALIGN_IP_ADDRESS, inet_ntoa(*(struct in_addr *)&hop[h].sinAddr.sin_addr.s_addr));
  881. Status = setsockopt( sockRaw,
  882. IPPROTO_IP,
  883. IP_TTL,
  884. (char *) &h,
  885. sizeof(h) );
  886. dest.sin_addr.s_addr = hop[end].sinAddr.sin_addr.s_addr;
  887. bwrote = sendto(sockRaw,
  888. RsvpPathMsg,
  889. sizeof(RsvpPathMsg),
  890. 0,
  891. (struct sockaddr*)&dest,
  892. sizeof(dest));
  893. if (bwrote == SOCKET_ERROR)
  894. {
  895. NlsPutMsg(STDOUT, PATHPING_SENDTO_FAILED, WSAGetLastError());
  896. break;
  897. }
  898. //
  899. // Wait for ICMP protocol unreachable or a RESV-ERR message.
  900. //
  901. Status = WSAWaitForMultipleEvents(1,
  902. hEvents,
  903. FALSE,
  904. g_ulTimeout,
  905. TRUE);
  906. switch(Status)
  907. {
  908. case WSA_WAIT_FAILED:
  909. NlsPutMsg(STDOUT, PATHPING_WSAWAIT_FAILED, WSAGetLastError());
  910. break;
  911. case WSA_WAIT_EVENT_0:
  912. bread = recvfrom(sockIcmp,
  913. recvbuf,
  914. MAX_PACKET,
  915. 0,
  916. (struct sockaddr *)&from,
  917. &fromlen);
  918. if(SOCKET_ERROR == bread)
  919. {
  920. if (WSAGetLastError() == WSAETIMEDOUT) {
  921. NlsPutMsg(STDOUT, PATHPING_REQ_TIMED_OUT);
  922. continue;
  923. }
  924. NlsPutMsg(STDOUT, PATHPING_RECVFROM_FAILED, WSAGetLastError());
  925. break;
  926. }
  927. else
  928. {
  929. decode_msg(recvbuf, bread, &from, ICMP_MSG, 0);
  930. }
  931. WSAResetEvent(hICMP);
  932. continue;
  933. case WSA_WAIT_TIMEOUT:
  934. NlsPutMsg(STDOUT, PATHPING_REQ_TIMED_OUT);
  935. continue;
  936. }
  937. break;
  938. }
  939. h = 255;
  940. Status = setsockopt( sockRaw,
  941. IPPROTO_IP,
  942. IP_TTL,
  943. (char *) &h,
  944. sizeof(h) );
  945. for(h=begin; h<=end; h++)
  946. {
  947. // send PATH_TEAR for each of the sessions.
  948. from.sin_addr.s_addr = QoSGetSourceAddress(hop[h].sinAddr.sin_addr.s_addr);
  949. buf = (PCHAR)RsvpPathTearMsg + sizeof(common_header);
  950. rsvphdr = (common_header *) RsvpPathTearMsg;
  951. len = ntohs(rsvphdr->rsvp_length) - sizeof(common_header);
  952. bwrote = 0;
  953. while(len > 0 && bwrote != 3)
  954. {
  955. Object_header *obj = (Object_header *)buf;
  956. switch(obj->obj_class)
  957. {
  958. case class_SESSION:
  959. {
  960. SESSION *x = (SESSION *) obj;
  961. // change the session in the message.
  962. x->sess4_addr.s_addr = hop[end].sinAddr.sin_addr.s_addr;
  963. if(port == RSVPPATH_STARTPORT)
  964. {
  965. port = 0;
  966. x->sess4_port = htons(RSVPPATH_STARTPORT);
  967. }
  968. else
  969. {
  970. x->sess4_port = htons((ushort)(ntohs(x->sess4_port) + 1));
  971. }
  972. bwrote++;
  973. break;
  974. }
  975. case class_RSVP_HOP:
  976. {
  977. RSVP_HOP *pRsvpHop = (RSVP_HOP *) obj;
  978. pRsvpHop->hop4_addr = from.sin_addr;
  979. bwrote++;
  980. break;
  981. }
  982. case class_SENDER_TEMPLATE:
  983. {
  984. SENDER_TEMPLATE *t = (SENDER_TEMPLATE *) obj;
  985. t->filt_srcaddr = from.sin_addr;
  986. bwrote++;
  987. break;
  988. }
  989. }
  990. buf = (PCHAR)buf + ntohs(obj->obj_length);
  991. len -= ntohs(obj->obj_length);
  992. }
  993. //
  994. // Recompute the RSVP checksum
  995. //
  996. rsvphdr = (common_header *) RsvpPathTearMsg;
  997. rsvphdr->rsvp_cksum = 0;
  998. rsvphdr->rsvp_cksum = in_cksum(RsvpPathTearMsg, ntohs(rsvphdr->rsvp_length));
  999. dest.sin_addr.s_addr = hop[end].sinAddr.sin_addr.s_addr;
  1000. bwrote = sendto(sockRaw,
  1001. RsvpPathTearMsg,
  1002. sizeof(RsvpPathTearMsg),
  1003. 0,
  1004. (struct sockaddr*)&dest,
  1005. sizeof(dest));
  1006. if (bwrote == SOCKET_ERROR)
  1007. {
  1008. NlsPutMsg(STDOUT, PATHPING_SENDTO_FAILED, WSAGetLastError());
  1009. break;
  1010. }
  1011. }
  1012. } while(0);
  1013. if(hICMP != WSA_INVALID_EVENT) WSACloseEvent(hICMP);
  1014. WSACleanup();
  1015. }