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.

1429 lines
37 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: work.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin August 31, 1995 Created
  8. //
  9. // Worker function implementation
  10. //============================================================================
  11. #include "pchbootp.h"
  12. #define STRSAFE_NO_DEPRECATE
  13. #include <strsafe.h>
  14. //----------------------------------------------------------------------------
  15. // Function: CallbackFunctionNetworkEvents
  16. //
  17. // This function runs in the context of the ntdll wait thread. Using
  18. // QueueBootpWorker ensures that the bootp dll is running
  19. //----------------------------------------------------------------------------
  20. VOID
  21. CallbackFunctionNetworkEvents(
  22. PVOID pvContext,
  23. BOOLEAN NotUsed
  24. ) {
  25. HANDLE WaitHandle;
  26. if (!ENTER_BOOTP_API()) { return; }
  27. //
  28. // set the handle to NULL, so that Unregister wont be called
  29. //
  30. WaitHandle = InterlockedExchangePointer(&ig.IG_InputEventHandle, NULL);
  31. if (WaitHandle) {
  32. UnregisterWaitEx( WaitHandle, NULL ) ;
  33. }
  34. QueueBootpWorker(WorkerFunctionNetworkEvents, pvContext);
  35. LEAVE_BOOTP_API();
  36. return;
  37. }
  38. //----------------------------------------------------------------------------
  39. // Function: WorkerFunctionNetworkEvents
  40. //
  41. // This function enumerates the input events on each interface and processes
  42. // any incoming input packets. Queued by CallbackFunctionNetworkEvents
  43. //----------------------------------------------------------------------------
  44. VOID
  45. WorkerFunctionNetworkEvents(
  46. PVOID pvContextNotused
  47. ) {
  48. DWORD i, dwErr;
  49. PIF_TABLE pTable;
  50. PIPBOOTP_IF_CONFIG pic;
  51. PIPBOOTP_IF_BINDING pib;
  52. PIPBOOTP_IP_ADDRESS paddr;
  53. PIF_TABLE_ENTRY pite;
  54. PLIST_ENTRY ple, phead;
  55. WSANETWORKEVENTS wsane;
  56. if (!ENTER_BOOTP_WORKER()) { return; }
  57. pTable = ig.IG_IfTable;
  58. ACQUIRE_READ_LOCK(&pTable->IT_RWL);
  59. //
  60. // go through the list of active interfaces
  61. // processing sockets which are read-ready
  62. //
  63. phead = &pTable->IT_ListByAddress;
  64. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  65. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  66. pic = pite->ITE_Config;
  67. pib = pite->ITE_Binding;
  68. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  69. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  70. if (pite->ITE_Sockets[i] == INVALID_SOCKET) { continue; }
  71. //
  72. // enumerate network events to see whether
  73. // any packets have arrived on this interface
  74. //
  75. dwErr = WSAEnumNetworkEvents(pite->ITE_Sockets[i], NULL, &wsane);
  76. if (dwErr != NO_ERROR) {
  77. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  78. TRACE3(
  79. RECEIVE, "error %d checking for input on interface %d (%s)",
  80. dwErr, pite->ITE_Index, lpszAddr
  81. );
  82. LOGWARN1(ENUM_NETWORK_EVENTS_FAILED, lpszAddr, dwErr);
  83. continue;
  84. }
  85. //
  86. // see if the input bit is set
  87. //
  88. if (!(wsane.lNetworkEvents & FD_READ)) { continue; }
  89. //
  90. // the input flag is set, now see if there was an error
  91. //
  92. if (wsane.iErrorCode[FD_READ_BIT] != NO_ERROR) {
  93. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  94. TRACE3(
  95. RECEIVE, "error %d in input record for interface %d (%s)",
  96. wsane.iErrorCode[FD_READ_BIT], pite->ITE_Index, lpszAddr
  97. );
  98. LOGWARN1(INPUT_RECORD_ERROR, lpszAddr, dwErr);
  99. continue;
  100. }
  101. //
  102. // there is no error, so process the socket
  103. //
  104. ProcessSocket(pite, i, pTable);
  105. }
  106. }
  107. RELEASE_READ_LOCK(&pTable->IT_RWL);
  108. //
  109. // register the InputEvent with the NtdllWait Thread again (only if the
  110. // dll is not stopping). I use this model of registering the event with
  111. // ntdll every time, to prevent the worker function from being called for
  112. // every packet received (when packets are received at the same time).
  113. //
  114. if (ig.IG_Status != IPBOOTP_STATUS_STOPPING) {
  115. if (! RegisterWaitForSingleObject(
  116. &ig.IG_InputEventHandle,
  117. ig.IG_InputEvent,
  118. CallbackFunctionNetworkEvents,
  119. NULL, //null context
  120. INFINITE, //no timeout
  121. (WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE)
  122. )) {
  123. dwErr = GetLastError();
  124. TRACE1(
  125. START, "error %d returned by RegisterWaitForSingleObjectEx",
  126. dwErr
  127. );
  128. LOGERR0(REGISTER_WAIT_FAILED, dwErr);
  129. }
  130. }
  131. LEAVE_BOOTP_WORKER();
  132. return;
  133. }
  134. //----------------------------------------------------------------------------
  135. // Function: ProcessSocket
  136. //
  137. // This function processes a packet on an interface, queueing
  138. // the packet for processing by a worker function after doing some
  139. // basic validation.
  140. //----------------------------------------------------------------------------
  141. DWORD
  142. ProcessSocket(
  143. PIF_TABLE_ENTRY pite,
  144. DWORD dwAddrIndex,
  145. PIF_TABLE pTable
  146. ) {
  147. BOOL bFreePacket;
  148. WORKERFUNCTION pwf;
  149. PINPUT_CONTEXT pwc;
  150. PIPBOOTP_IF_STATS pis;
  151. PIPBOOTP_IF_CONFIG pic;
  152. PIPBOOTP_IP_ADDRESS paddr;
  153. PIPBOOTP_PACKET pibp;
  154. PLIST_ENTRY ple;
  155. DWORD dwErr, dwInputSource;
  156. SOCKADDR_IN sinInputSource;
  157. PIPBOOTP_GLOBAL_CONFIG pigc;
  158. INT iInputLength, iAddrLength;
  159. PBYTE pInputPacket;
  160. pigc = ig.IG_Config;
  161. pis = &pite->ITE_Stats;
  162. paddr = IPBOOTP_IF_ADDRESS_TABLE(pite->ITE_Binding) + dwAddrIndex;
  163. //
  164. // the descriptor for this interface is set,
  165. // so allocate space for the packet
  166. //
  167. pwc = BOOTP_ALLOC(sizeof(INPUT_CONTEXT));
  168. if (pwc == NULL) {
  169. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  170. TRACE2(
  171. RECEIVE, "error %d allocating %d bytes for incoming packet",
  172. dwErr, sizeof(INPUT_CONTEXT)
  173. );
  174. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  175. return dwErr;
  176. }
  177. pInputPacket = pwc->IC_InputPacket;
  178. dwErr = NO_ERROR;
  179. bFreePacket = TRUE;
  180. do {
  181. CHAR szSource[20];
  182. //
  183. // receive the packet
  184. //
  185. iAddrLength = sizeof(SOCKADDR_IN);
  186. iInputLength = recvfrom(
  187. pite->ITE_Sockets[dwAddrIndex], pInputPacket,
  188. MAX_PACKET_SIZE, 0, (PSOCKADDR)&sinInputSource,
  189. &iAddrLength
  190. );
  191. if (iInputLength == 0 || iInputLength == SOCKET_ERROR) {
  192. LPSTR lpszAddr;
  193. dwErr = WSAGetLastError();
  194. lpszAddr = INET_NTOA(paddr->IA_Address);
  195. TRACE3(
  196. RECEIVE, "error %d receiving on interface %d (%s)",
  197. dwErr, pite->ITE_Index, lpszAddr
  198. );
  199. LOGERR1(RECVFROM_FAILED, lpszAddr, dwErr);
  200. InterlockedIncrement(&pis->IS_ReceiveFailures);
  201. break;
  202. }
  203. dwInputSource = sinInputSource.sin_addr.s_addr;
  204. //
  205. // filter out packets we sent ourselves
  206. //
  207. if (GetIfByAddress(pTable, dwInputSource, NULL)) {
  208. break;
  209. }
  210. {
  211. PCHAR pStr1, pStr2;
  212. pStr1 = INET_NTOA(dwInputSource);
  213. if (pStr1)
  214. lstrcpy(szSource, pStr1);
  215. pStr2 = INET_NTOA(paddr->IA_Address);
  216. if (pStr1 && pStr2) {
  217. TRACE4(
  218. RECEIVE, "received %d-byte packet from %s on interface %d (%s)",
  219. iInputLength, szSource, pite->ITE_Index,
  220. pStr2
  221. );
  222. }
  223. }
  224. //
  225. // cast packet as a BOOTP message
  226. //
  227. pibp = (PIPBOOTP_PACKET)pInputPacket;
  228. //
  229. // consistency check 1: length of packet must exceed the length
  230. // of the BOOTP header
  231. //
  232. if (iInputLength < sizeof(IPBOOTP_PACKET)) {
  233. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  234. TRACE3(
  235. RECEIVE,
  236. "minimum BOOTP data is %d bytes, dropping %d byte packet from %s",
  237. sizeof(IPBOOTP_PACKET), iInputLength, szSource
  238. );
  239. LOGWARN2(PACKET_TOO_SMALL, lpszAddr, szSource, 0);
  240. break;
  241. }
  242. //
  243. // consistency check 2: op field must be either BOOTP_REQUEST
  244. // or BOOTP_REPLY
  245. //
  246. if (pibp->IP_Operation != IPBOOTP_OPERATION_REQUEST &&
  247. pibp->IP_Operation != IPBOOTP_OPERATION_REPLY) {
  248. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  249. TRACE2(
  250. RECEIVE,
  251. "dropping packet from %s due to unknown operation field %d",
  252. szSource, pibp->IP_Operation
  253. );
  254. LOGWARN2(PACKET_OPCODE_INVALID, lpszAddr, szSource, 0);
  255. break;
  256. }
  257. //
  258. // update statistics on incoming packets
  259. //
  260. switch (pibp->IP_Operation) {
  261. case IPBOOTP_OPERATION_REQUEST:
  262. InterlockedIncrement(&pis->IS_RequestsReceived);
  263. break;
  264. case IPBOOTP_OPERATION_REPLY:
  265. InterlockedIncrement(&pis->IS_RepliesReceived);
  266. break;
  267. }
  268. //
  269. // finish initializing the work context
  270. //
  271. pwc->IC_InterfaceIndex = pite->ITE_Index;
  272. pwc->IC_AddrIndex = dwAddrIndex;
  273. pwc->IC_InputSource = sinInputSource;
  274. pwc->IC_InputLength = iInputLength;
  275. //
  276. // place the packet on the receive queue
  277. //
  278. ACQUIRE_READ_LOCK(&ig.IG_RWL);
  279. ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
  280. dwErr = EnqueueRecvEntry(
  281. ig.IG_RecvQueue, (DWORD)pibp->IP_Operation, (PBYTE)pwc
  282. );
  283. RELEASE_LIST_LOCK(ig.IG_RecvQueue);
  284. RELEASE_READ_LOCK(&ig.IG_RWL);
  285. if (dwErr != NO_ERROR) {
  286. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  287. TRACE4(
  288. RECEIVE, "error %d queueing packet from %s on interface %d (%s)",
  289. dwErr, szSource, pite->ITE_Index, lpszAddr
  290. );
  291. LOGERR2(QUEUE_PACKET_FAILED, lpszAddr, szSource, dwErr);
  292. break;
  293. }
  294. //
  295. // queue the function to handle the packet
  296. //
  297. dwErr = QueueBootpWorker(WorkerFunctionProcessInput, NULL);
  298. if (dwErr != NO_ERROR) {
  299. PLIST_ENTRY phead;
  300. TRACE2(
  301. RECEIVE, "error %d queueing packet from %s for processing",
  302. dwErr, szSource
  303. );
  304. LOGERR0(QUEUE_WORKER_FAILED, dwErr);
  305. ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
  306. phead = &ig.IG_RecvQueue->LL_Head;
  307. RemoveTailList(phead);
  308. ig.IG_RecvQueueSize -= sizeof(RECV_QUEUE_ENTRY);
  309. RELEASE_LIST_LOCK(ig.IG_RecvQueue);
  310. break;
  311. }
  312. //
  313. // all went well, so we let the input processor free the packet
  314. //
  315. bFreePacket = FALSE;
  316. } while(FALSE);
  317. if (bFreePacket) { BOOTP_FREE(pwc); }
  318. return dwErr;
  319. }
  320. //----------------------------------------------------------------------------
  321. // Function: WorkerFunctionProcessInput
  322. //
  323. // This function processes an incoming packet.
  324. //----------------------------------------------------------------------------
  325. VOID
  326. WorkerFunctionProcessInput(
  327. PVOID pContext
  328. ) {
  329. PINPUT_CONTEXT pwc;
  330. DWORD dwErr, dwCommand;
  331. if (!ENTER_BOOTP_WORKER()) { return; }
  332. TRACE0(ENTER, "entering WorkerFunctionProcessInput");
  333. do {
  334. ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
  335. dwErr = DequeueRecvEntry(ig.IG_RecvQueue, &dwCommand, (PBYTE *)&pwc);
  336. RELEASE_LIST_LOCK(ig.IG_RecvQueue);
  337. if (dwErr != NO_ERROR) {
  338. TRACE1(
  339. RECEIVE, "error %d dequeueing packet from receive queue", dwErr
  340. );
  341. break;
  342. }
  343. switch (dwCommand) {
  344. case IPBOOTP_OPERATION_REQUEST:
  345. ProcessRequest(pwc);
  346. break;
  347. case IPBOOTP_OPERATION_REPLY:
  348. ProcessReply(pwc);
  349. break;
  350. }
  351. } while(FALSE);
  352. TRACE0(LEAVE, "leaving WorkerFunctionProcessInput");
  353. LEAVE_BOOTP_WORKER();
  354. }
  355. //----------------------------------------------------------------------------
  356. // Function: ProcessRequest
  357. //
  358. // This function handles the processing of BOOT_REQUEST messages
  359. //----------------------------------------------------------------------------
  360. VOID
  361. ProcessRequest(
  362. PVOID pContext
  363. ) {
  364. INT iErr;
  365. PIF_TABLE pTable;
  366. PINPUT_CONTEXT pwc;
  367. SOCKADDR_IN sinsrv;
  368. PIPBOOTP_PACKET pibp;
  369. PIF_TABLE_ENTRY pite;
  370. PIPBOOTP_IF_STATS pis;
  371. PIPBOOTP_IF_CONFIG pic;
  372. PIPBOOTP_IP_ADDRESS paddr;
  373. PIPBOOTP_GLOBAL_CONFIG pigc;
  374. DWORD dwErr, dwIndex, dwDhcpInformServer;
  375. PDWORD pdwAddr, pdwEnd;
  376. PDHCP_PACKET pdp;
  377. TRACE0(ENTER, "entering ProcessRequest");
  378. pwc = (PINPUT_CONTEXT)pContext;
  379. pTable = ig.IG_IfTable;
  380. ACQUIRE_READ_LOCK(&pTable->IT_RWL);
  381. do { // error breakout loop
  382. //
  383. // find the interface on which the input arrived
  384. //
  385. dwIndex = pwc->IC_InterfaceIndex;
  386. pite = GetIfByIndex(pTable, dwIndex);
  387. if (pite == NULL) {
  388. TRACE1(
  389. REQUEST, "processing request: interface %d not found", dwIndex
  390. );
  391. break;
  392. }
  393. pis = &pite->ITE_Stats;
  394. pic = pite->ITE_Config;
  395. //
  396. // Check if interface still bound to an IP address
  397. //
  398. if (pite->ITE_Binding == NULL) {
  399. TRACE1(
  400. REQUEST, "processing request: interface %d not bound",
  401. dwIndex
  402. );
  403. break;
  404. }
  405. paddr = IPBOOTP_IF_ADDRESS_TABLE(pite->ITE_Binding) + pwc->IC_AddrIndex;
  406. //
  407. // if we are not configured to relay, do nothing
  408. //
  409. if (pic->IC_RelayMode == IPBOOTP_RELAY_DISABLED) { break; }
  410. pibp = (PIPBOOTP_PACKET)pwc->IC_InputPacket;
  411. //
  412. // check the hop-count field to see if it is over the max hop-count
  413. // configured for this interface
  414. //
  415. if (pibp->IP_HopCount > IPBOOTP_MAX_HOP_COUNT ||
  416. pibp->IP_HopCount > pic->IC_MaxHopCount) {
  417. //
  418. // discard and log
  419. //
  420. CHAR szHops[12], *lpszAddr = INET_NTOA(paddr->IA_Address);
  421. _ltoa(pibp->IP_HopCount, szHops, 10);
  422. TRACE4(
  423. REQUEST,
  424. "dropping REQUEST with hop-count %d: max hop-count is %d on interface %d (%s)",
  425. pibp->IP_HopCount, pic->IC_MaxHopCount, dwIndex, lpszAddr
  426. );
  427. LOGWARN2(HOP_COUNT_TOO_HIGH, lpszAddr, szHops, 0);
  428. InterlockedIncrement(&pis->IS_RequestsDiscarded);
  429. break;
  430. }
  431. //
  432. // check the seconds threshold to make sure it is up to the minimum
  433. //
  434. if (pibp->IP_SecondsSinceBoot < pic->IC_MinSecondsSinceBoot) {
  435. //
  436. // discard and log
  437. //
  438. CHAR szSecs[12], *lpszAddr = INET_NTOA(paddr->IA_Address);
  439. _ltoa(pibp->IP_SecondsSinceBoot, szSecs, 10);
  440. TRACE3(
  441. REQUEST,
  442. "dropping REQUEST with secs-since-boot %d on interface %d (%s)",
  443. pibp->IP_SecondsSinceBoot, dwIndex, lpszAddr
  444. );
  445. LOGINFO2(SECS_SINCE_BOOT_TOO_LOW, lpszAddr, szSecs, 0);
  446. InterlockedIncrement(&pis->IS_RequestsDiscarded);
  447. break;
  448. }
  449. //
  450. // increment the hop-count
  451. //
  452. ++pibp->IP_HopCount;
  453. //
  454. // fill in relay agent IP address if it is empty
  455. //
  456. if (pibp->IP_AgentAddress == 0) {
  457. pibp->IP_AgentAddress = paddr->IA_Address;
  458. }
  459. //
  460. // if a dhcp-inform server has been set,
  461. // and this packet is a dhcp inform packet,
  462. // we will forward it to the dhcp-inform server.
  463. //
  464. pdp = (PDHCP_PACKET)(pibp + 1);
  465. if (!(dwDhcpInformServer = ig.IG_DhcpInformServer) ||
  466. pwc->IC_InputLength <
  467. sizeof(IPBOOTP_PACKET) + sizeof(DHCP_PACKET) + 1 ||
  468. *(DWORD UNALIGNED *)pdp->Cookie != DHCP_MAGIC_COOKIE ||
  469. pdp->Tag != DHCP_TAG_MESSAGE_TYPE ||
  470. pdp->Length != 1 ||
  471. pdp->Option[0] != DHCP_MESSAGE_INFORM
  472. ) {
  473. dwDhcpInformServer = 0;
  474. }
  475. //
  476. // relay the request to all configured BOOTP servers
  477. //
  478. ACQUIRE_READ_LOCK(&ig.IG_RWL);
  479. pigc = ig.IG_Config;
  480. if (dwDhcpInformServer) {
  481. pdwAddr = &dwDhcpInformServer;
  482. pdwEnd = pdwAddr + 1;
  483. }
  484. else {
  485. pdwAddr = (PDWORD)((PBYTE)pigc + sizeof(IPBOOTP_GLOBAL_CONFIG));
  486. pdwEnd = pdwAddr + pigc->GC_ServerCount;
  487. }
  488. for ( ; pdwAddr < pdwEnd; pdwAddr++) {
  489. sinsrv.sin_family = AF_INET;
  490. sinsrv.sin_port = htons(IPBOOTP_SERVER_PORT);
  491. sinsrv.sin_addr.s_addr = *pdwAddr;
  492. iErr = sendto(
  493. pite->ITE_Sockets[pwc->IC_AddrIndex],
  494. pwc->IC_InputPacket, pwc->IC_InputLength, 0,
  495. (PSOCKADDR)&sinsrv, sizeof(SOCKADDR_IN)
  496. );
  497. if (iErr == SOCKET_ERROR || iErr < (INT)pwc->IC_InputLength) {
  498. CHAR szSrv[20], *lpszAddr;
  499. dwErr = WSAGetLastError();
  500. if ((lpszAddr = INET_NTOA(*pdwAddr)) != NULL) {
  501. lstrcpy(szSrv, lpszAddr);
  502. lpszAddr = INET_NTOA(paddr->IA_Address);
  503. if (lpszAddr != NULL) {
  504. TRACE4(
  505. REQUEST,
  506. "error %d relaying REQUEST to server %s on interface %d (%s)",
  507. dwErr, szSrv, dwIndex, lpszAddr
  508. );
  509. LOGERR2(RELAY_REQUEST_FAILED, lpszAddr, szSrv, dwErr);
  510. }
  511. }
  512. InterlockedIncrement(&pis->IS_SendFailures);
  513. }
  514. }
  515. RELEASE_READ_LOCK(&ig.IG_RWL);
  516. } while(FALSE);
  517. RELEASE_READ_LOCK(&pTable->IT_RWL);
  518. BOOTP_FREE(pwc);
  519. TRACE0(LEAVE, "leaving ProcessRequest");
  520. return;
  521. }
  522. //----------------------------------------------------------------------------
  523. // Function: ProcessReply
  524. //
  525. // This function handles the relaying of BOOT_REPLY packets
  526. //----------------------------------------------------------------------------
  527. VOID
  528. ProcessReply(
  529. PVOID pContext
  530. ) {
  531. INT iErr;
  532. PIF_TABLE pTable;
  533. BOOL bArpUpdated;
  534. SOCKADDR_IN sincli;
  535. PINPUT_CONTEXT pwc;
  536. PIPBOOTP_PACKET pibp;
  537. PIPBOOTP_IP_ADDRESS paddrin, paddrout;
  538. PIPBOOTP_IF_STATS pisin, pisout;
  539. PIF_TABLE_ENTRY pitein, piteout;
  540. DWORD dwErr, dwIndex, dwAddress, dwAddrIndexOut;
  541. TRACE0(ENTER, "entering ProcessReply");
  542. pwc = (PINPUT_CONTEXT)pContext;
  543. pTable = ig.IG_IfTable;
  544. ACQUIRE_READ_LOCK(&pTable->IT_RWL);
  545. do { // error breakout loop
  546. //
  547. // get the interface on which the packet was received
  548. //
  549. dwIndex = pwc->IC_InterfaceIndex;
  550. pitein = GetIfByIndex(pTable, dwIndex);
  551. if (pitein == NULL) {
  552. TRACE1(REPLY, "processing REPLY: interface %d not found", dwIndex);
  553. break;
  554. }
  555. if (pitein->ITE_Binding == NULL) {
  556. TRACE1(REPLY, "processing REPLY: interface %d not bound", dwIndex);
  557. break;
  558. }
  559. paddrin = IPBOOTP_IF_ADDRESS_TABLE(pitein->ITE_Binding) +
  560. pwc->IC_AddrIndex;
  561. //
  562. // if we are not configured t relay on this interface, do nothing
  563. //
  564. if (pitein->ITE_Config->IC_RelayMode == IPBOOTP_RELAY_DISABLED) {
  565. TRACE2(
  566. REPLY,
  567. "dropping REPLY: relaying on interface %d (%s) is disabled",
  568. pitein->ITE_Index, INET_NTOA(paddrin->IA_Address)
  569. );
  570. break;
  571. }
  572. pisin = &pitein->ITE_Stats;
  573. //
  574. // place a template over the packet, and retrieve
  575. // the AgentAddress field; this contains the address
  576. // of the relay agent responsible for relaying this REPLY
  577. //
  578. pibp = (PIPBOOTP_PACKET)pwc->IC_InputPacket;
  579. dwAddress = pibp->IP_AgentAddress;
  580. //
  581. // see if the address in the reply matches any local interface
  582. //
  583. piteout = GetIfByAddress(pTable, dwAddress, &dwAddrIndexOut);
  584. if (piteout == NULL) {
  585. CHAR szAddress[20];
  586. PCHAR pStr1, pStr2;
  587. pStr1 = INET_NTOA(dwAddress);
  588. if (pStr1)
  589. lstrcpy(szAddress, pStr1);
  590. pStr2 = INET_NTOA(paddrin->IA_Address);
  591. if (pStr1 && pStr2) {
  592. TRACE3(
  593. REPLY,
  594. "dropping REPLY packet on interface %d (%s); no interfaces have address %s",
  595. pitein->ITE_Index, pStr2, szAddress
  596. );
  597. }
  598. InterlockedIncrement(&pisin->IS_RepliesDiscarded);
  599. break;
  600. }
  601. if (piteout->ITE_Binding == NULL) {
  602. TRACE1(REPLY, "processing REPLY: outgoing interface %d is not bound", dwIndex);
  603. break;
  604. }
  605. paddrout = IPBOOTP_IF_ADDRESS_TABLE(piteout->ITE_Binding) +
  606. dwAddrIndexOut;
  607. //
  608. // only relay if relay is enabled on the outgoing interface
  609. //
  610. if (piteout->ITE_Config->IC_RelayMode == IPBOOTP_RELAY_DISABLED) {
  611. TRACE2(
  612. REPLY,
  613. "dropping REPLY: relaying on interface %d (%s) is disabled",
  614. piteout->ITE_Index, INET_NTOA(paddrout->IA_Address)
  615. );
  616. break;
  617. }
  618. pisout = &piteout->ITE_Stats;
  619. //
  620. // the message must be relayed on the interface whose address
  621. // was specifed in the packet;
  622. //
  623. //
  624. // if the broadcast bit is not set and the clients IP address
  625. // is in the packet, add an entry to the ARP cache for the client
  626. // and then relay the packet by unicast
  627. //
  628. sincli.sin_family = AF_INET;
  629. sincli.sin_port = htons(IPBOOTP_CLIENT_PORT);
  630. if ((pibp->IP_Flags & htons(IPBOOTP_FLAG_BROADCAST)) != 0 ||
  631. pibp->IP_OfferedAddress == 0) {
  632. //
  633. // the broadcast bit is set of the offered address is 0,
  634. // which is not an address we can add to the ARP cache;
  635. // in this case, send by broadcast
  636. //
  637. bArpUpdated = FALSE;
  638. sincli.sin_addr.s_addr = INADDR_BROADCAST;
  639. }
  640. else {
  641. //
  642. // attempt to seed the ARP cache with the address
  643. // offered to the client in the packet we are about
  644. // to send to the client.
  645. //
  646. dwErr = UpdateArpCache(
  647. piteout->ITE_Index, pibp->IP_OfferedAddress,
  648. (PBYTE)pibp->IP_MacAddr, pibp->IP_MacAddrLength,
  649. TRUE, ig.IG_FunctionTable
  650. );
  651. if (dwErr == NO_ERROR) {
  652. bArpUpdated = TRUE;
  653. sincli.sin_addr.s_addr = pibp->IP_OfferedAddress;
  654. }
  655. else {
  656. //
  657. // okay, that didn't work,
  658. // so fall back on broadcasting the packet
  659. //
  660. TRACE3(
  661. REPLY,
  662. "error %d adding entry to ARP cache on interface %d (%s)",
  663. dwErr, piteout->ITE_Index, INET_NTOA(paddrout->IA_Address)
  664. );
  665. bArpUpdated = FALSE;
  666. sincli.sin_addr.s_addr = INADDR_BROADCAST;
  667. InterlockedIncrement(&pisout->IS_ArpUpdateFailures);
  668. }
  669. }
  670. //
  671. // relay the packet
  672. //
  673. iErr = sendto(
  674. piteout->ITE_Sockets[dwAddrIndexOut], pwc->IC_InputPacket,
  675. pwc->IC_InputLength, 0,
  676. (PSOCKADDR)&sincli, sizeof(SOCKADDR_IN)
  677. );
  678. if (iErr == SOCKET_ERROR || iErr < (INT)pwc->IC_InputLength) {
  679. INT i;
  680. BYTE *pb;
  681. CHAR szCli[64], *psz, *lpszAddr, szDigits[] = "0123456789ABCDEF";
  682. dwErr = WSAGetLastError();
  683. lpszAddr = INET_NTOA(paddrout->IA_Address);
  684. //
  685. // format the client's hardware address
  686. //
  687. for (i = 0, psz = szCli, pb = pibp->IP_MacAddr;
  688. i < 16 && i < pibp->IP_MacAddrLength;
  689. i++, pb++) {
  690. *psz++ = szDigits[*pb / 16];
  691. *psz++ = szDigits[*pb % 16];
  692. *psz++ = ':';
  693. }
  694. (psz == szCli) ? (*psz = '\0') : (*(psz - 1) = '\0');
  695. TRACE4(
  696. REPLY,
  697. "error %d relaying REPLY to client %s on interface %d (%s)",
  698. dwErr, szCli, dwIndex, lpszAddr
  699. );
  700. LOGERR2(RELAY_REPLY_FAILED, lpszAddr, szCli, dwErr);
  701. InterlockedIncrement(&pisout->IS_SendFailures);
  702. }
  703. //
  704. // remove the ARP entry if one was added
  705. //
  706. if (bArpUpdated) {
  707. dwErr = UpdateArpCache(
  708. piteout->ITE_Index, pibp->IP_OfferedAddress,
  709. (PBYTE)pibp->IP_MacAddr, pibp->IP_MacAddrLength,
  710. FALSE, ig.IG_FunctionTable
  711. );
  712. if (dwErr != NO_ERROR) {
  713. InterlockedIncrement(&pisout->IS_ArpUpdateFailures);
  714. }
  715. }
  716. } while(FALSE);
  717. RELEASE_READ_LOCK(&pTable->IT_RWL);
  718. BOOTP_FREE(pwc);
  719. TRACE0(LEAVE, "leaving ProcessReply");
  720. return;
  721. }
  722. #define ClearScreen(h) { \
  723. DWORD _dwin,_dwout; \
  724. COORD _c = {0, 0}; \
  725. CONSOLE_SCREEN_BUFFER_INFO _csbi; \
  726. GetConsoleScreenBufferInfo(h,&_csbi); \
  727. _dwin = _csbi.dwSize.X * _csbi.dwSize.Y; \
  728. FillConsoleOutputCharacter(h,' ',_dwin,_c,&_dwout); \
  729. }
  730. VOID
  731. PrintGlobalConfig(
  732. HANDLE hConsole,
  733. PCOORD pc,
  734. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  735. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  736. );
  737. VOID
  738. PrintIfConfig(
  739. HANDLE hConsole,
  740. PCOORD pc,
  741. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  742. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  743. );
  744. VOID
  745. PrintIfBinding(
  746. HANDLE hConsole,
  747. PCOORD pc,
  748. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  749. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  750. );
  751. VOID
  752. PrintIfStats(
  753. HANDLE hConsole,
  754. PCOORD pc,
  755. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  756. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  757. );
  758. #if DBG
  759. VOID
  760. CallbackFunctionMibDisplay(
  761. PVOID pContext,
  762. BOOLEAN NotUsed
  763. ) {
  764. // enter/leaveBootpWorker not required as timer queue is persistent
  765. QueueBootpWorker(WorkerFunctionMibDisplay, pContext);
  766. return;
  767. }
  768. VOID
  769. WorkerFunctionMibDisplay(
  770. PVOID pContext
  771. ) {
  772. COORD c;
  773. INT iErr;
  774. FD_SET fdsRead;
  775. HANDLE hConsole;
  776. TIMEVAL tvTimeout;
  777. DWORD dwErr, dwTraceID;
  778. DWORD dwExactSize, dwInSize, dwOutSize;
  779. IPBOOTP_MIB_GET_INPUT_DATA imgid;
  780. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
  781. if (!ENTER_BOOTP_WORKER()) { return; }
  782. TraceGetConsole(ig.IG_MibTraceID, &hConsole);
  783. if (hConsole == NULL) {
  784. LEAVE_BOOTP_WORKER();
  785. return;
  786. }
  787. ClearScreen(hConsole);
  788. c.X = c.Y = 0;
  789. dwInSize = sizeof(imgid);
  790. imgid.IMGID_TypeID = IPBOOTP_GLOBAL_CONFIG_ID;
  791. dwOutSize = 0;
  792. pimgod = NULL;
  793. dwErr = MibGetFirst(dwInSize, &imgid, &dwOutSize, pimgod);
  794. if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
  795. pimgod = BOOTP_ALLOC(dwOutSize);
  796. if (pimgod) {
  797. dwErr = MibGetFirst(dwInSize, &imgid, &dwOutSize, pimgod);
  798. }
  799. }
  800. while (dwErr == NO_ERROR) {
  801. switch(pimgod->IMGOD_TypeID) {
  802. case IPBOOTP_GLOBAL_CONFIG_ID:
  803. PrintGlobalConfig(hConsole, &c, &imgid, pimgod);
  804. break;
  805. case IPBOOTP_IF_CONFIG_ID:
  806. PrintIfConfig(hConsole, &c, &imgid, pimgod);
  807. break;
  808. case IPBOOTP_IF_BINDING_ID:
  809. PrintIfBinding(hConsole, &c, &imgid, pimgod);
  810. break;
  811. case IPBOOTP_IF_STATS_ID:
  812. PrintIfStats(hConsole, &c, &imgid, pimgod);
  813. break;
  814. default:
  815. break;
  816. }
  817. //
  818. // move to next line
  819. //
  820. ++c.Y;
  821. dwOutSize = 0;
  822. if (pimgod) { BOOTP_FREE(pimgod); pimgod = NULL; }
  823. dwErr = MibGetNext(dwInSize, &imgid, &dwOutSize, pimgod);
  824. if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
  825. pimgod = BOOTP_ALLOC(dwOutSize);
  826. if (pimgod) {
  827. dwErr = MibGetNext(dwInSize, &imgid, &dwOutSize, pimgod);
  828. }
  829. }
  830. }
  831. if (pimgod != NULL) { BOOTP_FREE(pimgod); }
  832. LEAVE_BOOTP_WORKER();
  833. return;
  834. }
  835. #endif //if DBG
  836. #define WriteLine(h,c,fmt,arg) { \
  837. DWORD _dw; \
  838. CHAR _sz[200]; \
  839. _dw = StringCchPrintf(_sz, 200, fmt, arg); \
  840. if ( SUCCEEDED(_dw) ) { \
  841. WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \
  842. ++(c).Y; \
  843. } \
  844. }
  845. VOID
  846. PrintGlobalConfig(
  847. HANDLE hConsole,
  848. PCOORD pc,
  849. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  850. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  851. ) {
  852. PDWORD pdwsrv, pdwsrvend;
  853. PIPBOOTP_GLOBAL_CONFIG pgc;
  854. pgc = (PIPBOOTP_GLOBAL_CONFIG)pimgod->IMGOD_Buffer;
  855. WriteLine(
  856. hConsole,
  857. *pc,
  858. "Logging Level: %d",
  859. pgc->GC_LoggingLevel
  860. );
  861. WriteLine(
  862. hConsole,
  863. *pc,
  864. "Max Receive Queue Size: %d",
  865. pgc->GC_MaxRecvQueueSize
  866. );
  867. WriteLine(
  868. hConsole,
  869. *pc,
  870. "BOOTP Server Count: %d",
  871. pgc->GC_ServerCount
  872. );
  873. pdwsrv = (PDWORD)(pgc + 1);
  874. pdwsrvend = pdwsrv + pgc->GC_ServerCount;
  875. for ( ; pdwsrv < pdwsrvend; pdwsrv++) {
  876. WriteLine(
  877. hConsole,
  878. *pc,
  879. "BOOTP Server: %s",
  880. INET_NTOA(*pdwsrv)
  881. );
  882. }
  883. pimgid->IMGID_TypeID = IPBOOTP_GLOBAL_CONFIG_ID;
  884. }
  885. VOID
  886. PrintIfConfig(
  887. HANDLE hConsole,
  888. PCOORD pc,
  889. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  890. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  891. ) {
  892. CHAR szMode[20];
  893. PIPBOOTP_IF_CONFIG pic;
  894. pic = (PIPBOOTP_IF_CONFIG)pimgod->IMGOD_Buffer;
  895. switch (pic->IC_RelayMode) {
  896. case IPBOOTP_RELAY_ENABLED:
  897. strcpy(szMode, "enabled"); break;
  898. case IPBOOTP_RELAY_DISABLED:
  899. strcpy(szMode, "disabled"); break;
  900. default:
  901. break;
  902. }
  903. WriteLine(
  904. hConsole,
  905. *pc,
  906. "Interface Index: %d",
  907. pimgod->IMGOD_IfIndex
  908. );
  909. WriteLine(
  910. hConsole,
  911. *pc,
  912. "Relay Mode: %s",
  913. szMode
  914. );
  915. WriteLine(
  916. hConsole,
  917. *pc,
  918. "Max Hop Count: %d",
  919. pic->IC_MaxHopCount
  920. );
  921. WriteLine(
  922. hConsole,
  923. *pc,
  924. "Min Seconds Since Boot: %d",
  925. pic->IC_MinSecondsSinceBoot
  926. );
  927. pimgid->IMGID_TypeID = IPBOOTP_IF_CONFIG_ID;
  928. pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
  929. }
  930. VOID
  931. PrintIfBinding(
  932. HANDLE hConsole,
  933. PCOORD pc,
  934. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  935. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  936. ) {
  937. DWORD i;
  938. CHAR szAddr[64];
  939. PIPBOOTP_IF_BINDING pib;
  940. PIPBOOTP_IP_ADDRESS paddr;
  941. pib = (PIPBOOTP_IF_BINDING)pimgod->IMGOD_Buffer;
  942. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  943. WriteLine(
  944. hConsole, *pc, "Interface Index: %d",
  945. pimgod->IMGOD_IfIndex
  946. );
  947. WriteLine(
  948. hConsole, *pc, "Address Count: %d",
  949. pib->IB_AddrCount
  950. );
  951. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  952. LPSTR szTemp;
  953. szTemp = INET_NTOA(paddr->IA_Address);
  954. if (szTemp != NULL) {
  955. lstrcpy(szAddr, szTemp);
  956. lstrcat(szAddr, " - ");
  957. szTemp = INET_NTOA(paddr->IA_Netmask);
  958. if ( szTemp != NULL ) { lstrcat(szAddr, szTemp); }
  959. WriteLine(
  960. hConsole, *pc, "Address Entry: %s",
  961. szAddr
  962. );
  963. }
  964. }
  965. pimgid->IMGID_TypeID = IPBOOTP_IF_BINDING_ID;
  966. pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
  967. }
  968. VOID
  969. PrintIfStats(
  970. HANDLE hConsole,
  971. PCOORD pc,
  972. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  973. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
  974. ) {
  975. PIPBOOTP_IF_STATS pis;
  976. pis = (PIPBOOTP_IF_STATS)pimgod->IMGOD_Buffer;
  977. WriteLine(
  978. hConsole,
  979. *pc,
  980. "Interface Index: %d",
  981. pimgod->IMGOD_IfIndex
  982. );
  983. WriteLine(
  984. hConsole,
  985. *pc,
  986. "Send Failures: %d",
  987. pis->IS_SendFailures
  988. );
  989. WriteLine(
  990. hConsole,
  991. *pc,
  992. "Receive Failures: %d",
  993. pis->IS_ReceiveFailures
  994. );
  995. WriteLine(
  996. hConsole,
  997. *pc,
  998. "ARP Cache Update Failures: %d",
  999. pis->IS_ArpUpdateFailures
  1000. );
  1001. WriteLine(
  1002. hConsole,
  1003. *pc,
  1004. "Requests Received: %d",
  1005. pis->IS_RequestsReceived
  1006. );
  1007. WriteLine(
  1008. hConsole,
  1009. *pc,
  1010. "Requests Discarded: %d",
  1011. pis->IS_RequestsDiscarded
  1012. );
  1013. WriteLine(
  1014. hConsole,
  1015. *pc,
  1016. "Replies Received: %d",
  1017. pis->IS_RepliesReceived
  1018. );
  1019. WriteLine(
  1020. hConsole,
  1021. *pc,
  1022. "Replies Discarded: %d",
  1023. pis->IS_RepliesDiscarded
  1024. );
  1025. pimgid->IMGID_TypeID = IPBOOTP_IF_STATS_ID;
  1026. pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
  1027. }
  1028. char *
  1029. myinet_ntoa(
  1030. struct in_addr in
  1031. ) {
  1032. char *rv;
  1033. rv = inet_ntoa(in);
  1034. return rv ? rv : UNKNOWN_ADDRESS_STR;
  1035. }