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.

731 lines
22 KiB

  1. //=============================================================================
  2. // Copyright (c) 1997 Microsoft Corporation
  3. // File: packet.c
  4. //
  5. // Abstract:
  6. // This module defines SendPacket, JoinMulticastGroup, LeaveMulticastGroup,
  7. // and xsum.
  8. //
  9. // Author: K.S.Lokesh (lokeshs@) 11-1-97
  10. //
  11. // Revision History:
  12. //=============================================================================
  13. #include "pchigmp.h"
  14. #pragma hdrstop
  15. UCHAR
  16. GetMaxRespCode(
  17. PIF_TABLE_ENTRY pite,
  18. DWORD val
  19. );
  20. UCHAR GetQqic (
  21. DWORD val
  22. );
  23. //------------------------------------------------------------------------------
  24. // _SendPacket
  25. //
  26. // Sends the packet. Called for ras server interfaces only for general queries.
  27. // Locks: assumes IfRead lock
  28. // for ver2 group specific query, send packet irrespective of pgie state.
  29. //------------------------------------------------------------------------------
  30. DWORD
  31. SendPacket (
  32. PIF_TABLE_ENTRY pite,
  33. PGI_ENTRY pgie, //null for gen query, and group_query_v2
  34. DWORD PacketType, //MSG_GEN_QUERY,
  35. //MSG_GROUP_QUERY_V2,MSG_GROUP_QUERY_V3
  36. // MSG_SOURCES_QUERY
  37. DWORD Group //destination McastGrp
  38. )
  39. {
  40. DWORD Error = NO_ERROR;
  41. SOCKADDR_IN saSrcAddr, saDstnAddr;
  42. BYTE *SendBufPtr;
  43. DWORD SendBufLen, IpHdrLen=0, NumSources, Count;
  44. IGMP_HEADER UNALIGNED *IgmpHeader;
  45. INT iLength;
  46. BOOL bHdrIncl = IS_RAS_SERVER_IF(pite->IfType);
  47. UCHAR RouterAlert[4] = {148, 4, 0, 0};
  48. //MSG_SOURCES_QUERY
  49. PIGMP_HEADER_V3_EXT pSourcesQuery;
  50. LONGLONG llCurTime;
  51. DWORD Version;
  52. Trace0(ENTER1, "Entering _SendPacket()");
  53. if (PacketType==MSG_GEN_QUERY)
  54. Version = GET_IF_VERSION(pite);
  55. else if (PacketType==MSG_GROUP_QUERY_V2)
  56. Version =2;
  57. else
  58. Version = pgie->Version;
  59. //
  60. // make sure that the pgie->version has not meanwhile changed
  61. //
  62. if ( ((PacketType==MSG_SOURCES_QUERY)||(PacketType==MSG_GROUP_QUERY_V3))
  63. && pgie->Version!=3
  64. ) {
  65. return NO_ERROR;
  66. }
  67. if ( (PacketType==MSG_GROUP_QUERY_V2) && pgie!=NULL && pgie->Version!=2)
  68. return NO_ERROR;
  69. //source query and list is empty
  70. if (PacketType==MSG_SOURCES_QUERY && IsListEmpty(&pgie->V3SourcesQueryList))
  71. return NO_ERROR;
  72. SendBufLen = sizeof(IGMP_HEADER)
  73. + ((Version==3)?sizeof(IGMP_HEADER_V3_EXT):0);
  74. IpHdrLen = (bHdrIncl)
  75. ? sizeof(IP_HEADER) + sizeof(RouterAlert) : 0;
  76. if (PacketType==MSG_SOURCES_QUERY) {
  77. SendBufPtr = (PBYTE) IGMP_ALLOC(SendBufLen + IpHdrLen
  78. + sizeof(IPADDR)*pgie->V3SourcesQueryCount,
  79. 0x4000,pite->IfIndex);
  80. }
  81. else {
  82. SendBufPtr = (PBYTE) IGMP_ALLOC(SendBufLen+IpHdrLen, 0x8000,pite->IfIndex);
  83. }
  84. if (!SendBufPtr) {
  85. return ERROR_NOT_ENOUGH_MEMORY;
  86. }
  87. //
  88. // set destination multicast addr (general queries sent to ALL_HOSTS_MCAST
  89. // and group specific queries sent to the GroupAddr
  90. //
  91. ZeroMemory((PVOID)&saDstnAddr, sizeof(saDstnAddr));
  92. saDstnAddr.sin_family = AF_INET;
  93. saDstnAddr.sin_port = 0;
  94. saDstnAddr.sin_addr.s_addr = (PacketType==MSG_GEN_QUERY) ?
  95. ALL_HOSTS_MCAST : Group;
  96. //
  97. // set igmp header
  98. //
  99. IgmpHeader = (IGMP_HEADER UNALIGNED*)
  100. (bHdrIncl
  101. ? &SendBufPtr[IpHdrLen]
  102. : SendBufPtr);
  103. IgmpHeader->Vertype = IGMP_QUERY;
  104. // have to divide GenQueryInterval by 100, as it should be in units of 100ms
  105. if (PacketType==MSG_GEN_QUERY) {
  106. // for gen query, set response time if the IF-Ver2 else set it to 0
  107. IgmpHeader->ResponseTime = GetMaxRespCode(pite,
  108. pite->Config.GenQueryMaxResponseTime/100);
  109. }
  110. else {
  111. IgmpHeader->ResponseTime = GetMaxRespCode(pite,
  112. pite->Config.LastMemQueryInterval/100);
  113. }
  114. if (Version==3) {
  115. llCurTime = GetCurrentIgmpTime();
  116. pSourcesQuery = (PIGMP_HEADER_V3_EXT)
  117. ((PBYTE)IgmpHeader+sizeof(IGMP_HEADER));
  118. pSourcesQuery->Reserved = 0;
  119. pSourcesQuery->QRV = (UCHAR)pite->Config.RobustnessVariable;
  120. pSourcesQuery->QQIC = GetQqic(pite->Config.GenQueryInterval);
  121. pSourcesQuery->NumSources = 0;
  122. if (PacketType==MSG_GROUP_QUERY_V3) {
  123. pSourcesQuery->SFlag =
  124. (QueryRemainingTime(&pgie->GroupMembershipTimer, llCurTime)
  125. <=pite->Config.LastMemQueryInterval)
  126. ? 0 : 1;
  127. }
  128. // first send gen query and 1st sources query packet without suppress bit
  129. else {
  130. pSourcesQuery->SFlag = 0;
  131. }
  132. }
  133. // twice in loop for sources query
  134. Count = (PacketType==MSG_SOURCES_QUERY)? 0 : 1;
  135. for ( ; Count<2; Count++) {
  136. IgmpHeader->Xsum = 0;
  137. if (PacketType==MSG_SOURCES_QUERY) {
  138. PLIST_ENTRY pHead, ple;
  139. if (Count==1 && (PacketType==MSG_SOURCES_QUERY))
  140. pSourcesQuery->SFlag = 1;
  141. pHead = &pgie->V3SourcesQueryList;
  142. for (NumSources=0,ple=pHead->Flink; ple!=pHead; ) {
  143. PGI_SOURCE_ENTRY pSourceEntry =
  144. CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList);
  145. ple = ple->Flink;
  146. if ( (pSourcesQuery->SFlag
  147. &&(QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)
  148. >GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval))
  149. || (!pSourcesQuery->SFlag
  150. &&(QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)
  151. <=GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval)) )
  152. {
  153. if (NumSources==0) {
  154. Trace4(SEND,
  155. "Sent Sources Query on IfIndex(%0x) IpAddr(%d.%d.%d.%d) "
  156. "for Group(%d.%d.%d.%d) SFlag:%d",
  157. pite->IfIndex, PRINT_IPADDR(pite->IpAddr),
  158. PRINT_IPADDR(Group),pSourcesQuery->SFlag
  159. );
  160. }
  161. pSourcesQuery->Sources[NumSources++] = pSourceEntry->IpAddr;
  162. Trace1(SEND, " Source:%d.%d.%d.%d",
  163. PRINT_IPADDR(pSourceEntry->IpAddr));
  164. if (--pSourceEntry->V3SourcesQueryLeft==0) {
  165. RemoveEntryList(&pSourceEntry->V3SourcesQueryList);
  166. pSourceEntry->bInV3SourcesQueryList = FALSE;
  167. pgie->V3SourcesQueryCount--;
  168. }
  169. }
  170. }
  171. if (NumSources==0)
  172. continue;
  173. pSourcesQuery->NumSources = htons((USHORT)NumSources);
  174. SendBufLen += sizeof(IPADDR)*NumSources;
  175. }
  176. IgmpHeader->Group = (PacketType==MSG_GEN_QUERY) ? 0 : Group;
  177. IgmpHeader->Xsum = ~xsum((PVOID)IgmpHeader, SendBufLen);
  178. //
  179. // send the packet
  180. //
  181. if (!bHdrIncl) {
  182. Error = NO_ERROR;
  183. iLength = sendto(pite->SocketEntry.Socket, SendBufPtr,
  184. SendBufLen+IpHdrLen, 0,
  185. (PSOCKADDR) &saDstnAddr, sizeof(SOCKADDR_IN)
  186. );
  187. //
  188. // error messages and statistics updates
  189. //
  190. if ( (iLength==SOCKET_ERROR) || ((DWORD)iLength<SendBufLen+IpHdrLen) ) {
  191. Error = WSAGetLastError();
  192. Trace4(ERR,
  193. "error %d sending query on McastAddr %d.%d.%d.%d on "
  194. "interface %d(%d.%d.%d.%d)",
  195. Error, PRINT_IPADDR(saDstnAddr.sin_addr.s_addr), pite->IfIndex,
  196. PRINT_IPADDR(pite->IpAddr));
  197. IgmpAssertOnError(FALSE);
  198. Logwarn2(SENDTO_FAILED, "%I%I", pite->IpAddr, saDstnAddr.sin_addr, Error);
  199. }
  200. }
  201. //
  202. // for RAS server interface, use HDRINCL option. Build up the ip header and
  203. // send the packet to all RAS clients.
  204. //
  205. else {
  206. PIP_HEADER IpHdr;
  207. DWORD IpHdrLen = sizeof(IP_HEADER) + sizeof(RouterAlert);
  208. //
  209. // igmp follows the ip header containing the routerAlert option
  210. //
  211. IpHdr = (IP_HEADER *)((PBYTE)SendBufPtr);
  212. #define wordsof(x) (((x)+3)/4) /* Number of 32-bit words */
  213. // Set IP version (4) and IP header length
  214. IpHdr->Hl = (UCHAR) (IPVERSION * 16
  215. + wordsof(sizeof(IP_HEADER) + sizeof(RouterAlert)));
  216. // No TOS bits are set
  217. IpHdr->Tos = 0;
  218. // Total IP length is set in host order
  219. IpHdr->Len = (USHORT)(IpHdrLen+sizeof(IGMP_HEADER));
  220. // Stack will fill in the ID
  221. IpHdr->Id = 0;
  222. // No offset
  223. IpHdr->Offset = 0;
  224. // Set the TTL to 1
  225. IpHdr->Ttl = 1;
  226. // Protocol is IGMP
  227. IpHdr->Protocol = IPPROTO_IGMP;
  228. // Checksum is set by stack
  229. IpHdr->Xsum = 0;
  230. // Set source and destination address
  231. IpHdr->Src.s_addr = pite->IpAddr;
  232. IpHdr->Dstn.s_addr = ALL_HOSTS_MCAST;
  233. // set the router alert option, but still set it
  234. memcpy( (void *)((UCHAR *)IpHdr + sizeof(IP_HEADER)),
  235. (void *)RouterAlert, sizeof(RouterAlert));
  236. // send packet to all RAS clients, with the destination address in sendto
  237. // set to the unicast addr of the client
  238. {
  239. PLIST_ENTRY pHead, ple;
  240. PRAS_TABLE_ENTRY prte;
  241. pHead = &pite->pRasTable->ListByAddr;
  242. Error = NO_ERROR;
  243. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  244. // get address of ras client
  245. prte = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
  246. saDstnAddr.sin_addr.s_addr = prte->NHAddr;
  247. // send the packet to the client
  248. iLength = sendto(pite->SocketEntry.Socket, SendBufPtr,
  249. SendBufLen+IpHdrLen, 0,
  250. (PSOCKADDR) &saDstnAddr, sizeof(SOCKADDR_IN)
  251. );
  252. // print error if sendto failed
  253. if ((iLength==SOCKET_ERROR) || ((DWORD)iLength<SendBufLen+IpHdrLen) ) {
  254. Error = WSAGetLastError();
  255. Trace4(ERR,
  256. "error %d sending query to Ras client %d.%d.%d.%d on "
  257. "interface %d(%d.%d.%d.%d)",
  258. Error, PRINT_IPADDR(saDstnAddr.sin_addr.s_addr), pite->IfIndex,
  259. PRINT_IPADDR(pite->IpAddr)
  260. );
  261. IgmpAssertOnError(FALSE);
  262. Logwarn2(SENDTO_FAILED, "%I%I", pite->IpAddr,
  263. saDstnAddr.sin_addr.s_addr, Error);
  264. }
  265. else {
  266. Trace1(SEND, "sent general query to ras client: %d.%d.%d.%d",
  267. PRINT_IPADDR(prte->NHAddr));
  268. }
  269. }//for loop:sent packet to a RAS client
  270. }//sent packets to all ras clients
  271. }//created IPHeader and sent packets to all ras clients
  272. }; //for loop. send both packets
  273. if (PacketType==MSG_SOURCES_QUERY) {
  274. pgie->bV3SourcesQueryNow = FALSE;
  275. // set timer for next sources query
  276. if (pgie->V3SourcesQueryCount>0) {
  277. ACQUIRE_TIMER_LOCK("_SendPacket");
  278. #if DEBUG_TIMER_TIMERID
  279. SET_TIMER_ID(&pgie->V3SourcesQueryTimer,1001, pite->IfIndex,
  280. Group, 0);
  281. #endif
  282. if (IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer)) {
  283. UpdateLocalTimer(&pgie->V3SourcesQueryTimer,
  284. (pite->Config.LastMemQueryInterval/pite->Config.LastMemQueryCount),
  285. DBG_Y);
  286. }
  287. else {
  288. InsertTimer(&pgie->V3SourcesQueryTimer,
  289. (pite->Config.LastMemQueryInterval/pite->Config.LastMemQueryCount),
  290. TRUE, DBG_Y);
  291. }
  292. RELEASE_TIMER_LOCK("_SendPacket");
  293. }
  294. }
  295. //
  296. // if successful, print trace and update statistics
  297. //
  298. if (Error==NO_ERROR) {
  299. if (PacketType==MSG_GEN_QUERY) {
  300. Trace2(SEND, "Sent GenQuery on IfIndex(%0x) IpAddr(%d.%d.%d.%d)",
  301. pite->IfIndex, PRINT_IPADDR(pite->IpAddr));
  302. InterlockedIncrement(&pite->Info.GenQueriesSent);
  303. }
  304. else if (PacketType==MSG_GROUP_QUERY_V2 || PacketType==MSG_GROUP_QUERY_V3) {
  305. Trace3(SEND,
  306. "Sent Group Query on IfIndex(%0x) IpAddr(%d.%d.%d.%d) "
  307. "for Group(%d.%d.%d.%d)",
  308. pite->IfIndex, PRINT_IPADDR(pite->IpAddr), PRINT_IPADDR(Group));
  309. InterlockedIncrement(&pite->Info.GroupQueriesSent);
  310. }
  311. }
  312. IGMP_FREE_NOT_NULL(SendBufPtr);
  313. Trace0(LEAVE1, "Leaving _SendPacket()");
  314. return Error;
  315. } //end _SendPacket
  316. DWORD
  317. BlockSource (
  318. SOCKET Sock,
  319. DWORD dwGroup,
  320. DWORD IfIndex,
  321. IPADDR IpAddr,
  322. IPADDR Source
  323. )
  324. {
  325. struct ip_mreq imOption;
  326. DWORD Error = NO_ERROR;
  327. DWORD dwRetval;
  328. struct ip_mreq_source imr;
  329. imr.imr_multiaddr.s_addr = dwGroup;
  330. imr.imr_sourceaddr.s_addr = Source;
  331. imr.imr_interface.s_addr = IpAddr;
  332. dwRetval = setsockopt(Sock, IPPROTO_IP, IP_BLOCK_SOURCE,
  333. (PCHAR)&imr, sizeof(imr));
  334. if (dwRetval == SOCKET_ERROR) {
  335. Error = WSAGetLastError();
  336. Trace5(ERR,
  337. "ERROR %d BLOCKING MULTICAST GROUP(%d.%d.%d.%d) "
  338. "Source:%d.%d.%d.%d ON INTERFACE (%d) %d.%d.%d.%d",
  339. Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
  340. IfIndex, PRINT_IPADDR(IpAddr));
  341. IgmpAssertOnError(FALSE);
  342. }
  343. Trace2(MGM, "Blocking MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
  344. PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
  345. return Error;
  346. }
  347. DWORD
  348. UnBlockSource (
  349. SOCKET Sock,
  350. DWORD dwGroup,
  351. DWORD IfIndex,
  352. IPADDR IpAddr,
  353. IPADDR Source
  354. )
  355. {
  356. struct ip_mreq imOption;
  357. DWORD Error = NO_ERROR;
  358. DWORD dwRetval;
  359. struct ip_mreq_source imr;
  360. imr.imr_multiaddr.s_addr = dwGroup;
  361. imr.imr_sourceaddr.s_addr = Source;
  362. imr.imr_interface.s_addr = IpAddr;
  363. dwRetval = setsockopt(Sock, IPPROTO_IP, IP_UNBLOCK_SOURCE,
  364. (PCHAR)&imr, sizeof(imr));
  365. if (dwRetval == SOCKET_ERROR) {
  366. Error = WSAGetLastError();
  367. Trace5(ERR,
  368. "ERROR %d UN-BLOCKING MULTICAST GROUP(%d.%d.%d.%d) "
  369. "Source:%d.%d.%d.%d ON INTERFACE (%d) %d.%d.%d.%d",
  370. Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
  371. IfIndex, PRINT_IPADDR(IpAddr));
  372. IgmpAssertOnError(FALSE);
  373. }
  374. Trace2(MGM, "UnBlocking MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
  375. PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
  376. return Error;
  377. }
  378. //------------------------------------------------------------------------------
  379. // _JoinMulticastGroup
  380. //------------------------------------------------------------------------------
  381. DWORD
  382. JoinMulticastGroup (
  383. SOCKET Sock,
  384. DWORD dwGroup,
  385. DWORD IfIndex,
  386. IPADDR IpAddr,
  387. IPADDR Source
  388. )
  389. {
  390. struct ip_mreq imOption;
  391. DWORD Error = NO_ERROR;
  392. DWORD dwRetval;
  393. if (Source==0) {
  394. imOption.imr_multiaddr.s_addr = dwGroup;
  395. imOption.imr_interface.s_addr = IpAddr;
  396. dwRetval = setsockopt(Sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  397. (PBYTE)&imOption, sizeof(imOption));
  398. }
  399. else {
  400. struct ip_mreq_source imr;
  401. imr.imr_multiaddr.s_addr = dwGroup;
  402. imr.imr_sourceaddr.s_addr = Source;
  403. imr.imr_interface.s_addr = IpAddr;
  404. dwRetval = setsockopt(Sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
  405. (PCHAR)&imr, sizeof(imr));
  406. }
  407. if (dwRetval == SOCKET_ERROR) {
  408. Error = WSAGetLastError();
  409. Trace5(ERR,
  410. "ERROR %d JOINING MULTICAST GROUP(%d.%d.%d.%d) "
  411. "Source:%d.%d.%d.%d ON INTERFACE (%d) %d.%d.%d.%d",
  412. Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
  413. IfIndex, PRINT_IPADDR(IpAddr));
  414. IgmpAssertOnError(FALSE);
  415. Logerr2(JOIN_GROUP_FAILED, "%I%I", dwGroup, IpAddr, Error);
  416. }
  417. Trace2(MGM, "Joining MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
  418. PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
  419. return Error;
  420. }
  421. //------------------------------------------------------------------------------
  422. // _LeaveMulticastGroup
  423. //------------------------------------------------------------------------------
  424. DWORD
  425. LeaveMulticastGroup (
  426. SOCKET Sock,
  427. DWORD dwGroup,
  428. DWORD IfIndex,
  429. IPADDR IpAddr,
  430. IPADDR Source
  431. )
  432. {
  433. struct ip_mreq imOption;
  434. DWORD Error = NO_ERROR;
  435. DWORD dwRetval;
  436. if (Source==0) {
  437. imOption.imr_multiaddr.s_addr = dwGroup;
  438. imOption.imr_interface.s_addr = IpAddr;
  439. dwRetval = setsockopt(Sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
  440. (PBYTE)&imOption, sizeof(imOption));
  441. }
  442. else {
  443. struct ip_mreq_source imr;
  444. imr.imr_multiaddr.s_addr = dwGroup;
  445. imr.imr_sourceaddr.s_addr = Source;
  446. imr.imr_interface.s_addr = IpAddr;
  447. dwRetval = setsockopt(Sock, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
  448. (PCHAR)&imr, sizeof(imr));
  449. }
  450. if (dwRetval == SOCKET_ERROR) {
  451. Error = WSAGetLastError();
  452. Trace5(ERR,
  453. "error %d leaving multicast group(%d.%d.%d.%d) "
  454. "Source:%d.%d.%d.%d on interface (%d) %d.%d.%d.%d",
  455. Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
  456. IfIndex, PRINT_IPADDR(IpAddr));
  457. IgmpAssertOnError(FALSE);
  458. }
  459. Trace2(MGM, "Leaving MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
  460. PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
  461. return Error;
  462. }
  463. //------------------------------------------------------------------------------
  464. // _McastSetTtl
  465. // set the ttl value for multicast data. the default ttl for multicast is 1.
  466. //------------------------------------------------------------------------------
  467. DWORD
  468. McastSetTtl(
  469. SOCKET sock,
  470. UCHAR ttl
  471. )
  472. {
  473. INT dwTtl = ttl;
  474. DWORD Error=NO_ERROR;
  475. Error = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
  476. (char *)&dwTtl, sizeof(dwTtl));
  477. if (Error != 0) {
  478. Error = WSAGetLastError();
  479. Trace1(ERR, "error:%d: unable to set ttl value", Error);
  480. IgmpAssertOnError(FALSE);
  481. return Error;
  482. }
  483. return Error;
  484. }
  485. UCHAR
  486. GetMaxRespCode(
  487. PIF_TABLE_ENTRY pite,
  488. DWORD val
  489. )
  490. {
  491. if (IS_IF_VER1(pite))
  492. return 0;
  493. if (IS_IF_VER2(pite))
  494. return val>255 ? 0 : (UCHAR)val;
  495. //version 3
  496. if (val < 128)
  497. return (UCHAR)val;
  498. {
  499. DWORD n,mant, exp;
  500. n = val;
  501. exp = mant = 0;
  502. while (n) {
  503. exp++;
  504. n = n>>1;
  505. }
  506. exp=exp-2-3-3;
  507. mant = 15;
  508. if ( ((mant+16)<<(exp+3)) < val)
  509. exp++;
  510. mant = (val >> (exp+3)) - 15;
  511. IgmpAssert(mant<16 && exp <8); //deldel
  512. Trace4(KSL, "\n=======exp: LMQI:%d:%d exp:%d mant:%d\n",
  513. val, (mant+16)<<(exp+3), exp, mant); //deldel
  514. return (UCHAR)(0x80 + (exp<<4) + mant);
  515. }
  516. }
  517. UCHAR
  518. GetQqic (
  519. DWORD val
  520. )
  521. {
  522. val = val/1000;
  523. if ((val) > 31744)
  524. return 0;
  525. if (val<128)
  526. return (UCHAR)val;
  527. {
  528. DWORD n,mant, exp;
  529. n = val;
  530. exp = mant = 0;
  531. while (n) {
  532. exp++;
  533. n = n>>1;
  534. }
  535. exp=exp-2-3-3;
  536. mant = 15;
  537. if ( ((mant+16)<<(exp+3)) < val)
  538. exp++;
  539. mant = (val >> (exp+3)) - 15;
  540. IgmpAssert(mant<16 && exp <8); //deldel
  541. Trace4(KSL, "\n=======exp: QQic:%d:%d exp:%d mant:%d\n",
  542. val, (mant+16)<<(exp+3), exp, mant); //deldel
  543. return (UCHAR)(0x80 + (exp<<4) + mant);
  544. }
  545. }
  546. //------------------------------------------------------------------------------
  547. // xsum: copied from ipxmit.c
  548. //------------------------------------------------------------------------------
  549. USHORT
  550. xsum(PVOID Buffer, INT Size)
  551. {
  552. USHORT UNALIGNED *Buffer1 = (USHORT UNALIGNED *)Buffer; // Buffer expressed as shorts.
  553. ULONG csum = 0;
  554. while (Size > 1) {
  555. csum += *Buffer1++;
  556. Size -= sizeof(USHORT);
  557. }
  558. if (Size)
  559. csum += *(UCHAR *)Buffer1; // For odd buffers, add in last byte.
  560. csum = (csum >> 16) + (csum & 0xffff);
  561. csum += (csum >> 16);
  562. return (USHORT)csum;
  563. }