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.

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