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.

1792 lines
46 KiB

  1. /*******************************************************************/
  2. /* Copyright(c) 1993 Microsoft Corporation */
  3. /*******************************************************************/
  4. //***
  5. //
  6. // Filename: ipxcp.c
  7. //
  8. // Description: implements the IPX network layer configuration
  9. //
  10. //
  11. // Author: Stefan Solomon (stefans) November 24, 1993.
  12. //
  13. // Revision History:
  14. //
  15. //***
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. // keep track is we already have an active dialout port as a client
  19. DWORD WorkstationDialoutActive = 0;
  20. // Keep track of the number of clients currently connected
  21. DWORD dwClientCount = 0;
  22. // Used to assign remote wan workstations node numbers
  23. extern DWORD LastNodeAssigned;
  24. extern BOOL bAssignSpecificNode;
  25. VOID (*PPPCompletionRoutine)(HCONN hPortOrBundle,
  26. DWORD Protocol,
  27. PPP_CONFIG * pSendConfig,
  28. DWORD dwError);
  29. HANDLE PPPThreadHandle = INVALID_HANDLE_VALUE;
  30. // Handle to queue that holds configuration changes that need to
  31. // be made when the client count goes to zero next.
  32. HANDLE hConfigQueue = NULL;
  33. // Function obtained from the router manager to update global
  34. // config
  35. extern DWORD (WINAPI *RmUpdateIpxcpConfig)(PIPXCP_ROUTER_CONFIG_PARAMS pParams);
  36. HANDLE g_hRouterLog = NULL;
  37. DWORD
  38. WanNetReconfigure();
  39. DWORD
  40. IpxCpBegin(OUT VOID **ppWorkBuf,
  41. IN VOID *pInfo);
  42. DWORD
  43. IpxCpEnd(IN VOID *pWorkBuffer);
  44. DWORD
  45. IpxCpReset(IN VOID *pWorkBuffer);
  46. DWORD
  47. IpxCpThisLayerUp(IN VOID *pWorkBuffer);
  48. DWORD
  49. IpxCpThisLayerDown(IN VOID *pWorkBuffer);
  50. DWORD
  51. IpxCpMakeConfigRequest(IN VOID *pWorkBuffer,
  52. OUT PPP_CONFIG *pRequestBufffer,
  53. IN DWORD cbRequestBuffer);
  54. DWORD
  55. IpxCpMakeConfigResult(IN VOID *pWorkBuffer,
  56. IN PPP_CONFIG *pReceiveBuffer,
  57. OUT PPP_CONFIG *pResultBuffer,
  58. IN DWORD cbResultBuffer,
  59. IN BOOL fRejectNaks);
  60. DWORD
  61. IpxCpConfigNakReceived(IN VOID *pWorkBuffer,
  62. IN PPP_CONFIG *pReceiveBuffer);
  63. DWORD
  64. IpxCpConfigAckReceived(IN VOID *pWorkBuffer,
  65. IN PPP_CONFIG *pReceiveBuffer);
  66. DWORD
  67. IpxCpConfigRejReceived(IN VOID *pWorkBuffer,
  68. IN PPP_CONFIG *pReceiveBuffer);
  69. DWORD
  70. IpxCpGetNegotiatedInfo(IN VOID *pWorkBuffer,
  71. OUT VOID * pIpxCpResult );
  72. DWORD
  73. IpxCpProjectionNotification(IN VOID *pWorkBuf,
  74. IN VOID *pProjectionResult);
  75. #define ERROR_INVALID_OPTION 1
  76. #define ERROR_INVALID_OPTLEN 2
  77. DWORD
  78. ValidOption(UCHAR option,
  79. UCHAR optlen);
  80. BOOL
  81. DesiredOption(UCHAR option, USHORT *indexp);
  82. USHORT
  83. DesiredConfigReqLength();
  84. DWORD
  85. IpxCpUpdateGlobalConfig( VOID );
  86. DWORD
  87. IpxcpUpdateQueuedGlobalConfig();
  88. // Update Flags
  89. #define FLAG_UPDATE_WANNET 0x1
  90. #define FLAG_UPDATE_ROUTER 0x2
  91. typedef BOOL (*OPTION_HANDLER)(PUCHAR optptr,
  92. PIPXCP_CONTEXT contextp,
  93. PUCHAR resptr,
  94. OPT_ACTION Action);
  95. static OPTION_HANDLER OptionHandler[] =
  96. {
  97. NULL,
  98. NetworkNumberHandler,
  99. NodeNumberHandler,
  100. CompressionProtocolHandler,
  101. RoutingProtocolHandler,
  102. NULL, // RouterName - not a DESIRED parammeter
  103. ConfigurationCompleteHandler
  104. };
  105. UCHAR nullnet[] = { 0x00, 0x00, 0x00, 0x00 };
  106. UCHAR nullnode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  107. USHORT MaxDesiredParameters = MAX_DESIRED_PARAMETERS;
  108. CRITICAL_SECTION DbaseCritSec;
  109. //*** Declarations and defs for the options to be negotiated with this
  110. // version of IPXCP
  111. UCHAR DesiredParameter[MAX_DESIRED_PARAMETERS] = {
  112. IPX_NETWORK_NUMBER,
  113. IPX_NODE_NUMBER,
  114. IPX_COMPRESSION_PROTOCOL
  115. };
  116. USHORT DesiredParameterLength[MAX_DESIRED_PARAMETERS] = {
  117. 6, // IPX_NETWORK_NUMBER,
  118. 8, // IPX_NODE_NUMBER,
  119. 4 // IPX_COMPRESSION_PROTOCOL
  120. };
  121. DWORD
  122. IpxCpInit(BOOL fInitialize)
  123. {
  124. static DWORD dwRefCount = 0;
  125. if (fInitialize)
  126. {
  127. if (0 == dwRefCount)
  128. {
  129. //
  130. // Read the registry parameters and set IpxCp configuration
  131. //
  132. InitializeCriticalSection(&DbaseCritSec);
  133. g_hRouterLog = RouterLogRegisterW(L"IPXCP");
  134. StartTracing();
  135. GetIpxCpParameters(&GlobalConfig);
  136. SS_DBGINITIALIZE;
  137. InitializeRouterManagerIf();
  138. InitializeNodeHT();
  139. InitializeConnHT();
  140. #if (WINVER < 0x0501)
  141. LoadIpxWan();
  142. #endif
  143. CQCreate (&hConfigQueue);
  144. }
  145. dwRefCount++;
  146. }
  147. else
  148. {
  149. dwRefCount--;
  150. if (0 == dwRefCount)
  151. {
  152. //
  153. // Release the global list of routes
  154. //
  155. CQCleanup (hConfigQueue);
  156. UnloadIpxWan ();
  157. StopTracing();
  158. g_hRouterLog = NULL;
  159. DeleteCriticalSection(&DbaseCritSec);
  160. }
  161. }
  162. return(NO_ERROR);
  163. }
  164. DWORD
  165. IpxCpGetInfo(
  166. IN DWORD dwProtocolId,
  167. OUT PPPCP_INFO *pCpInfo)
  168. {
  169. if (dwProtocolId != PPP_IPXCP_PROTOCOL)
  170. return(ERROR_INVALID_PARAMETER);
  171. ZeroMemory(pCpInfo, sizeof(PPPCP_INFO));
  172. pCpInfo->Protocol = PPP_IPXCP_PROTOCOL;
  173. lstrcpy(pCpInfo->SzProtocolName, "IPXCP");
  174. pCpInfo->Recognize = CODE_REJ + 1;
  175. pCpInfo->RasCpInit = IpxCpInit;
  176. pCpInfo->RasCpBegin = IpxCpBegin;
  177. pCpInfo->RasCpEnd = IpxCpEnd;
  178. pCpInfo->RasCpReset = IpxCpReset;
  179. pCpInfo->RasCpThisLayerUp = IpxCpThisLayerUp;
  180. pCpInfo->RasCpThisLayerDown = IpxCpThisLayerDown;
  181. pCpInfo->RasCpMakeConfigRequest = IpxCpMakeConfigRequest;
  182. pCpInfo->RasCpMakeConfigResult = IpxCpMakeConfigResult;
  183. pCpInfo->RasCpConfigAckReceived = IpxCpConfigAckReceived;
  184. pCpInfo->RasCpConfigNakReceived = IpxCpConfigNakReceived;
  185. pCpInfo->RasCpConfigRejReceived = IpxCpConfigRejReceived;
  186. pCpInfo->RasCpGetNegotiatedInfo = IpxCpGetNegotiatedInfo;
  187. pCpInfo->RasCpProjectionNotification = IpxCpProjectionNotification;
  188. pCpInfo->RasCpChangeNotification = IpxCpUpdateGlobalConfig;
  189. return(NO_ERROR);
  190. }
  191. //***
  192. //
  193. // Function: IpxCpBegin
  194. //
  195. // Descr: Called when a line is connected.
  196. //
  197. //***
  198. DWORD
  199. IpxCpBegin(OUT VOID **ppWorkBuf,
  200. IN VOID *pInfo)
  201. {
  202. PIPXCP_CONTEXT contextp;
  203. PPPPCP_INIT initp;
  204. DWORD err;
  205. DWORD tickcount;
  206. int i;
  207. ULONG InterfaceType;
  208. ULONG ConnectionId;
  209. initp = (PPPPCP_INIT)pInfo;
  210. TraceIpx(PPPIF_TRACE, "IpxCpBegin: Entered for if # %d\n", initp->hInterface);
  211. // Get the completion routine and the thread handle
  212. if(PPPThreadHandle == INVALID_HANDLE_VALUE) {
  213. // not initialized
  214. if (!DuplicateHandle(
  215. GetCurrentProcess(),
  216. GetCurrentThread(),
  217. GetCurrentProcess(),
  218. &PPPThreadHandle,
  219. 0,
  220. FALSE,
  221. DUPLICATE_SAME_ACCESS )) {
  222. return GetLastError();
  223. }
  224. PPPCompletionRoutine = initp->CompletionRoutine;
  225. }
  226. //
  227. // Get the Connection Id (Bundle id)
  228. //
  229. ConnectionId = HandleToUlong(initp->hConnection);
  230. //
  231. // Determine the connection type
  232. //
  233. if((InterfaceType = GetInterfaceType(initp)) == IF_TYPE_OTHER) {
  234. return ERROR_CAN_NOT_COMPLETE;
  235. }
  236. if((InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) ||
  237. (InterfaceType == IF_TYPE_STANDALONE_WORKSTATION_DIALOUT)) {
  238. // If we are configured to allow only one dialout net and if we are
  239. // already dialed out once, we disable further dialouts.
  240. if(GlobalConfig.SingleClientDialout && IsWorkstationDialoutActive()) {
  241. return ERROR_IPXCP_DIALOUT_ALREADY_ACTIVE;
  242. }
  243. }
  244. if(initp->fServer &&
  245. (!IsRouterStarted())) {
  246. // we cannot accept dialin on machines without the router started
  247. return ERROR_CAN_NOT_COMPLETE;
  248. }
  249. // allocate a context structure to be used as work buffer for this connection
  250. if((contextp = (PIPXCP_CONTEXT)GlobalAlloc(GPTR, sizeof(IPXCP_CONTEXT))) == NULL) {
  251. *ppWorkBuf = NULL;
  252. return (ERROR_NOT_ENOUGH_MEMORY);
  253. }
  254. *ppWorkBuf = (VOID *)contextp;
  255. // allocate a route for this connection to the IPX stack
  256. if(err = RmAllocateRoute(HandleToUlong(initp->hPort))) {
  257. // cannot allocate route
  258. *ppWorkBuf = NULL;
  259. GlobalFree(contextp);
  260. return err;
  261. }
  262. //
  263. // Set up common context part
  264. //
  265. // hInterface is always an index
  266. contextp->Config.InterfaceIndex = HandleToUlong(initp->hInterface);
  267. if(InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) {
  268. if(AddLocalWkstaDialoutInterface(&contextp->Config.InterfaceIndex) != NO_ERROR) {
  269. TraceIpx(PPPIF_TRACE, "IpxCpBegin: AddLocalWkstaDialoutInterface failed !\n");
  270. RmDeallocateRoute(HandleToUlong(initp->hConnection));
  271. GlobalFree(contextp);
  272. return ERROR_CAN_NOT_COMPLETE;
  273. }
  274. }
  275. contextp->hPort = HandleToUlong(initp->hPort);
  276. contextp->hConnection = initp->hConnection;
  277. contextp->InterfaceType = InterfaceType;
  278. contextp->RouteState = ROUTE_ALLOCATED;
  279. contextp->IpxwanState = IPXWAN_NOT_STARTED;
  280. contextp->ErrorLogged = FALSE;
  281. contextp->NetNumberNakSentCount = 0;
  282. contextp->NetNumberNakReceivedCount = 0;
  283. contextp->CompressionProtocol = TELEBIT_COMPRESSED_IPX;
  284. contextp->SetReceiveCompressionProtocol = FALSE; // no compression initially
  285. contextp->SetSendCompressionProtocol = FALSE;
  286. // mark all our desired parameters as negotiable
  287. for(i=0; i<MAX_DESIRED_PARAMETERS; i++) {
  288. contextp->DesiredParameterNegotiable[i] = TRUE;
  289. }
  290. if(!GlobalConfig.EnableCompressionProtocol) {
  291. contextp->DesiredParameterNegotiable[IPX_COMPRESSION_PROTOCOL_INDEX] = FALSE;
  292. }
  293. contextp->NodeHtLinkage.Flink = NULL;
  294. contextp->NodeHtLinkage.Blink = NULL;
  295. contextp->Config.ConnectionId = ConnectionId;
  296. contextp->AllocatedNetworkIndex = INVALID_NETWORK_INDEX;
  297. // check if this is an IPXWAN connection
  298. contextp->Config.IpxwanConfigRequired = 0;
  299. if((InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) ||
  300. (InterfaceType == IF_TYPE_STANDALONE_WORKSTATION_DIALOUT)) {
  301. if(GlobalConfig.EnableIpxwanForWorkstationDialout) {
  302. contextp->Config.IpxwanConfigRequired = 1;
  303. }
  304. }
  305. else
  306. {
  307. if(GetIpxwanInterfaceConfig(contextp->Config.InterfaceIndex,
  308. &contextp->Config.IpxwanConfigRequired) != NO_ERROR) {
  309. RmDeallocateRoute(HandleToUlong(initp->hConnection));
  310. GlobalFree(contextp);
  311. return ERROR_CAN_NOT_COMPLETE;
  312. }
  313. }
  314. if(contextp->Config.IpxwanConfigRequired &&
  315. !IpxWanDllHandle) {
  316. TraceIpx(PPPIF_TRACE, "IpxCpBegin: IPXWAN Config Required but IPXWAN.DLL not loaded");
  317. RmDeallocateRoute(HandleToUlong(initp->hConnection));
  318. GlobalFree(contextp);
  319. return ERROR_CAN_NOT_COMPLETE;
  320. }
  321. contextp->IpxConnectionHandle = 0xFFFFFFFF;
  322. //
  323. // Set up the remaining context according to Dialin/Dialout role
  324. //
  325. if(initp->fServer) {
  326. //*** DIALIN ***
  327. if(!contextp->Config.IpxwanConfigRequired) {
  328. // allocate/generate the connection's WAN net number according to the router configuration
  329. if(GetWanNetNumber(contextp->Config.Network,
  330. &contextp->AllocatedNetworkIndex,
  331. contextp->InterfaceType) != NO_ERROR) {
  332. if(contextp->InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) {
  333. DeleteLocalWkstaDialoutInterface(contextp->Config.InterfaceIndex);
  334. }
  335. RmDeallocateRoute(HandleToUlong(initp->hConnection));
  336. GlobalFree(contextp);
  337. return ERROR_CAN_NOT_COMPLETE;
  338. }
  339. // set up the local server node value
  340. contextp->Config.LocalNode[5] = 1;
  341. // set up the remote client node value
  342. ACQUIRE_DATABASE_LOCK;
  343. // if we have been given a specific node to handout
  344. // to clients, assign it here
  345. if (bAssignSpecificNode) {
  346. memcpy (contextp->Config.RemoteNode, GlobalConfig.puSpecificNode, 6);
  347. }
  348. // Otherwise, assign a random node number
  349. else {
  350. LastNodeAssigned++;
  351. PUTULONG2LONG(&contextp->Config.RemoteNode[2], LastNodeAssigned);
  352. contextp->Config.RemoteNode[0] = 0x02;
  353. contextp->Config.RemoteNode[1] = 0xEE;
  354. }
  355. // if global wan net -> insert this context buffer in the node hash table.
  356. if((contextp->InterfaceType == IF_TYPE_WAN_WORKSTATION) &&
  357. GlobalConfig.RParams.EnableGlobalWanNet)
  358. {
  359. // Try until we get a unique node number
  360. while(!NodeIsUnique(contextp->Config.RemoteNode)) {
  361. LastNodeAssigned++;
  362. PUTULONG2LONG(&contextp->Config.RemoteNode[2], LastNodeAssigned);
  363. }
  364. AddToNodeHT(contextp);
  365. }
  366. RELEASE_DATABASE_LOCK;
  367. }
  368. else
  369. {
  370. // we'll have IPXWAN config on this line
  371. // set up the remote client node value if the remote is a wksta
  372. if(contextp->InterfaceType == IF_TYPE_WAN_WORKSTATION) {
  373. ACQUIRE_DATABASE_LOCK;
  374. LastNodeAssigned++;
  375. PUTULONG2LONG(&contextp->Config.RemoteNode[2], LastNodeAssigned);
  376. contextp->Config.RemoteNode[0] = 0x02;
  377. contextp->Config.RemoteNode[1] = 0xEE;
  378. if(GlobalConfig.RParams.EnableGlobalWanNet) {
  379. // Try until we get a unique node number
  380. while(!NodeIsUnique(contextp->Config.RemoteNode)) {
  381. LastNodeAssigned++;
  382. PUTULONG2LONG(&contextp->Config.RemoteNode[2], LastNodeAssigned);
  383. }
  384. AddToNodeHT(contextp);
  385. }
  386. RELEASE_DATABASE_LOCK;
  387. }
  388. }
  389. contextp->Config.ConnectionClient = 0;
  390. }
  391. else
  392. {
  393. //*** DIALOUT ***
  394. if(!contextp->Config.IpxwanConfigRequired) {
  395. // set up the context for the client
  396. // no network allocated
  397. contextp->AllocatedNetworkIndex = INVALID_NETWORK_INDEX;
  398. // default network is null for all cases except cisco router client
  399. memcpy(contextp->Config.Network, nullnet, 4);
  400. contextp->Config.RemoteNode[5] = 1; // server node value
  401. // set up the value to be requested as the client node
  402. tickcount = GetTickCount();
  403. PUTULONG2LONG(&contextp->Config.LocalNode[2], tickcount);
  404. contextp->Config.LocalNode[0] = 0x02;
  405. contextp->Config.LocalNode[1] = 0xEE;
  406. }
  407. contextp->Config.ConnectionClient = 1;
  408. if((contextp->InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) ||
  409. (contextp->InterfaceType == IF_TYPE_STANDALONE_WORKSTATION_DIALOUT)) {
  410. ACQUIRE_DATABASE_LOCK;
  411. WorkstationDialoutActive++;
  412. RELEASE_DATABASE_LOCK;
  413. }
  414. // disable the browser on ipx and netbios
  415. DisableRestoreBrowserOverIpx(contextp, TRUE);
  416. DisableRestoreBrowserOverNetbiosIpx(contextp, TRUE);
  417. }
  418. ACQUIRE_DATABASE_LOCK;
  419. if(contextp->Config.IpxwanConfigRequired) {
  420. AddToConnHT(contextp);
  421. }
  422. RELEASE_DATABASE_LOCK;
  423. return (NO_ERROR);
  424. }
  425. //***
  426. //
  427. // Function: IpxCpEnd
  428. //
  429. // Descr: Called when the line gets disconnected
  430. //
  431. //***
  432. DWORD
  433. IpxCpEnd(IN VOID *pWorkBuffer)
  434. {
  435. PIPXCP_CONTEXT contextp;
  436. DWORD err;
  437. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  438. TraceIpx(PPPIF_TRACE, "IpxCpEnd: Entered for if # %d\n", contextp->Config.InterfaceIndex);
  439. if(!contextp->Config.ConnectionClient) {
  440. //*** DIALIN Clean-Up ***
  441. if(!contextp->Config.IpxwanConfigRequired) {
  442. // if wan net allocated, release the wan net
  443. if(contextp->AllocatedNetworkIndex != INVALID_NETWORK_INDEX) {
  444. ReleaseWanNetNumber(contextp->AllocatedNetworkIndex);
  445. }
  446. }
  447. ACQUIRE_DATABASE_LOCK;
  448. if((contextp->InterfaceType == IF_TYPE_WAN_WORKSTATION) &&
  449. GlobalConfig.RParams.EnableGlobalWanNet) {
  450. RemoveFromNodeHT(contextp);
  451. }
  452. RELEASE_DATABASE_LOCK;
  453. }
  454. else
  455. {
  456. //*** DIALOUT Clean-Up ***
  457. if((contextp->InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) ||
  458. (contextp->InterfaceType == IF_TYPE_STANDALONE_WORKSTATION_DIALOUT)) {
  459. ACQUIRE_DATABASE_LOCK;
  460. WorkstationDialoutActive--;
  461. RELEASE_DATABASE_LOCK;
  462. }
  463. // restore the browser on ipx and netbios
  464. DisableRestoreBrowserOverIpx(contextp, FALSE);
  465. DisableRestoreBrowserOverNetbiosIpx(contextp, FALSE);
  466. }
  467. // we count on the route being de-allocated when the line gets disconnected
  468. err = RmDeallocateRoute(HandleToUlong(contextp->hConnection));
  469. if(contextp->InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) {
  470. DeleteLocalWkstaDialoutInterface(contextp->Config.InterfaceIndex);
  471. }
  472. ACQUIRE_DATABASE_LOCK;
  473. if(contextp->Config.IpxwanConfigRequired) {
  474. RemoveFromConnHT(contextp);
  475. }
  476. // free the work buffer
  477. if(GlobalFree(contextp)) {
  478. SS_ASSERT(FALSE);
  479. }
  480. RELEASE_DATABASE_LOCK;
  481. return (NO_ERROR);
  482. }
  483. DWORD
  484. IpxCpReset(IN VOID *pWorkBuffer)
  485. {
  486. return(NO_ERROR);
  487. }
  488. DWORD
  489. IpxCpProjectionNotification(IN VOID *pWorkBuffer,
  490. IN VOID *pProjectionResult)
  491. {
  492. PIPXCP_CONTEXT contextp;
  493. return NO_ERROR;
  494. }
  495. //***
  496. //
  497. // Function: IpxThisLayerUp
  498. //
  499. // Descr: Called when the IPXCP negotiation has been SUCCESSFULY
  500. // completed
  501. //
  502. //***
  503. DWORD
  504. IpxCpThisLayerUp(IN VOID *pWorkBuffer)
  505. {
  506. PIPXCP_CONTEXT contextp;
  507. DWORD err;
  508. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  509. dwClientCount++;
  510. TraceIpx(PPPIF_TRACE, "IpxCpThisLayerUp: Entered for if # %d (%d total)\n",
  511. contextp->Config.InterfaceIndex, dwClientCount);
  512. if(contextp->Config.IpxwanConfigRequired) {
  513. //
  514. //*** Configuration done with IPXWAN ***
  515. //
  516. ACQUIRE_DATABASE_LOCK;
  517. switch(contextp->IpxwanState) {
  518. case IPXWAN_NOT_STARTED:
  519. TraceIpx(
  520. PPPIF_TRACE,
  521. "IpxCpThisLayerUp: Do LINEUP on if #%d. IPXWAN completes config.\n",
  522. contextp->Config.InterfaceIndex);
  523. if((err = RmActivateRoute(contextp->hPort, &contextp->Config)) == NO_ERROR) {
  524. contextp->RouteState = ROUTE_ACTIVATED;
  525. contextp->IpxwanState = IPXWAN_ACTIVE;
  526. err = PENDING;
  527. }
  528. break;
  529. case IPXWAN_ACTIVE:
  530. err = PENDING;
  531. break;
  532. case IPXWAN_DONE:
  533. default:
  534. err = contextp->IpxwanConfigResult;
  535. break;
  536. }
  537. RELEASE_DATABASE_LOCK;
  538. return err;
  539. }
  540. //
  541. //*** Configuration done with IPXCP ***
  542. //
  543. if(contextp->RouteState != ROUTE_ALLOCATED) {
  544. return NO_ERROR;
  545. }
  546. // call LineUp indication into the IPX stack with the negociated config
  547. // values.
  548. TraceIpx(
  549. PPPIF_TRACE,
  550. "IpxCpThisLayerUp: Config complete, Do LINEUP on if #%d.\n",
  551. contextp->Config.InterfaceIndex);
  552. if(err = RmActivateRoute(contextp->hPort, &contextp->Config)) {
  553. return err;
  554. }
  555. TraceIpx(PPPIF_TRACE,"\n*** IPXCP final configuration ***\n");
  556. TraceIpx(PPPIF_TRACE," Network: %.2x%.2x%.2x%.2x\n",
  557. contextp->Config.Network[0],
  558. contextp->Config.Network[1],
  559. contextp->Config.Network[2],
  560. contextp->Config.Network[3]);
  561. TraceIpx(PPPIF_TRACE," LocalNode: %.2x%.2x%.2x%.2x%.2x%.2x\n",
  562. contextp->Config.LocalNode[0],
  563. contextp->Config.LocalNode[1],
  564. contextp->Config.LocalNode[2],
  565. contextp->Config.LocalNode[3],
  566. contextp->Config.LocalNode[4],
  567. contextp->Config.LocalNode[5]);
  568. TraceIpx(PPPIF_TRACE," RemoteNode: %.2x%.2x%.2x%.2x%.2x%.2x\n",
  569. contextp->Config.RemoteNode[0],
  570. contextp->Config.RemoteNode[1],
  571. contextp->Config.RemoteNode[2],
  572. contextp->Config.RemoteNode[3],
  573. contextp->Config.RemoteNode[4],
  574. contextp->Config.RemoteNode[5]);
  575. TraceIpx(PPPIF_TRACE," ReceiveCompression = %d SendCompression = %d\n",
  576. contextp->SetReceiveCompressionProtocol,
  577. contextp->SetSendCompressionProtocol);
  578. contextp->RouteState = ROUTE_ACTIVATED;
  579. return NO_ERROR;
  580. }
  581. //***
  582. //
  583. // Function: IpxMakeConfigRequest
  584. //
  585. // Descr: Builds the config request packet from the desired parameters
  586. //
  587. //***
  588. DWORD
  589. IpxCpMakeConfigRequest(IN VOID *pWorkBuffer,
  590. OUT PPP_CONFIG *pRequestBuffer,
  591. IN DWORD cbRequestBuffer)
  592. {
  593. USHORT cnfglen;
  594. PUCHAR cnfgptr;
  595. USHORT optlen;
  596. PIPXCP_CONTEXT contextp;
  597. int i;
  598. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  599. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigRequest: Entered for if # %d\n",
  600. contextp->Config.InterfaceIndex);
  601. if(contextp->RouteState == NO_ROUTE) {
  602. TraceIpx(PPPIF_TRACE, "IpxcpMakeConfigRequest: No route allocated!\n");
  603. return(ERROR_NO_NETWORK);
  604. }
  605. // check that the request buffer is big enough to get the desired
  606. // parameters
  607. if((USHORT)cbRequestBuffer < DesiredConfigReqLength()) {
  608. return(ERROR_INSUFFICIENT_BUFFER);
  609. }
  610. pRequestBuffer->Code = CONFIG_REQ;
  611. cnfglen = 4;
  612. cnfgptr = (PUCHAR)pRequestBuffer;
  613. if(contextp->Config.IpxwanConfigRequired) {
  614. // Do not request any option
  615. PUTUSHORT2SHORT(pRequestBuffer->Length, cnfglen);
  616. return NO_ERROR;
  617. }
  618. // set the desired options
  619. for(i = 0; i < MaxDesiredParameters; i++) {
  620. if(!contextp->DesiredParameterNegotiable[i]) {
  621. // do not request this config option
  622. continue;
  623. }
  624. OptionHandler[DesiredParameter[i]](cnfgptr + cnfglen,
  625. contextp,
  626. NULL,
  627. SNDREQ_OPTION);
  628. optlen = *(cnfgptr + cnfglen + OPTIONH_LENGTH);
  629. cnfglen += optlen;
  630. }
  631. // set the length of the configuration request frame
  632. PUTUSHORT2SHORT(pRequestBuffer->Length, cnfglen);
  633. return NO_ERROR;
  634. }
  635. //***
  636. //
  637. // Function: IpxMakeConfigResult
  638. //
  639. // Descr: Starts by building the ack packet as the result
  640. // If an option gets NAKed (!), it resets the result packet
  641. // and starts building the NAK packet instead.
  642. // If an option gets rejected, only the reject packet will
  643. // be built.
  644. // If one of the desired parameters is missing from this
  645. // configuration request, we reset the result packet and start
  646. // building a NAK packet with the missing desired parameters.
  647. //
  648. //***
  649. #define MAX_OPTION_LENGTH 512
  650. DWORD
  651. IpxCpMakeConfigResult(IN VOID *pWorkBuffer,
  652. IN PPP_CONFIG *pReceiveBuffer,
  653. OUT PPP_CONFIG *pResultBuffer,
  654. IN DWORD cbResultBuffer,
  655. IN BOOL fRejectNaks)
  656. {
  657. USHORT cnfglen; // config request packet len
  658. USHORT rcvlen; // used to scan the received options packet
  659. USHORT reslen; // result length
  660. PUCHAR rcvptr;
  661. PUCHAR resptr; // result ptr
  662. PIPXCP_CONTEXT contextp;
  663. UCHAR option; // value of this option
  664. UCHAR optlen; // length of this option
  665. BOOL DesiredParameterRequested[MAX_DESIRED_PARAMETERS];
  666. USHORT i;
  667. BOOL AllDesiredParamsRequested;
  668. UCHAR nakedoption[MAX_OPTION_LENGTH];
  669. DWORD rc;
  670. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  671. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: Entered for if # %d\n",
  672. contextp->Config.InterfaceIndex);
  673. if(contextp->RouteState == NO_ROUTE) {
  674. return(ERROR_NO_NETWORK);
  675. }
  676. // start by marking all negotiable parameters as not requested yet
  677. for(i=0; i<MaxDesiredParameters; i++) {
  678. DesiredParameterRequested[i] = !contextp->DesiredParameterNegotiable[i];
  679. }
  680. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  681. // get the total cnfg request packet length
  682. GETSHORT2USHORT(&cnfglen, pReceiveBuffer->Length);
  683. // check that the result buffer is at least as big as the receive buffer
  684. if((USHORT)cbResultBuffer < cnfglen) {
  685. return(ERROR_PPP_INVALID_PACKET);
  686. }
  687. // set the ptrs and length to the start of the options in the packet
  688. pResultBuffer->Code = CONFIG_ACK;
  689. rcvptr = (PUCHAR)pReceiveBuffer;
  690. resptr = (PUCHAR)pResultBuffer;
  691. if(contextp->Config.IpxwanConfigRequired) {
  692. if(cnfglen > 4) {
  693. pResultBuffer->Code = CONFIG_REJ;
  694. for(rcvlen = reslen = 4;
  695. rcvlen < cnfglen;
  696. rcvlen += optlen) {
  697. // get the current option type and length
  698. option = *(rcvptr + rcvlen + OPTIONH_TYPE);
  699. optlen = *(rcvptr + rcvlen + OPTIONH_LENGTH);
  700. CopyOption(resptr + reslen, rcvptr + rcvlen);
  701. reslen += optlen;
  702. }
  703. // set the final result length
  704. PUTUSHORT2SHORT(pResultBuffer->Length, reslen);
  705. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: reject all options because IPXWAN required\n");
  706. }
  707. else
  708. {
  709. PUTUSHORT2SHORT(pResultBuffer->Length, 4);
  710. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: ack null options packet because IPXWAN required\n");
  711. }
  712. return (NO_ERROR);
  713. }
  714. for(rcvlen = reslen = 4;
  715. rcvlen < cnfglen;
  716. rcvlen += optlen) {
  717. // get the current option type and length
  718. option = *(rcvptr + rcvlen + OPTIONH_TYPE);
  719. optlen = *(rcvptr + rcvlen + OPTIONH_LENGTH);
  720. switch(pResultBuffer->Code) {
  721. case CONFIG_ACK:
  722. // Check if this is a valid option
  723. if((rc = ValidOption(option, optlen)) != NO_ERROR) {
  724. if(rc == ERROR_INVALID_OPTLEN) {
  725. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: option %d has invalid length %d\n",
  726. option, optlen);
  727. return ERROR_PPP_NOT_CONVERGING;
  728. }
  729. // reject this option
  730. pResultBuffer->Code = CONFIG_REJ;
  731. // restart the result packet with this rejected option
  732. reslen = 4;
  733. CopyOption(resptr + reslen, rcvptr + rcvlen);
  734. reslen += optlen;
  735. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: REJECT option %\n",
  736. option);
  737. break;
  738. }
  739. // Option is valid.
  740. // Check if it is desired and acceptable
  741. if(DesiredOption(option, &i)) {
  742. DesiredParameterRequested[i] = TRUE;
  743. if(!OptionHandler[option](rcvptr + rcvlen,
  744. contextp,
  745. nakedoption,
  746. RCVREQ_OPTION)) {
  747. // if this is a renegociation, we are not converging!
  748. if(contextp->RouteState == ROUTE_ACTIVATED) {
  749. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: Not Converging\n");
  750. return ERROR_PPP_NOT_CONVERGING;
  751. }
  752. if((option == IPX_NETWORK_NUMBER) &&
  753. (contextp->NetNumberNakSentCount >= MAX_NET_NUMBER_NAKS_SENT)) {
  754. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: Not converging because TOO MANY NAKs SENT!!\n");
  755. return ERROR_PPP_NOT_CONVERGING;
  756. }
  757. //
  758. //*** NAK this option ***
  759. //
  760. // check if we should send a reject instead
  761. if(fRejectNaks) {
  762. // make up a reject packet
  763. pResultBuffer->Code = CONFIG_REJ;
  764. // restart the result packet with this rejected option
  765. reslen = 4;
  766. CopyOption(resptr + reslen, rcvptr + rcvlen);
  767. reslen += optlen;
  768. break;
  769. }
  770. pResultBuffer->Code = CONFIG_NAK;
  771. // restart the result packet with the NAK-ed option
  772. reslen = 4;
  773. CopyOption(resptr + reslen, nakedoption);
  774. reslen += optlen;
  775. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: NAK option %d\n", option);
  776. break;
  777. }
  778. }
  779. // Option is valid and either desired AND accepted or
  780. // not desired and we will accept it without any testing
  781. // Ack it and increment the result length.
  782. CopyOption(resptr + reslen, rcvptr + rcvlen);
  783. reslen += optlen;
  784. break;
  785. case CONFIG_NAK:
  786. // Check if this is a valid option
  787. if((rc = ValidOption(*(rcvptr + rcvlen + OPTIONH_TYPE),
  788. *(rcvptr + rcvlen + OPTIONH_LENGTH))) != NO_ERROR) {
  789. if(rc == ERROR_INVALID_OPTLEN) {
  790. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: option %d has invalid length %d\n",
  791. *(rcvptr + rcvlen + OPTIONH_TYPE),
  792. *(rcvptr + rcvlen + OPTIONH_LENGTH));
  793. return ERROR_PPP_NOT_CONVERGING;
  794. }
  795. // reject this option
  796. pResultBuffer->Code = CONFIG_REJ;
  797. // restart the result packet with this rejected option
  798. reslen = 4;
  799. CopyOption(resptr + reslen, rcvptr + rcvlen);
  800. reslen += optlen;
  801. break;
  802. }
  803. // We are looking only for options to NAK and skip all others
  804. if(DesiredOption(option, &i)) {
  805. DesiredParameterRequested[i] = TRUE;
  806. if(!OptionHandler[option](rcvptr + rcvlen,
  807. contextp,
  808. resptr + reslen,
  809. RCVREQ_OPTION)) {
  810. reslen += optlen;
  811. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: NAK option %d\n", option);
  812. if((option == IPX_NETWORK_NUMBER) &&
  813. (contextp->NetNumberNakSentCount >= MAX_NET_NUMBER_NAKS_SENT)) {
  814. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: TOO MANY NAKs SENT!!\n");
  815. return ERROR_PPP_NOT_CONVERGING;
  816. }
  817. }
  818. }
  819. break;
  820. case CONFIG_REJ:
  821. // We are looking only for options to reject and skip all others
  822. if((rc = ValidOption(*(rcvptr + rcvlen + OPTIONH_TYPE),
  823. *(rcvptr + rcvlen + OPTIONH_LENGTH))) != NO_ERROR) {
  824. if(rc == ERROR_INVALID_OPTLEN) {
  825. TraceIpx(PPPIF_TRACE, "IpxCpMakeConfigResult: option %d has invalid length %d\n",
  826. *(rcvptr + rcvlen + OPTIONH_TYPE),
  827. *(rcvptr + rcvlen + OPTIONH_LENGTH));
  828. return ERROR_PPP_NOT_CONVERGING;
  829. }
  830. CopyOption(resptr + reslen, rcvptr + rcvlen);
  831. reslen += optlen;
  832. }
  833. if(DesiredOption(option, &i)) {
  834. DesiredParameterRequested[i] = TRUE;
  835. }
  836. break;
  837. default:
  838. SS_ASSERT(FALSE);
  839. break;
  840. }
  841. }
  842. // check if all our desired parameters have been requested
  843. AllDesiredParamsRequested = TRUE;
  844. for(i=0; i<MaxDesiredParameters; i++) {
  845. if(!DesiredParameterRequested[i]) {
  846. AllDesiredParamsRequested = FALSE;
  847. }
  848. }
  849. if(AllDesiredParamsRequested) {
  850. //
  851. //*** ALL DESIRED PARAMETERS HAVE BEEN REQUESTED ***
  852. //
  853. // set the final result length
  854. PUTUSHORT2SHORT(pResultBuffer->Length, reslen);
  855. return (NO_ERROR);
  856. }
  857. //
  858. //*** SOME DESIRED PARAMETERS ARE MISSING ***
  859. //
  860. // check that we have enough result buffer to transmit all our non received
  861. // desired params
  862. if((USHORT)cbResultBuffer < DesiredConfigReqLength()) {
  863. return(ERROR_INSUFFICIENT_BUFFER);
  864. }
  865. switch(pResultBuffer->Code) {
  866. case CONFIG_ACK:
  867. // the only case where we request a NAK when a requested parameter
  868. // is missing is when this parameter is the node number
  869. if(DesiredParameterRequested[IPX_NODE_NUMBER_INDEX]) {
  870. break;
  871. }
  872. else
  873. {
  874. // reset the ACK packet and make it NAK packet
  875. pResultBuffer->Code = CONFIG_NAK;
  876. reslen = 4;
  877. // FALL THROUGH
  878. }
  879. case CONFIG_NAK:
  880. // Append the missing options in the NAK packet
  881. for(i=0; i<MaxDesiredParameters; i++) {
  882. if(DesiredParameterRequested[i]) {
  883. // skip it!
  884. continue;
  885. }
  886. option = DesiredParameter[i];
  887. if((option == IPX_NETWORK_NUMBER) ||
  888. (option == IPX_COMPRESSION_PROTOCOL)) {
  889. // These two desired options are not forced in a nak if
  890. // the other end didn't provide them.
  891. // skip it!
  892. continue;
  893. }
  894. OptionHandler[option](NULL,
  895. contextp,
  896. resptr + reslen,
  897. SNDNAK_OPTION);
  898. optlen = *(resptr + reslen + OPTIONH_LENGTH);
  899. reslen += optlen;
  900. }
  901. break;
  902. default:
  903. break;
  904. }
  905. // set the final result length
  906. PUTUSHORT2SHORT(pResultBuffer->Length, reslen);
  907. return (NO_ERROR);
  908. }
  909. DWORD
  910. IpxCpConfigNakReceived(IN VOID *pWorkBuffer,
  911. IN PPP_CONFIG *pReceiveBuffer)
  912. {
  913. PIPXCP_CONTEXT contextp;
  914. PUCHAR rcvptr;
  915. USHORT rcvlen;
  916. USHORT naklen;
  917. UCHAR option;
  918. UCHAR optlen;
  919. DWORD rc;
  920. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  921. TraceIpx(PPPIF_TRACE, "IpxCpConfigNakReceived: Entered for if # %d\n",
  922. contextp->Config.InterfaceIndex);
  923. if(contextp->Config.IpxwanConfigRequired) {
  924. return NO_ERROR;
  925. }
  926. rcvptr = (PUCHAR)pReceiveBuffer;
  927. GETSHORT2USHORT(&naklen, pReceiveBuffer->Length);
  928. for(rcvlen = 4; rcvlen < naklen; rcvlen += optlen) {
  929. // get the current option type and length
  930. option = *(rcvptr + rcvlen + OPTIONH_TYPE);
  931. optlen = *(rcvptr + rcvlen + OPTIONH_LENGTH);
  932. if((rc = ValidOption(option, optlen)) != NO_ERROR) {
  933. if(rc == ERROR_INVALID_OPTLEN) {
  934. TraceIpx(PPPIF_TRACE, "IpxCpConfigNakReceived: option %d has invalid length %d\n",
  935. option, optlen);
  936. return ERROR_PPP_NOT_CONVERGING;
  937. }
  938. TraceIpx(PPPIF_TRACE, "IpxCpConfigNakReceived: option %d not valid\n", option);
  939. // ignore this option
  940. continue;
  941. }
  942. else
  943. {
  944. // valid option
  945. OptionHandler[option](rcvptr + rcvlen,
  946. contextp,
  947. NULL,
  948. RCVNAK_OPTION);
  949. if((option == IPX_NETWORK_NUMBER) &&
  950. (contextp->NetNumberNakReceivedCount >= MAX_NET_NUMBER_NAKS_RECEIVED)) {
  951. TraceIpx(PPPIF_TRACE, "IpxCpConfigNakReceived: TOO MANY NAKs RECEIVED !! terminate IPXCP negotiation\n");
  952. return ERROR_PPP_NOT_CONVERGING;
  953. }
  954. }
  955. }
  956. return NO_ERROR;
  957. }
  958. DWORD
  959. IpxCpConfigAckReceived(IN VOID *pWorkBuffer,
  960. IN PPP_CONFIG *pReceiveBuffer)
  961. {
  962. PIPXCP_CONTEXT contextp;
  963. PUCHAR rcvptr;
  964. USHORT rcvlen;
  965. USHORT acklen;
  966. UCHAR option;
  967. USHORT optlen;
  968. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  969. TraceIpx(PPPIF_TRACE, "IpxCpConfigAckReceived: Entered for if # %d\n",
  970. contextp->Config.InterfaceIndex);
  971. // check that this is what we have requested
  972. rcvptr = (PUCHAR)pReceiveBuffer;
  973. GETSHORT2USHORT(&acklen, pReceiveBuffer->Length);
  974. if(contextp->Config.IpxwanConfigRequired) {
  975. if(acklen != 4) {
  976. return ERROR_PPP_NOT_CONVERGING;
  977. }
  978. else
  979. {
  980. return NO_ERROR;
  981. }
  982. }
  983. for(rcvlen = 4; rcvlen < acklen; rcvlen += optlen) {
  984. // get the current option type and length
  985. option = *(rcvptr + rcvlen + OPTIONH_TYPE);
  986. optlen = *(rcvptr + rcvlen + OPTIONH_LENGTH);
  987. if(!DesiredOption(option, NULL)) {
  988. // this is not our option!
  989. TraceIpx(PPPIF_TRACE, "IpxCpConfigAckReceived: Option %d not desired\n", option);
  990. return ERROR_PPP_NOT_CONVERGING;
  991. }
  992. if(!OptionHandler[option](rcvptr + rcvlen,
  993. contextp,
  994. NULL,
  995. RCVACK_OPTION)) {
  996. // this option doesn't have our configured request value
  997. TraceIpx(PPPIF_TRACE, "IpxCpConfigAckReceived: Option %d not our value\n", option);
  998. return ERROR_PPP_NOT_CONVERGING;
  999. }
  1000. }
  1001. TraceIpx(PPPIF_TRACE, "IpxCpConfigAckReceived: All options validated\n");
  1002. return NO_ERROR;
  1003. }
  1004. DWORD
  1005. IpxCpConfigRejReceived(IN VOID *pWorkBuffer,
  1006. IN PPP_CONFIG *pReceiveBuffer)
  1007. {
  1008. PIPXCP_CONTEXT contextp;
  1009. PUCHAR rcvptr;
  1010. USHORT rcvlen;
  1011. USHORT rejlen;
  1012. UCHAR option;
  1013. USHORT optlen;
  1014. int i;
  1015. // if we are a server node or a client on a server machine, we don't accept
  1016. // any rejection
  1017. if(IsRouterStarted()) {
  1018. TraceIpx(PPPIF_TRACE, "IpxCpConfigRejReceived: Cannot handle rejects on a router, aborting\n");
  1019. return ERROR_PPP_NOT_CONVERGING;
  1020. }
  1021. // This node doesn't have a router. We continue the negotiation with the
  1022. // remaining options.
  1023. // If the network number negotiation has been rejected, we will tell the
  1024. // ipx stack that we have net number 0 and let it deal with it.
  1025. contextp = (PIPXCP_CONTEXT)pWorkBuffer;
  1026. TraceIpx(PPPIF_TRACE, "IpxCpConfigRejReceived: Entered for if # %d\n",
  1027. contextp->Config.InterfaceIndex);
  1028. if(contextp->Config.IpxwanConfigRequired) {
  1029. return ERROR_PPP_NOT_CONVERGING;
  1030. }
  1031. // check that this is what we have requested
  1032. rcvptr = (PUCHAR)pReceiveBuffer;
  1033. GETSHORT2USHORT(&rejlen, pReceiveBuffer->Length);
  1034. for(rcvlen = 4; rcvlen < rejlen; rcvlen += optlen) {
  1035. // get the current option type and length
  1036. option = *(rcvptr + rcvlen + OPTIONH_TYPE);
  1037. optlen = *(rcvptr + rcvlen + OPTIONH_LENGTH);
  1038. if(optlen == 0) {
  1039. TraceIpx(PPPIF_TRACE, "IpxCpConfigRejReceived: received null option length, aborting\n");
  1040. return ERROR_PPP_NOT_CONVERGING;
  1041. }
  1042. for(i=0; i<MAX_DESIRED_PARAMETERS; i++) {
  1043. if(option == DesiredParameter[i]) {
  1044. switch(i) {
  1045. case 0:
  1046. TraceIpx(PPPIF_TRACE, "IpxCpConfigRejReceived: Turn off Network Number negotiation\n");
  1047. break;
  1048. case 1:
  1049. TraceIpx(PPPIF_TRACE, "IpxCpConfigRejReceived: Turn off Node Number negotiation\n");
  1050. break;
  1051. default:
  1052. break;
  1053. }
  1054. contextp->DesiredParameterNegotiable[i] = FALSE;
  1055. // if this is the node configuration rejected, set the remote
  1056. // node to 0 to indicate it's unknown.
  1057. if(option == IPX_NODE_NUMBER) {
  1058. memcpy(contextp->Config.RemoteNode, nullnode, 6);
  1059. }
  1060. }
  1061. }
  1062. }
  1063. return NO_ERROR;
  1064. }
  1065. DWORD
  1066. IpxCpThisLayerDown(IN VOID *pWorkBuffer)
  1067. {
  1068. dwClientCount--;
  1069. TraceIpx(PPPIF_TRACE, "IpxCpThisLayerDown: Entered (%d total)\n", dwClientCount);
  1070. // If the last client hung up, go ahead and update all of the global
  1071. // config
  1072. if (dwClientCount == 0)
  1073. IpxcpUpdateQueuedGlobalConfig();
  1074. return 0L;
  1075. }
  1076. char * YesNo (DWORD dwVal) {
  1077. return (dwVal) ? "YES" : "NO";
  1078. }
  1079. //
  1080. // Gets called when a registry value related to ppp changes. This
  1081. // function must read in the new registry config and plumb any
  1082. // changes it finds.
  1083. //
  1084. // The following values will be supported for on the fly update
  1085. // since they are exposed through connections ui:
  1086. // CQC_THIS_MACHINE_ONLY
  1087. // CQC_ENABLE_GLOBAL_WAN_NET
  1088. // CQC_FIRST_WAN_NET
  1089. // CQC_ENABLE_AUTO_WAN_NET_ALLOCATION
  1090. // CQC_ACCEPT_REMOTE_NODE_NUMBER
  1091. //
  1092. // In addition the following will be supported
  1093. // CQC_FIRST_WAN_NODE
  1094. //
  1095. DWORD
  1096. IpxCpUpdateGlobalConfig()
  1097. {
  1098. IPXCP_GLOBAL_CONFIG_PARAMS Params;
  1099. DWORD dwErr;
  1100. INT iCmp;
  1101. TraceIpx(PPPIF_TRACE, "IpxCpUpdateGlobalConfig: Entered");
  1102. // Re-read the configuration from the registry
  1103. CopyMemory (&Params, &GlobalConfig, sizeof (Params));
  1104. GetIpxCpParameters(&Params);
  1105. // First, go through and update any parameters that can immediately be
  1106. // applied. Included in these are: CQC_THIS_MACHINE_ONLY
  1107. //
  1108. if (!!(Params.RParams.ThisMachineOnly) != !!(GlobalConfig.RParams.ThisMachineOnly)) {
  1109. GlobalConfig.RParams.ThisMachineOnly = !!(Params.RParams.ThisMachineOnly);
  1110. // Tell the router manager that some configuration has updated
  1111. if (RmUpdateIpxcpConfig) {
  1112. if ((dwErr = RmUpdateIpxcpConfig (&(GlobalConfig.RParams))) != NO_ERROR)
  1113. return dwErr;
  1114. }
  1115. }
  1116. // Now, go through and queue any settings that will take
  1117. // delayed effect.
  1118. //
  1119. // Queue any changes to the global wan net enabling
  1120. if (!!(Params.RParams.EnableGlobalWanNet) != !!(GlobalConfig.RParams.EnableGlobalWanNet))
  1121. CQAdd ( hConfigQueue,
  1122. CQC_ENABLE_GLOBAL_WAN_NET,
  1123. &(Params.RParams.EnableGlobalWanNet),
  1124. sizeof (Params.RParams.EnableGlobalWanNet));
  1125. // Queue any changes to the globalwan/firstwan setting
  1126. if (Params.FirstWanNet != GlobalConfig.FirstWanNet)
  1127. CQAdd (hConfigQueue, CQC_FIRST_WAN_NET, &(Params.FirstWanNet), sizeof(Params.FirstWanNet));
  1128. // Queue any changes to the auto net assignment enabling
  1129. if (!!(Params.EnableAutoWanNetAllocation) != !!(GlobalConfig.EnableAutoWanNetAllocation))
  1130. CQAdd ( hConfigQueue,
  1131. CQC_ENABLE_AUTO_WAN_NET_ALLOCATION,
  1132. &(Params.EnableAutoWanNetAllocation),
  1133. sizeof (Params.EnableAutoWanNetAllocation));
  1134. // Queue any changes to the accept remote node enabling
  1135. if (!!(Params.AcceptRemoteNodeNumber) != !!(GlobalConfig.AcceptRemoteNodeNumber))
  1136. CQAdd ( hConfigQueue,
  1137. CQC_ACCEPT_REMOTE_NODE_NUMBER,
  1138. &(Params.AcceptRemoteNodeNumber),
  1139. sizeof (Params.AcceptRemoteNodeNumber));
  1140. // Queue any changes to the first remote node setting
  1141. if (memcmp (Params.puSpecificNode, GlobalConfig.puSpecificNode, 6) != 0)
  1142. CQAdd (hConfigQueue, CQC_FIRST_WAN_NODE, Params.puSpecificNode, 6);
  1143. // If there are no clients, go ahead and update the queued config
  1144. //
  1145. if (dwClientCount == 0) {
  1146. if ((dwErr = IpxcpUpdateQueuedGlobalConfig()) != NO_ERROR)
  1147. return dwErr;
  1148. }
  1149. TraceIpx(PPPIF_TRACE, "IpxCpUpdateGlobalConfig: exiting...\n");
  1150. return NO_ERROR;
  1151. }
  1152. //
  1153. // Callback function used to update each piece of queued configuration
  1154. // data one at a time. The client count is assumed to be zero when this
  1155. // function is called.
  1156. //
  1157. BOOL
  1158. IpxcpUpdateConfigItem (DWORD dwCode, LPVOID pvData, DWORD dwSize, ULONG_PTR ulpUser) {
  1159. DWORD dwErr, dwData = *(DWORD*)pvData;
  1160. PUCHAR puData = (PUCHAR)pvData;
  1161. DWORD* pdwFlags = (DWORD*)ulpUser;
  1162. TraceIpx(PPPIF_TRACE, "IpxcpUpdateConfigItem: Entered for item code %x", dwCode);
  1163. switch (dwCode) {
  1164. case CQC_ENABLE_GLOBAL_WAN_NET:
  1165. TraceIpx(PPPIF_TRACE, "IpxcpUpdateConfigItem: EnableGlobalWanNet %s", YesNo(dwData));
  1166. GlobalConfig.RParams.EnableGlobalWanNet = !!dwData;
  1167. *pdwFlags |= FLAG_UPDATE_ROUTER | FLAG_UPDATE_WANNET;
  1168. break;
  1169. case CQC_FIRST_WAN_NET:
  1170. TraceIpx(PPPIF_TRACE, "IpxcpUpdateConfigItem: FirstWanNet %x", dwData);
  1171. GlobalConfig.FirstWanNet = dwData;
  1172. *pdwFlags |= FLAG_UPDATE_WANNET;
  1173. break;
  1174. case CQC_ENABLE_AUTO_WAN_NET_ALLOCATION:
  1175. TraceIpx(PPPIF_TRACE, "IpxcpUpdateConfigItem: EnableAutoAssign %s", YesNo(dwData));
  1176. GlobalConfig.EnableAutoWanNetAllocation = !!dwData;
  1177. *pdwFlags |= FLAG_UPDATE_WANNET;
  1178. break;
  1179. case CQC_ACCEPT_REMOTE_NODE_NUMBER:
  1180. TraceIpx(PPPIF_TRACE, "IpxcpUpdateConfigItem: AcceptRemoteNodeNumber %s", YesNo(dwData));
  1181. GlobalConfig.AcceptRemoteNodeNumber = !!dwData;
  1182. break;
  1183. case CQC_FIRST_WAN_NODE:
  1184. TraceIpx(PPPIF_TRACE, "IpxcpUpdateConfigItem: FirstWanNode %x%x%x%x%x%x", puData[0], puData[1], puData[2], puData[3], puData[4], puData[5]);
  1185. memcpy (GlobalConfig.puSpecificNode, pvData, 6);
  1186. GETLONG2ULONG(&LastNodeAssigned,&(GlobalConfig.puSpecificNode[2]));
  1187. break;
  1188. }
  1189. return NO_ERROR;
  1190. }
  1191. //
  1192. // Called only when client count is zero to update any settings that have
  1193. // been queued to take place.
  1194. //
  1195. DWORD
  1196. IpxcpUpdateQueuedGlobalConfig() {
  1197. DWORD dwErr, dwFlags = 0;
  1198. TraceIpx(PPPIF_TRACE, "IpxcpUpdateQueuedGlobalConfig: entered");
  1199. // Enumerate all of the queued config information updating
  1200. // global config as we go.
  1201. //
  1202. if ((dwErr = CQEnum (hConfigQueue, IpxcpUpdateConfigItem, (ULONG_PTR)&dwFlags)) != NO_ERROR)
  1203. return dwErr;
  1204. // If we need to update the wan net, do so
  1205. //
  1206. if (dwFlags & FLAG_UPDATE_WANNET) {
  1207. TraceIpx(PPPIF_TRACE, "IpxcpUpdateQueuedGlobalConfig: Updating WanNet Information.");
  1208. WanNetReconfigure();
  1209. }
  1210. // If we need to update the router, do so
  1211. //
  1212. if (dwFlags & FLAG_UPDATE_ROUTER) {
  1213. TraceIpx(PPPIF_TRACE, "IpxcpUpdateQueuedGlobalConfig: Updating Router.");
  1214. if (RmUpdateIpxcpConfig) {
  1215. if ((dwErr = RmUpdateIpxcpConfig (&(GlobalConfig.RParams))) != NO_ERROR)
  1216. return dwErr;
  1217. }
  1218. }
  1219. // Clear the queued config data as it has been completely processed
  1220. // at this point.
  1221. //
  1222. CQRemoveAll (hConfigQueue);
  1223. return NO_ERROR;
  1224. }
  1225. DWORD
  1226. ValidOption(UCHAR option,
  1227. UCHAR optlen)
  1228. {
  1229. //
  1230. // NarenG: Put in fix for Bug # 74555. Otherwise PPP was blocked in
  1231. // NakReceived which was in a forever loop.
  1232. //
  1233. if ( optlen == 0 )
  1234. {
  1235. return( ERROR_INVALID_OPTLEN );
  1236. }
  1237. switch(option)
  1238. {
  1239. case IPX_NETWORK_NUMBER:
  1240. if(optlen != 6)
  1241. {
  1242. return ERROR_INVALID_OPTLEN;
  1243. }
  1244. return NO_ERROR;
  1245. break;
  1246. case IPX_NODE_NUMBER:
  1247. if(optlen != 8)
  1248. {
  1249. return ERROR_INVALID_OPTLEN;
  1250. }
  1251. return NO_ERROR;
  1252. break;
  1253. case IPX_ROUTING_PROTOCOL:
  1254. if(optlen < 4)
  1255. {
  1256. return ERROR_INVALID_OPTLEN;
  1257. }
  1258. return NO_ERROR;
  1259. break;
  1260. case IPX_ROUTER_NAME:
  1261. if(optlen < 3)
  1262. {
  1263. return ERROR_INVALID_OPTLEN;
  1264. }
  1265. else
  1266. {
  1267. TraceIpx(
  1268. PPPIF_TRACE,
  1269. "ValidOption: Accept Router Name w/ valid len.");
  1270. return NO_ERROR;
  1271. }
  1272. break;
  1273. case IPX_CONFIGURATION_COMPLETE:
  1274. if(optlen != 2)
  1275. {
  1276. return ERROR_INVALID_OPTLEN;
  1277. }
  1278. return NO_ERROR;
  1279. break;
  1280. case IPX_COMPRESSION_PROTOCOL:
  1281. if(GlobalConfig.EnableCompressionProtocol)
  1282. {
  1283. if(optlen < 4)
  1284. {
  1285. return ERROR_INVALID_OPTLEN;
  1286. }
  1287. }
  1288. else
  1289. {
  1290. return ERROR_INVALID_OPTION;
  1291. }
  1292. break;
  1293. default:
  1294. return ERROR_INVALID_OPTION;
  1295. }
  1296. return ERROR_INVALID_OPTION;
  1297. }
  1298. BOOL
  1299. DesiredOption(UCHAR option, USHORT *indexp)
  1300. {
  1301. USHORT i;
  1302. for(i=0; i<MaxDesiredParameters; i++) {
  1303. if(option == DesiredParameter[i]) {
  1304. if(indexp) {
  1305. *indexp = i;
  1306. }
  1307. return TRUE;
  1308. }
  1309. }
  1310. return FALSE;
  1311. }
  1312. USHORT
  1313. DesiredConfigReqLength(VOID)
  1314. {
  1315. USHORT i, len;
  1316. for(i=0, len=0; i<MaxDesiredParameters; i++) {
  1317. len += DesiredParameterLength[i];
  1318. }
  1319. return len;
  1320. }