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.

690 lines
17 KiB

  1. /*******************************************************************/
  2. /* Copyright(c) 1993 Microsoft Corporation */
  3. /*******************************************************************/
  4. //***
  5. //
  6. // Filename: options.c
  7. //
  8. // Description: routines for options handling
  9. //
  10. // Author: Stefan Solomon (stefans) November 24, 1993.
  11. //
  12. // Revision History:
  13. //
  14. //***
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. extern HANDLE g_hRouterLog;
  18. VOID
  19. SetNetworkNak(PUCHAR resptr,
  20. PIPXCP_CONTEXT contextp);
  21. VOID
  22. SetNodeNak(PUCHAR resptr,
  23. PIPXCP_CONTEXT contextp);
  24. VOID
  25. SetOptionTypeAndLength(PUCHAR dstptr,
  26. UCHAR opttype,
  27. UCHAR optlen);
  28. #if DBG
  29. #define GET_LOCAL_NET GETLONG2ULONG(&dbglocnet, contextp->Config.Network)
  30. #else
  31. #define GET_LOCAL_NET
  32. #endif
  33. //***
  34. //
  35. // Global description of option handlers
  36. //
  37. // Input: optptr - pointer to the respective option in the frame
  38. // contextp - pointer to the associated context (work buffer)
  39. // resptr - pointer to the response frame to be generated
  40. // Action - one of:
  41. // SNDREQ_OPTION - optptr is the frame to be sent as
  42. // a config request;
  43. // RCVNAK_OPTION - optptr is the frame received as NAK
  44. // RCVREQ_OPTION - optptr is the received request.
  45. // resptr is the frame to generate back
  46. // a response. If the response is not
  47. // an ACK, the return code is FALSE.
  48. // In this case if resptr is not NULL it
  49. // gets the NAK frame.
  50. //
  51. //***
  52. BOOL
  53. NetworkNumberHandler(PUCHAR optptr,
  54. PIPXCP_CONTEXT contextp,
  55. PUCHAR resptr,
  56. OPT_ACTION Action)
  57. {
  58. ULONG recvdnet;
  59. ULONG localnet;
  60. BOOL rc = TRUE;
  61. UCHAR newnet[4];
  62. UCHAR asc[9];
  63. PUCHAR ascp;
  64. // prepare to log if error
  65. asc[8] = 0;
  66. ascp = asc;
  67. switch(Action) {
  68. case SNDREQ_OPTION:
  69. SetOptionTypeAndLength(optptr, IPX_NETWORK_NUMBER, 6);
  70. memcpy(optptr + OPTIONH_DATA, contextp->Config.Network, 4);
  71. GETLONG2ULONG(&localnet, contextp->Config.Network);
  72. TraceIpx(OPTIONS_TRACE, "NetworkNumberHandler: SND REQ with net 0x%x\n", localnet);
  73. break;
  74. case RCVNAK_OPTION:
  75. contextp->NetNumberNakReceivedCount++;
  76. GETLONG2ULONG(&recvdnet, optptr + OPTIONH_DATA);
  77. GETLONG2ULONG(&localnet, contextp->Config.Network);
  78. TraceIpx(OPTIONS_TRACE, "NetworkNumberHandler: RCV NAK with net 0x%x\n", recvdnet);
  79. if(recvdnet > localnet) {
  80. if(IsRoute(optptr + OPTIONH_DATA)) {
  81. if(GetUniqueHigherNetNumber(newnet,
  82. optptr + OPTIONH_DATA,
  83. contextp) == NO_ERROR) {
  84. // store a new net proposal for the next net send config request
  85. memcpy(contextp->Config.Network, newnet, 4);
  86. }
  87. else
  88. {
  89. // cannot get a net number unique and higher
  90. break;
  91. }
  92. }
  93. else
  94. {
  95. if((contextp->InterfaceType == IF_TYPE_WAN_WORKSTATION) &&
  96. GlobalConfig.RParams.EnableGlobalWanNet) {
  97. break;
  98. }
  99. else
  100. {
  101. memcpy(contextp->Config.Network, optptr + OPTIONH_DATA, 4);
  102. }
  103. }
  104. }
  105. break;
  106. case RCVACK_OPTION:
  107. if(memcmp(contextp->Config.Network, optptr + OPTIONH_DATA, 4)) {
  108. rc = FALSE;
  109. }
  110. break;
  111. case RCVREQ_OPTION:
  112. // if we have already negotiated and this is a renegociation, stick by
  113. // what we have already told the stack in line-up
  114. if(contextp->RouteState == ROUTE_ACTIVATED) {
  115. TraceIpx(OPTIONS_TRACE, "NetworkNumberHandler: rcv req in re-negociation\n");
  116. if(memcmp(contextp->Config.Network, optptr + OPTIONH_DATA, 4)) {
  117. SetNetworkNak(resptr, contextp);
  118. rc = FALSE;
  119. }
  120. break;
  121. }
  122. GETLONG2ULONG(&recvdnet, optptr + OPTIONH_DATA);
  123. GETLONG2ULONG(&localnet, contextp->Config.Network);
  124. // check if a network number has been requested
  125. if((recvdnet == 0) &&
  126. ((contextp->InterfaceType == IF_TYPE_STANDALONE_WORKSTATION_DIALOUT) ||
  127. (contextp->InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT))) {
  128. // this is a workstation and needs a network number
  129. if(GetUniqueHigherNetNumber(newnet,
  130. nullnet,
  131. contextp) == NO_ERROR) {
  132. memcpy(contextp->Config.Network, newnet, 4);
  133. }
  134. SetNetworkNak(resptr, contextp);
  135. rc = FALSE;
  136. }
  137. else
  138. {
  139. if(recvdnet > localnet) {
  140. // check if we don't have a net number conflict
  141. if(IsRoute(optptr + OPTIONH_DATA)) {
  142. NetToAscii(ascp, optptr + OPTIONH_DATA);
  143. RouterLogErrorW(
  144. g_hRouterLog,
  145. ROUTERLOG_IPXCP_NETWORK_NUMBER_CONFLICT,
  146. 1,
  147. (PWCHAR*)&ascp,
  148. NO_ERROR);
  149. if(GetUniqueHigherNetNumber(newnet,
  150. optptr + OPTIONH_DATA,
  151. contextp) == NO_ERROR) {
  152. // new net is different, NAK with this new value
  153. memcpy(contextp->Config.Network, newnet, 4);
  154. }
  155. SetNetworkNak(resptr, contextp);
  156. rc = FALSE;
  157. }
  158. else
  159. {
  160. // the received net number is unique but is different
  161. // of the locally configured net number.
  162. if((contextp->InterfaceType == IF_TYPE_WAN_WORKSTATION) &&
  163. GlobalConfig.RParams.EnableGlobalWanNet) {
  164. NetToAscii(ascp, optptr + OPTIONH_DATA);
  165. RouterLogErrorW(
  166. g_hRouterLog,
  167. ROUTERLOG_IPXCP_CANNOT_CHANGE_WAN_NETWORK_NUMBER,
  168. 1,
  169. (PWCHAR*)&ascp,
  170. NO_ERROR);
  171. SetNetworkNak(resptr, contextp);
  172. rc = FALSE;
  173. }
  174. else
  175. {
  176. // router is not installed or net number is unique
  177. memcpy(contextp->Config.Network, optptr + OPTIONH_DATA, 4);
  178. }
  179. }
  180. }
  181. else
  182. {
  183. // recvdnet is smaller or equal with the local net
  184. if(recvdnet < localnet) {
  185. // as per RFC - return the highest network number
  186. SetNetworkNak(resptr, contextp);
  187. rc = FALSE;
  188. }
  189. }
  190. }
  191. break;
  192. case SNDNAK_OPTION:
  193. // this option has not been requested by the remote end.
  194. // Force it to request in a NAK
  195. SetNetworkNak(resptr, contextp);
  196. GETLONG2ULONG(&localnet, contextp->Config.Network);
  197. TraceIpx(OPTIONS_TRACE, "NetworkNumberHandler: SND NAK to force request for net 0x%x\n", localnet);
  198. rc = FALSE;
  199. break;
  200. default:
  201. SS_ASSERT(FALSE);
  202. break;
  203. }
  204. return rc;
  205. }
  206. BOOL
  207. NodeNumberHandler(PUCHAR optptr,
  208. PIPXCP_CONTEXT contextp,
  209. PUCHAR resptr,
  210. OPT_ACTION Action)
  211. {
  212. BOOL rc = TRUE;
  213. switch(Action) {
  214. case SNDREQ_OPTION:
  215. SetOptionTypeAndLength(optptr, IPX_NODE_NUMBER, 8);
  216. memcpy(optptr + OPTIONH_DATA, contextp->Config.LocalNode, 6);
  217. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: SND REQ with local node %.2x%.2x%.2x%.2x%.2x%.2x\n",
  218. contextp->Config.LocalNode[0],
  219. contextp->Config.LocalNode[1],
  220. contextp->Config.LocalNode[2],
  221. contextp->Config.LocalNode[3],
  222. contextp->Config.LocalNode[4],
  223. contextp->Config.LocalNode[5]);
  224. break;
  225. case RCVNAK_OPTION:
  226. // If this is server config, then the client has rejected
  227. // our local node number. Ignore the suggestion
  228. // to use a new one. We will not negociate
  229. if(!contextp->Config.ConnectionClient)
  230. break;
  231. // If we are the client, then we'll be happy to accept
  232. // whatever the server assigns us.
  233. memcpy(contextp->Config.LocalNode, optptr + OPTIONH_DATA, 6);
  234. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: RCV NAK accepted. New local node %.2x%.2x%.2x%.2x%.2x%.2x\n",
  235. contextp->Config.LocalNode[0],
  236. contextp->Config.LocalNode[1],
  237. contextp->Config.LocalNode[2],
  238. contextp->Config.LocalNode[3],
  239. contextp->Config.LocalNode[4],
  240. contextp->Config.LocalNode[5]);
  241. break;
  242. case RCVACK_OPTION:
  243. if(memcmp(optptr + OPTIONH_DATA, contextp->Config.LocalNode, 6)) {
  244. rc = FALSE;
  245. }
  246. break;
  247. case RCVREQ_OPTION:
  248. // Is it legal to consider node options at this time?
  249. if(contextp->RouteState == ROUTE_ACTIVATED) {
  250. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: rcv req in re-negociation\n");
  251. if(memcmp(contextp->Config.RemoteNode, optptr + OPTIONH_DATA, 6)) {
  252. SetNodeNak(resptr, contextp);
  253. rc = FALSE;
  254. }
  255. break;
  256. }
  257. // Check if the remote machine has specified any node number
  258. if(!memcmp(optptr + OPTIONH_DATA, nullnode, 6)) {
  259. // the remote node wants us to specify its node number.
  260. SetNodeNak(resptr, contextp);
  261. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: RCV REQ with remote node 0x0, snd NAK with remote node %.2x%.2x%.2x%.2x%.2x%.2x\n",
  262. contextp->Config.RemoteNode[0],
  263. contextp->Config.RemoteNode[1],
  264. contextp->Config.RemoteNode[2],
  265. contextp->Config.RemoteNode[3],
  266. contextp->Config.RemoteNode[4],
  267. contextp->Config.RemoteNode[5]);
  268. rc = FALSE;
  269. }
  270. // Otherwise go through the process of determining whether we
  271. // are able/willing to accept the remote node number suggested.
  272. else {
  273. // If we have been set up as the ras server to reject the request for
  274. // a specific node number, do so here.
  275. if ( (GlobalConfig.AcceptRemoteNodeNumber == 0) &&
  276. (contextp->InterfaceType == IF_TYPE_WAN_WORKSTATION) &&
  277. (memcmp(contextp->Config.RemoteNode, optptr + OPTIONH_DATA, 6)) )
  278. {
  279. SetNodeNak(resptr, contextp);
  280. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: RCV REQ with remote client node but we force a specific node, snd NAK with remote node %.2x%.2x%.2x%.2x%.2x%.2x\n",
  281. contextp->Config.RemoteNode[0],
  282. contextp->Config.RemoteNode[1],
  283. contextp->Config.RemoteNode[2],
  284. contextp->Config.RemoteNode[3],
  285. contextp->Config.RemoteNode[4],
  286. contextp->Config.RemoteNode[5]);
  287. rc = FALSE;
  288. }
  289. // else, if we are a ras server set up with a global network and the client
  290. // requests a specific node number (different from our suggestion), then accept
  291. // or reject the node based on whether that node is unique in the global network.
  292. else if ( (!contextp->Config.ConnectionClient) &&
  293. (contextp->InterfaceType == IF_TYPE_WAN_WORKSTATION) &&
  294. (memcmp(contextp->Config.RemoteNode, optptr + OPTIONH_DATA, 6)) &&
  295. (GlobalConfig.RParams.EnableGlobalWanNet) )
  296. {
  297. ACQUIRE_DATABASE_LOCK;
  298. // remove the present node from the node HT
  299. RemoveFromNodeHT(contextp);
  300. // check the remote node is unique
  301. if(NodeIsUnique(optptr + OPTIONH_DATA)) {
  302. // copy this value in the context buffer
  303. memcpy(contextp->Config.RemoteNode, optptr + OPTIONH_DATA, 6);
  304. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: RCV REQ with remote client node different, ACCEPT it\n");
  305. }
  306. else {
  307. // proposed node not unique -> NAK it
  308. SetNodeNak(resptr, contextp);
  309. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: RCV REQ with non unique remote client node, snd NAK with remote node %.2x%.2x%.2x%.2x%.2x%.2x\n",
  310. contextp->Config.RemoteNode[0],
  311. contextp->Config.RemoteNode[1],
  312. contextp->Config.RemoteNode[2],
  313. contextp->Config.RemoteNode[3],
  314. contextp->Config.RemoteNode[4],
  315. contextp->Config.RemoteNode[5]);
  316. rc = FALSE;
  317. }
  318. // add node to HT
  319. AddToNodeHT(contextp);
  320. RELEASE_DATABASE_LOCK;
  321. }
  322. // Otherwise, it's ok to accept the node number that the other side
  323. // requests. This is true for ras clients, ras servers that don't enforce
  324. // specific node numbers, and ras server that don't assign the same
  325. // network number to every dialed in client.
  326. else
  327. {
  328. memcpy(contextp->Config.RemoteNode, optptr + OPTIONH_DATA, 6);
  329. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: RCV REQ with remote node %.2x%.2x%.2x%.2x%.2x%.2x, accepted\n",
  330. contextp->Config.RemoteNode[0],
  331. contextp->Config.RemoteNode[1],
  332. contextp->Config.RemoteNode[2],
  333. contextp->Config.RemoteNode[3],
  334. contextp->Config.RemoteNode[4],
  335. contextp->Config.RemoteNode[5]);
  336. }
  337. }
  338. break;
  339. case SNDNAK_OPTION:
  340. // the remote node didn't specify this parameter as a desired
  341. // parameter. We suggest it what to specify in a further REQ
  342. SetNodeNak(resptr, contextp);
  343. TraceIpx(OPTIONS_TRACE, "NodeNumberHandler: SND NAK to force the remote to request node %.2x%.2x%.2x%.2x%.2x%.2x\n",
  344. contextp->Config.RemoteNode[0],
  345. contextp->Config.RemoteNode[1],
  346. contextp->Config.RemoteNode[2],
  347. contextp->Config.RemoteNode[3],
  348. contextp->Config.RemoteNode[4],
  349. contextp->Config.RemoteNode[5]);
  350. rc = FALSE;
  351. break;
  352. default:
  353. SS_ASSERT(FALSE);
  354. break;
  355. }
  356. return rc;
  357. }
  358. BOOL
  359. RoutingProtocolHandler(PUCHAR optptr,
  360. PIPXCP_CONTEXT contextp,
  361. PUCHAR resptr,
  362. OPT_ACTION Action)
  363. {
  364. USHORT RoutingProtocol;
  365. BOOL rc = TRUE;
  366. switch(Action) {
  367. case SNDREQ_OPTION:
  368. SetOptionTypeAndLength(optptr, IPX_ROUTING_PROTOCOL, 4);
  369. PUTUSHORT2SHORT(optptr + OPTIONH_DATA, (USHORT)RIP_SAP_ROUTING);
  370. break;
  371. case RCVNAK_OPTION:
  372. // if this option get NAK-ed, we ignore any other suggestions
  373. // for it
  374. break;
  375. case RCVACK_OPTION:
  376. GETSHORT2USHORT(&RoutingProtocol, optptr + OPTIONH_DATA);
  377. if(RoutingProtocol != RIP_SAP_ROUTING) {
  378. rc = FALSE;
  379. }
  380. break;
  381. case RCVREQ_OPTION:
  382. GETSHORT2USHORT(&RoutingProtocol, optptr + OPTIONH_DATA);
  383. if(RoutingProtocol != RIP_SAP_ROUTING) {
  384. SetOptionTypeAndLength(resptr, IPX_ROUTING_PROTOCOL, 4);
  385. PUTUSHORT2SHORT(resptr + OPTIONH_DATA, (USHORT)RIP_SAP_ROUTING);
  386. rc = FALSE;
  387. }
  388. break;
  389. case SNDNAK_OPTION:
  390. SetOptionTypeAndLength(resptr, IPX_ROUTING_PROTOCOL, 4);
  391. PUTUSHORT2SHORT(resptr + OPTIONH_DATA, (USHORT)RIP_SAP_ROUTING);
  392. rc = FALSE;
  393. break;
  394. default:
  395. SS_ASSERT(FALSE);
  396. break;
  397. }
  398. return rc;
  399. }
  400. BOOL
  401. CompressionProtocolHandler(PUCHAR optptr,
  402. PIPXCP_CONTEXT contextp,
  403. PUCHAR resptr,
  404. OPT_ACTION Action)
  405. {
  406. USHORT CompressionProtocol;
  407. BOOL rc = TRUE;
  408. switch(Action) {
  409. case SNDREQ_OPTION:
  410. SetOptionTypeAndLength(optptr, IPX_COMPRESSION_PROTOCOL, 4);
  411. PUTUSHORT2SHORT(optptr + OPTIONH_DATA, (USHORT)TELEBIT_COMPRESSED_IPX);
  412. break;
  413. case RCVNAK_OPTION:
  414. // if this option gets NAK-ed it means that the remote node doesn't
  415. // support Telebit compression but supports another type of compression
  416. // that we don't support. In this case we turn off compression negotiation.
  417. break;
  418. case RCVACK_OPTION:
  419. GETSHORT2USHORT(&CompressionProtocol, optptr + OPTIONH_DATA);
  420. if(CompressionProtocol != TELEBIT_COMPRESSED_IPX) {
  421. rc = FALSE;
  422. }
  423. else
  424. {
  425. // Our compression option got ACK-ed by the other end. This means that
  426. // we can receive compressed packets and have to set the receive
  427. // compression on our end.
  428. contextp->SetReceiveCompressionProtocol = TRUE;
  429. }
  430. break;
  431. case RCVREQ_OPTION:
  432. // if we have already negotiated and this is a renegociation, stick by
  433. // what we have already told the stack in line-up
  434. if(contextp->RouteState == ROUTE_ACTIVATED) {
  435. TraceIpx(OPTIONS_TRACE, "CompressionProtocolHandler: rcv req in re-negociation\n");
  436. }
  437. GETSHORT2USHORT(&CompressionProtocol, optptr + OPTIONH_DATA);
  438. if(CompressionProtocol != TELEBIT_COMPRESSED_IPX) {
  439. if(resptr) {
  440. SetOptionTypeAndLength(resptr, IPX_COMPRESSION_PROTOCOL, 4);
  441. PUTUSHORT2SHORT(resptr + OPTIONH_DATA, (USHORT)TELEBIT_COMPRESSED_IPX);
  442. }
  443. rc = FALSE;
  444. }
  445. else
  446. {
  447. // The remote requests the supported compression option and we ACK it.
  448. // This means it can receive compressed packets and we have to
  449. // set the send compression on our end.
  450. contextp->SetSendCompressionProtocol = TRUE;
  451. }
  452. break;
  453. default:
  454. SS_ASSERT(FALSE);
  455. break;
  456. }
  457. return rc;
  458. }
  459. BOOL
  460. ConfigurationCompleteHandler(PUCHAR optptr,
  461. PIPXCP_CONTEXT contextp,
  462. PUCHAR resptr,
  463. OPT_ACTION Action)
  464. {
  465. BOOL rc = TRUE;
  466. switch(Action) {
  467. case SNDREQ_OPTION:
  468. SetOptionTypeAndLength(optptr, IPX_CONFIGURATION_COMPLETE, 2);
  469. break;
  470. case RCVNAK_OPTION:
  471. // if this option gets NAK-ed we ignore any other suggestions
  472. case RCVREQ_OPTION:
  473. case RCVACK_OPTION:
  474. break;
  475. case SNDNAK_OPTION:
  476. SetOptionTypeAndLength(resptr, IPX_CONFIGURATION_COMPLETE, 2);
  477. rc = FALSE;
  478. break;
  479. default:
  480. SS_ASSERT(FALSE);
  481. break;
  482. }
  483. return rc;
  484. }
  485. VOID
  486. CopyOption(PUCHAR dstptr,
  487. PUCHAR srcptr)
  488. {
  489. USHORT optlen;
  490. optlen = *(srcptr + OPTIONH_LENGTH);
  491. memcpy(dstptr, srcptr, optlen);
  492. }
  493. VOID
  494. SetOptionTypeAndLength(PUCHAR dstptr,
  495. UCHAR opttype,
  496. UCHAR optlen)
  497. {
  498. *(dstptr + OPTIONH_TYPE) = opttype;
  499. *(dstptr + OPTIONH_LENGTH) = optlen;
  500. }
  501. VOID
  502. SetNetworkNak(PUCHAR resptr,
  503. PIPXCP_CONTEXT contextp)
  504. {
  505. SetOptionTypeAndLength(resptr, IPX_NETWORK_NUMBER, 6);
  506. memcpy(resptr + OPTIONH_DATA, contextp->Config.Network, 4);
  507. contextp->NetNumberNakSentCount++;
  508. }
  509. VOID
  510. SetNodeNak(PUCHAR resptr,
  511. PIPXCP_CONTEXT contextp)
  512. {
  513. SetOptionTypeAndLength(resptr, IPX_NODE_NUMBER, 8);
  514. memcpy(resptr + OPTIONH_DATA, contextp->Config.RemoteNode, 6);
  515. }