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.

2904 lines
82 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. arap.c
  5. Abstract:
  6. This module implements routines specific to ARAP
  7. Author:
  8. Shirish Koti
  9. Revision History:
  10. 15 Nov 1996 Initial Version
  11. --*/
  12. #include <atalk.h>
  13. #pragma hdrstop
  14. #define FILENUM ARAP
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, ArapProcessIoctl)
  17. #pragma alloc_text(PAGE_ARAP, ArapMarkConnectionUp)
  18. #pragma alloc_text(PAGE_ARAP, ArapIoctlRecv)
  19. #pragma alloc_text(PAGE_ARAP, ArapExchangeParms)
  20. #pragma alloc_text(PAGE_ARAP, ArapConnect)
  21. #pragma alloc_text(PAGE_ARAP, ArapConnectComplete)
  22. #pragma alloc_text(PAGE_ARAP, ArapDisconnect)
  23. #pragma alloc_text(PAGE_ARAP, ArapGetAddr)
  24. #pragma alloc_text(PAGE_ARAP, ArapGetStats)
  25. #pragma alloc_text(PAGE_ARAP, ArapIoctlSend)
  26. #pragma alloc_text(PAGE_ARAP, ArapSendPrepare)
  27. #pragma alloc_text(PAGE_ARAP, ArapMnpSendComplete)
  28. #pragma alloc_text(PAGE_ARAP, ArapIoctlSendComplete)
  29. #pragma alloc_text(PAGE_ARAP, ArapDataToDll)
  30. #pragma alloc_text(PAGE_ARAP, MnpSendAckIfReqd)
  31. #pragma alloc_text(PAGE_ARAP, MnpSendLNAck)
  32. #pragma alloc_text(PAGE_ARAP, ArapSendLDPacket)
  33. #pragma alloc_text(PAGE_ARAP, ArapRetryTimer)
  34. #endif
  35. //***
  36. //
  37. // Function: ArapProcessIoctl
  38. // Process all ioctls coming from the Ras-ARAP module
  39. //
  40. // Parameters: pIrp - the irp to process
  41. //
  42. // Return: result of the operation
  43. //
  44. //***$
  45. NTSTATUS
  46. ArapProcessIoctl(
  47. IN PIRP pIrp
  48. )
  49. {
  50. NTSTATUS status=STATUS_SUCCESS;
  51. PIO_STACK_LOCATION pIrpSp;
  52. ULONG IoControlCode;
  53. PARAP_SEND_RECV_INFO pSndRcvInfo=NULL;
  54. PATCPCONN pAtcpConn=NULL;
  55. PARAPCONN pArapConn=NULL;
  56. ATALK_NODEADDR ClientNode;
  57. DWORD dwBytesToDll;
  58. DWORD dwOrgIrql;
  59. DWORD dwFlags;
  60. DWORD dwInputBufLen;
  61. DWORD dwOutputBufLen;
  62. BOOLEAN fDerefDefPort=FALSE;
  63. NTSTATUS ReturnStatus=STATUS_SUCCESS;
  64. PAGED_CODE ();
  65. dwOrgIrql = KeGetCurrentIrql();
  66. ASSERT(dwOrgIrql < DISPATCH_LEVEL);
  67. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  68. IoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
  69. dwInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  70. dwOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  71. ARAPTRACE(("Entered ArapProcessIoctl (%lx %lx)\n",pIrp, IoControlCode));
  72. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  73. if (!pSndRcvInfo)
  74. {
  75. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  76. ("ArapProcessIoctl: SystemBuffer is NULL!! (ioctl = %lx,pIrp = %lx)\n",
  77. pIrp,IoControlCode));
  78. ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
  79. return( ReturnStatus );
  80. }
  81. if (dwInputBufLen < sizeof(ARAP_SEND_RECV_INFO))
  82. {
  83. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  84. ("ArapProcessIoctl: irp %lx, too small input buffer (%d bytes)!\n",
  85. pIrp,dwInputBufLen));
  86. ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
  87. return( ReturnStatus );
  88. }
  89. if (dwOutputBufLen < sizeof(ARAP_SEND_RECV_INFO))
  90. {
  91. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  92. ("ArapProcessIoctl: irp %lx, too small output buffer (%d bytes)!\n",
  93. pIrp,dwOutputBufLen));
  94. ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
  95. return( ReturnStatus );
  96. }
  97. //
  98. // handle PPP (ATCP) ioctls separately
  99. //
  100. if ((IoControlCode == IOCTL_ATCP_SETUP_CONNECTION) ||
  101. (IoControlCode == IOCTL_ATCP_SUPPRESS_BCAST) ||
  102. (IoControlCode == IOCTL_ATCP_CLOSE_CONNECTION))
  103. {
  104. if (IoControlCode == IOCTL_ATCP_SETUP_CONNECTION)
  105. {
  106. AtalkLockPPPIfNecessary();
  107. ReturnStatus = PPPProcessIoctl(pIrp, pSndRcvInfo, IoControlCode, NULL);
  108. return (ReturnStatus);
  109. }
  110. else
  111. {
  112. ClientNode.atn_Network = pSndRcvInfo->ClientAddr.ata_Network;
  113. ClientNode.atn_Node = (BYTE)pSndRcvInfo->ClientAddr.ata_Node;
  114. if (ClientNode.atn_Node != 0)
  115. {
  116. // find the right connection
  117. pAtcpConn = FindAndRefPPPConnByAddr(ClientNode, &dwFlags);
  118. }
  119. else
  120. {
  121. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  122. ("ArapProcessIoctl: excuse me? Node is 0! Irp=%lx\n",pIrp));
  123. ASSERT(0);
  124. }
  125. if (pAtcpConn)
  126. {
  127. PPPProcessIoctl(pIrp, pSndRcvInfo, IoControlCode, pAtcpConn);
  128. // remove the refcount put in by FindAndRefPPPConnByAddr
  129. DerefPPPConn(pAtcpConn);
  130. }
  131. else
  132. {
  133. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  134. ("ArapProcessIoctl: PPP Ioctl %lx but can't find conn %x.%x\n",
  135. IoControlCode,pSndRcvInfo->ClientAddr.ata_Network,
  136. pSndRcvInfo->ClientAddr.ata_Node));
  137. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  138. ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO),
  139. STATUS_SUCCESS, &ReturnStatus);
  140. return (ReturnStatus);
  141. }
  142. }
  143. return( STATUS_SUCCESS);
  144. }
  145. //
  146. // NOTE: ALL THE ARAP CODE IS NOW DEFUNCT. To minimize code-churn, only small changes
  147. // are done to disable ARAP. At some point in time, all the code needs to be cleaned up
  148. // so ARAP-specific stuff is completely removed
  149. //
  150. else
  151. {
  152. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  153. ("ArapProcessIoctl: ARAP not supported anymore!!\n"));
  154. ASSERT(0);
  155. ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
  156. return( ReturnStatus );
  157. }
  158. if (!ArapAcceptIrp(pIrp, IoControlCode, &fDerefDefPort))
  159. {
  160. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  161. ("ArapProcessIoctl: irp %lx not accepted (%lx)\n", pIrp,IoControlCode));
  162. ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
  163. // remove that IrpProcess refcount
  164. if (fDerefDefPort)
  165. {
  166. AtalkPortDereference(AtalkDefaultPort);
  167. }
  168. return( ReturnStatus);
  169. }
  170. if ((IoControlCode != IOCTL_ARAP_EXCHANGE_PARMS) &&
  171. (IoControlCode != IOCTL_ARAP_GET_ZONE_LIST))
  172. {
  173. pArapConn = pSndRcvInfo->AtalkContext;
  174. }
  175. //
  176. // if ths irp is for a specific connection, validate the connection first!
  177. //
  178. if ((pArapConn != NULL) && (!ArapConnIsValid(pArapConn)))
  179. {
  180. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  181. ("ArapProcessIoctl: conn %lx is gone! (ioctl = %lx)\n",
  182. pArapConn,IoControlCode));
  183. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  184. ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
  185. // remove that IrpProcess refcount
  186. if (fDerefDefPort)
  187. {
  188. AtalkPortDereference(AtalkDefaultPort);
  189. }
  190. return( ReturnStatus);
  191. }
  192. dwBytesToDll = sizeof(ARAP_SEND_RECV_INFO);
  193. // in most likelihood, we're going to return pending: mark it so
  194. IoMarkIrpPending(pIrp);
  195. switch (IoControlCode)
  196. {
  197. //
  198. // receive parameters from the user-level, and return some of our own
  199. //
  200. case IOCTL_ARAP_EXCHANGE_PARMS:
  201. // exchange of parms: if not already done, lock arap pages
  202. AtalkLockArapIfNecessary();
  203. status = ArapExchangeParms( pIrp );
  204. dwBytesToDll = sizeof(EXCHGPARMS);
  205. // exchange of parms done: unlock if possible
  206. AtalkUnlockArapIfNecessary();
  207. break;
  208. case IOCTL_ARAP_SETUP_CONNECTION:
  209. // new connection being established: if not already done, lock arap pages
  210. AtalkLockArapIfNecessary();
  211. pSndRcvInfo->StatusCode = ARAPERR_NO_ERROR;
  212. status = STATUS_SUCCESS;
  213. break;
  214. //
  215. // setup the low level arap connection link (aka Point-to-Point Link)
  216. // (first time client dials in, we respond. At callback, we initiate;
  217. // at callback time, we initiate the connection here)
  218. //
  219. case IOCTL_ARAP_MNP_CONN_RESPOND:
  220. case IOCTL_ARAP_MNP_CONN_INITIATE:
  221. status = ArapConnect( pIrp, IoControlCode );
  222. break;
  223. //
  224. // obtain (or make up) an appletalk address for the client and return it
  225. //
  226. case IOCTL_ARAP_GET_ADDR:
  227. status = ArapGetAddr( pIrp );
  228. break;
  229. //
  230. // just mark the Arap connection as being established
  231. //
  232. case IOCTL_ARAP_CONNECTION_UP:
  233. status = ArapMarkConnectionUp( pIrp );
  234. break;
  235. //
  236. // dll wants the connection blown away: disconnect it
  237. //
  238. case IOCTL_ARAP_DISCONNECT:
  239. status = ArapDisconnect( pIrp );
  240. break;
  241. //
  242. // send the buffer given by the dll
  243. //
  244. case IOCTL_ARAP_SEND:
  245. status = ArapIoctlSend( pIrp );
  246. break;
  247. //
  248. // "direct irp": get data for the connection specified
  249. //
  250. case IOCTL_ARAP_RECV:
  251. status = ArapIoctlRecv( pIrp );
  252. break;
  253. //
  254. // "select irp": get data if there is for any connection
  255. //
  256. case IOCTL_ARAP_SELECT:
  257. status = ArapProcessSelect( pIrp );
  258. break;
  259. #if DBG
  260. //
  261. // "sniff irp": return all the sniff info
  262. //
  263. case IOCTL_ARAP_SNIFF_PKTS:
  264. status = ArapProcessSniff( pIrp );
  265. break;
  266. #endif
  267. //
  268. // engine wants the select irp unblocked (either because it's shutting
  269. // down or because we want to shutdown)
  270. //
  271. case IOCTL_ARAP_CONTINUE_SHUTDOWN:
  272. ArapUnblockSelect();
  273. status = STATUS_SUCCESS;
  274. break;
  275. //
  276. // get names of all the zones in the entire network
  277. //
  278. case IOCTL_ARAP_GET_ZONE_LIST:
  279. ArapZipGetZoneStat( (PZONESTAT)pSndRcvInfo );
  280. // (-4 to avoid 4 bytes from ZoneNames[1] field)
  281. dwBytesToDll = ((PZONESTAT)pSndRcvInfo)->BufLen + sizeof(ZONESTAT) - 4;
  282. status = STATUS_SUCCESS;
  283. break;
  284. default:
  285. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  286. ("ArapProcessIoctl: Invalid Request %lx\n", IoControlCode));
  287. status = STATUS_INVALID_PARAMETER;
  288. }
  289. if( status != STATUS_PENDING )
  290. {
  291. pIrpSp->Control &= ~SL_PENDING_RETURNED;
  292. ARAP_COMPLETE_IRP(pIrp, dwBytesToDll, STATUS_SUCCESS, &ReturnStatus);
  293. status = ReturnStatus;
  294. }
  295. //
  296. // if this irp was for a specific connection, validation refcount was put
  297. // on it: take that away
  298. //
  299. if (pArapConn)
  300. {
  301. DerefArapConn(pArapConn);
  302. }
  303. // remove that IrpProcess refcount
  304. if (fDerefDefPort)
  305. {
  306. AtalkPortDereference(AtalkDefaultPort);
  307. }
  308. ASSERT(KeGetCurrentIrql() == dwOrgIrql);
  309. return( status );
  310. }
  311. //***
  312. //
  313. // Function: ArapMarkConnectionUp
  314. // Set the flags in our connection to mark that Arap connection
  315. // has been established (by the dll) (we don't route until this
  316. // happens)
  317. //
  318. // Parameters: pIrp - the irp to process
  319. //
  320. // Return: result of the operation
  321. //
  322. //***$
  323. NTSTATUS
  324. ArapMarkConnectionUp(
  325. IN PIRP pIrp
  326. )
  327. {
  328. PARAPCONN pArapConn;
  329. PARAP_SEND_RECV_INFO pSndRcvInfo;
  330. KIRQL OldIrql;
  331. DBG_ARAP_CHECK_PAGED_CODE();
  332. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  333. pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
  334. if (pArapConn == NULL)
  335. {
  336. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  337. ("ArapMarkConnectionUp: null conn\n"));
  338. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  339. return(STATUS_SUCCESS);
  340. }
  341. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  342. (" Yippeee! %s connection is up! (%x.%x @%lx)\n",
  343. (pArapConn->Flags & ARAP_V20_CONNECTION)? "ARAP v2.0":"ARAP v1.0",
  344. pArapConn->NetAddr.atn_Network,pArapConn->NetAddr.atn_Node,pArapConn));
  345. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  346. pArapConn->Flags |= ARAP_CONNECTION_UP;
  347. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  348. pSndRcvInfo->StatusCode = ARAPERR_NO_ERROR;
  349. return( STATUS_SUCCESS );
  350. }
  351. //***
  352. //
  353. // Function: ArapIoctlRecv
  354. // Try to get data for the specified connection. If there is no
  355. // data available, irp is just "queued"
  356. //
  357. // Parameters: pIrp - the irp to process
  358. //
  359. // Return: result of the operation
  360. //
  361. //***$
  362. NTSTATUS
  363. ArapIoctlRecv(
  364. IN PIRP pIrp
  365. )
  366. {
  367. PARAPCONN pArapConn;
  368. PARAP_SEND_RECV_INFO pSndRcvInfo;
  369. KIRQL OldIrql;
  370. DBG_ARAP_CHECK_PAGED_CODE();
  371. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  372. pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
  373. if (pArapConn == NULL)
  374. {
  375. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  376. ("ArapIoctlRecv: null conn\n"));
  377. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  378. return(STATUS_SUCCESS);
  379. }
  380. ARAPTRACE(("Entered ArapIoctlRecv (%lx %lx)\n",pIrp,pArapConn));
  381. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  382. if (pArapConn->State >= MNP_LDISCONNECTING)
  383. {
  384. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  385. ("ArapIoctlRecv: rejecting recv ioctl recvd during disconnect %lx\n", pArapConn));
  386. pSndRcvInfo->StatusCode = ARAPERR_DISCONNECT_IN_PROGRESS;
  387. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  388. return(STATUS_SUCCESS);
  389. }
  390. // we only allow one irp to be in progress at a time
  391. if (pArapConn->pRecvIoctlIrp != NULL)
  392. {
  393. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapIoctlRecv: rejecting recv \
  394. (irp already in progress) %lx\n", pArapConn));
  395. pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
  396. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  397. return(STATUS_SUCCESS);
  398. }
  399. pArapConn->pRecvIoctlIrp = pIrp;
  400. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  401. // see if we can satisfy this request
  402. ArapDataToDll( pArapConn );
  403. return( STATUS_PENDING );
  404. }
  405. //***
  406. //
  407. // Function: ArapExchangeParms
  408. // Get configuration parameters from the dll, and return some info
  409. //
  410. // Parameters: pIrp - the irp to process
  411. //
  412. // Return: result of the operation
  413. //
  414. //***$
  415. NTSTATUS
  416. ArapExchangeParms(
  417. IN PIRP pIrp
  418. )
  419. {
  420. ZONESTAT ZoneStat;
  421. KIRQL OldIrql;
  422. PADDRMGMT pAddrMgmt;
  423. PEXCHGPARMS pExchgParms;
  424. DBG_ARAP_CHECK_PAGED_CODE();
  425. ARAPTRACE(("Entered ArapExchangeParms (%lx)\n",pIrp));
  426. pExchgParms = (PEXCHGPARMS)pIrp->AssociatedIrp.SystemBuffer;
  427. // we enter this routine only if AtalkDefaultPort is referenced
  428. ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
  429. ArapGlobs.LowVersion = pExchgParms->Parms.LowVersion;
  430. ArapGlobs.HighVersion = pExchgParms->Parms.HighVersion;
  431. ArapGlobs.MnpInactiveTime = pExchgParms->Parms.MnpInactiveTime;
  432. ArapGlobs.V42bisEnabled = pExchgParms->Parms.V42bisEnabled;
  433. ArapGlobs.SmartBuffEnabled = pExchgParms->Parms.SmartBuffEnabled;
  434. ArapGlobs.NetworkAccess = pExchgParms->Parms.NetworkAccess;
  435. ArapGlobs.DynamicMode = pExchgParms->Parms.DynamicMode;
  436. ArapGlobs.NetRange.LowEnd = pExchgParms->Parms.NetRange.LowEnd;
  437. ArapGlobs.NetRange.HighEnd = pExchgParms->Parms.NetRange.HighEnd;
  438. ArapGlobs.MaxLTFrames = (BYTE)pExchgParms->Parms.MaxLTFrames;
  439. ArapGlobs.SniffMode = pExchgParms->Parms.SniffMode;
  440. ArapGlobs.pAddrMgmt = NULL;
  441. // we only support dynamic mode
  442. ASSERT(ArapGlobs.DynamicMode);
  443. #if ARAP_STATIC_MODE
  444. //
  445. // allocate and initialize the bitmap for node allocation
  446. //
  447. if (!(ArapGlobs.DynamicMode))
  448. {
  449. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
  450. if (!ArapValidNetrange(ArapGlobs.NetRange))
  451. {
  452. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  453. ("ArapExchangeParms: Netrange %lx - %lx is invalid\n",
  454. ArapGlobs.NetRange.LowEnd,ArapGlobs.NetRange.HighEnd));
  455. pExchgParms->StatusCode = ARAPERR_BAD_NETWORK_RANGE;
  456. return (STATUS_SUCCESS);
  457. }
  458. ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
  459. if ( (pAddrMgmt = AtalkAllocZeroedMemory(sizeof(ADDRMGMT))) == NULL)
  460. {
  461. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  462. ("ArapExchangeParms: alloc for pAddrMgmt failed\n"));
  463. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
  464. pExchgParms->StatusCode = ARAPERR_OUT_OF_RESOURCES;
  465. return (STATUS_SUCCESS);
  466. }
  467. //
  468. // node numbers 0 and 255 are reserved, so mark them as occupied.
  469. //
  470. pAddrMgmt->NodeBitMap[0] |= 0x1;
  471. pAddrMgmt->NodeBitMap[31] |= 0x80;
  472. pAddrMgmt->Network = ArapGlobs.NetRange.LowEnd;
  473. ArapGlobs.pAddrMgmt = pAddrMgmt;
  474. }
  475. #endif //ARAP_STATIC_MODE
  476. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
  477. //
  478. // now, time to return some stack info to the dll.
  479. //
  480. // just an initial guess: dll will figure out the real number when an
  481. // actual connection comes in
  482. //
  483. pExchgParms->Parms.NumZones = 50;
  484. pExchgParms->Parms.ServerAddr.ata_Network =
  485. AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Network;
  486. pExchgParms->Parms.ServerAddr.ata_Node =
  487. AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Node;
  488. // copy the server zone in Pascal string format
  489. if (AtalkDesiredZone)
  490. {
  491. pExchgParms->Parms.ServerZone[0] = AtalkDesiredZone->zn_ZoneLen;
  492. RtlCopyMemory( &pExchgParms->Parms.ServerZone[1],
  493. &AtalkDesiredZone->zn_Zone[0],
  494. AtalkDesiredZone->zn_ZoneLen );
  495. }
  496. else if (AtalkDefaultPort->pd_DefaultZone)
  497. {
  498. pExchgParms->Parms.ServerZone[0] = AtalkDefaultPort->pd_DefaultZone->zn_ZoneLen;
  499. RtlCopyMemory( &pExchgParms->Parms.ServerZone[1],
  500. &AtalkDefaultPort->pd_DefaultZone->zn_Zone[0],
  501. AtalkDefaultPort->pd_DefaultZone->zn_ZoneLen );
  502. }
  503. else
  504. {
  505. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  506. ("Arap: Server not in any zone?? Client won't see any zones!!\n"));
  507. pExchgParms->Parms.ServerZone[0] = 0;
  508. }
  509. ArapGlobs.OurNetwkNum =
  510. AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Network;
  511. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  512. ("Arap: ready to accept connections (Router net=%x node=%x)\n",
  513. AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Network,
  514. AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Node));
  515. pExchgParms->StatusCode = ARAPERR_NO_ERROR;
  516. // complete the irp successfully
  517. return (STATUS_SUCCESS);
  518. }
  519. //***
  520. //
  521. // Function: ArapConnect
  522. // Setup the MNP level connection with the client
  523. //
  524. // Parameters: pIrp - the irp to process
  525. //
  526. // Return: result of the operation
  527. //
  528. //***$
  529. NTSTATUS
  530. ArapConnect(
  531. IN PIRP pIrp,
  532. IN ULONG IoControlCode
  533. )
  534. {
  535. KIRQL OldIrql;
  536. PBYTE pFrame;
  537. SHORT MnpLen;
  538. SHORT FrameLen;
  539. DWORD StatusCode=ARAPERR_NO_ERROR;
  540. PMNPSENDBUF pMnpSendBuf=NULL;
  541. PARAP_SEND_RECV_INFO pSndRcvInfo;
  542. PARAPCONN pArapConn;
  543. PNDIS_PACKET ndisPacket;
  544. NDIS_STATUS ndisStatus;
  545. DBG_ARAP_CHECK_PAGED_CODE();
  546. ARAPTRACE(("Entered ArapConnect (%lx)\n",pIrp));
  547. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  548. pArapConn = FindArapConnByContx(pSndRcvInfo->pDllContext);
  549. if (pArapConn == NULL)
  550. {
  551. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  552. ("ArapConnect: couldn't find pArapConn!\n"));
  553. ASSERT(0);
  554. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  555. return(STATUS_SUCCESS);
  556. }
  557. ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
  558. ArapConnections++;
  559. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
  560. #if ARAP_STATIC_MODE
  561. // This will add a route (one-time only) for the ARAP network range
  562. ArapAddArapRoute();
  563. #endif //ARAP_STATIC_MODE
  564. // first, write stack's context for dll's future use
  565. pSndRcvInfo->AtalkContext = (PVOID)pArapConn;
  566. //
  567. // put a refcount for the connection (deref only when the connection gets
  568. // disconnected *and* the dll is told about it).
  569. // Also, initialize the v42bis stuff for this connection
  570. //
  571. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  572. if (pArapConn->pIoctlIrp != NULL)
  573. {
  574. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapConnect: rejecting connect \
  575. (irp already in progress) %lx\n", pArapConn));
  576. pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
  577. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  578. return(STATUS_SUCCESS);
  579. }
  580. ASSERT(pArapConn->State == MNP_IDLE);
  581. if (IoControlCode == IOCTL_ARAP_MNP_CONN_RESPOND)
  582. {
  583. pArapConn->State = MNP_RESPONSE;
  584. }
  585. //
  586. // we're doing callback: do some fixing up
  587. //
  588. else
  589. {
  590. pArapConn->State = MNP_REQUEST;
  591. pArapConn->Flags |= ARAP_CALLBACK_MODE;
  592. pArapConn->MnpState.SendCredit = 8;
  593. }
  594. // Connect refcount: remove only after we tell dll that connection died
  595. pArapConn->RefCount++;
  596. // put MNPSend refcount
  597. pArapConn->RefCount++;
  598. pArapConn->pIoctlIrp = pIrp;
  599. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  600. KeInitializeEvent(&pArapConn->NodeAcquireEvent, NotificationEvent, FALSE);
  601. StatusCode = ARAPERR_NO_ERROR;
  602. //
  603. // allocate buf to send out the connection response/request
  604. //
  605. if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
  606. {
  607. // get an ndis packet for this puppy
  608. StatusCode = ArapGetNdisPacket(pMnpSendBuf);
  609. }
  610. if ((pMnpSendBuf == NULL) || (StatusCode != ARAPERR_NO_ERROR))
  611. {
  612. if (pMnpSendBuf)
  613. {
  614. ArapNdisFreeBuf(pMnpSendBuf);
  615. }
  616. else
  617. {
  618. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  619. ("ArapConnect: AtalkBPAllocBlock failed on %lx\n", pArapConn));
  620. }
  621. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  622. pArapConn->State = MNP_IDLE;
  623. pSndRcvInfo->StatusCode = ARAPERR_OUT_OF_RESOURCES;
  624. pSndRcvInfo->AtalkContext = ARAP_INVALID_CONTEXT;
  625. pArapConn->pIoctlIrp = NULL;
  626. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  627. // didn't succeed: remove that connection refcount
  628. DerefArapConn(pArapConn);
  629. // and the MNPSend refcount
  630. DerefArapConn(pArapConn);
  631. // return success: we have already set our StatusCode to the right thing
  632. return( STATUS_SUCCESS );
  633. }
  634. #if DBG
  635. pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
  636. #endif
  637. // yes, we need this, in case we bail out
  638. InitializeListHead(&pMnpSendBuf->Linkage);
  639. pMnpSendBuf->SeqNum = 0; // Indication code expects this to be 0
  640. pMnpSendBuf->RetryCount = 1;
  641. pMnpSendBuf->RefCount = 1; // 1 MNP refcount
  642. pMnpSendBuf->pArapConn = pArapConn;
  643. pMnpSendBuf->ComplRoutine = ArapConnectComplete;
  644. pMnpSendBuf->Flags = 1;
  645. // when should we retransmit this pkt?
  646. pMnpSendBuf->RetryTime = pArapConn->SendRetryTime + AtalkGetCurrentTick();
  647. pFrame = &pMnpSendBuf->Buffer[0];
  648. AtalkNdisBuildARAPHdr(pFrame, pArapConn);
  649. pFrame += WAN_LINKHDR_LEN;
  650. FrameLen = WAN_LINKHDR_LEN;
  651. //
  652. // are we just responding to a connection request?
  653. //
  654. if (IoControlCode == IOCTL_ARAP_MNP_CONN_RESPOND)
  655. {
  656. //
  657. // pSndRcvInfo contains the client's connect request. Parse it and
  658. // prepare a response as appropriate
  659. //
  660. ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
  661. StatusCode = PrepareConnectionResponse( pArapConn,
  662. &pSndRcvInfo->Data[0],
  663. pSndRcvInfo->DataLen,
  664. pFrame,
  665. &MnpLen);
  666. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
  667. if (StatusCode != ARAPERR_NO_ERROR)
  668. {
  669. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  670. ("ArapConnect: (%lx) response prep failed %ld\n", pArapConn,StatusCode));
  671. ArapConnectComplete(pMnpSendBuf, StatusCode);
  672. return( STATUS_PENDING );
  673. }
  674. FrameLen += MnpLen;
  675. }
  676. //
  677. // no, actually we are initiating a connection (callback time)
  678. // copy the frame we used in earlier setup (that dll kindly saved for us)
  679. //
  680. else
  681. {
  682. RtlCopyMemory(pFrame, (PBYTE)&pSndRcvInfo->Data[0], pSndRcvInfo->DataLen);
  683. FrameLen += (USHORT)pSndRcvInfo->DataLen;
  684. #if DBG
  685. pArapConn->MnpState.SynByte = pSndRcvInfo->Data[0];
  686. pArapConn->MnpState.DleByte = pSndRcvInfo->Data[1];
  687. pArapConn->MnpState.StxByte = pSndRcvInfo->Data[2];
  688. pArapConn->MnpState.EtxByte = MNP_ETX;
  689. #endif
  690. }
  691. AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
  692. pMnpSendBuf->RefCount++; // 1 ndis count, since we'll send now
  693. pMnpSendBuf->DataSize = FrameLen;
  694. NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,
  695. pMnpSendBuf->DataSize);
  696. // put this connection response on the retransmission queue
  697. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  698. InsertTailList(&pArapConn->RetransmitQ, &pMnpSendBuf->Linkage);
  699. pArapConn->SendsPending += pMnpSendBuf->DataSize;
  700. pArapConn->MnpState.UnAckedSends++;
  701. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  702. ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
  703. NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
  704. // if there was a problem sending, call the completion routine here
  705. // retransmit logic will send it again
  706. //
  707. if (ndisStatus != NDIS_STATUS_PENDING)
  708. {
  709. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  710. ("MnpSendAck: NdisSend failed %lx\n",ndisStatus));
  711. ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
  712. }
  713. //
  714. // done. we'll complete the irp when the client responds (acks or response)
  715. //
  716. return( STATUS_PENDING );
  717. }
  718. //***
  719. //
  720. // Function: ArapConnectComplete
  721. // Completion routine for the ArapConnect routine. This routine
  722. // is called by the ArapRcvComplete routine when we get an ack
  723. // for our Connection response (LR) frame
  724. //
  725. // Parameters: pMnpSendBuf - the send buff that contained the LR response
  726. // StatusCode - how did it go?
  727. //
  728. // Return: none
  729. //
  730. //***$
  731. VOID
  732. ArapConnectComplete(
  733. IN PMNPSENDBUF pMnpSendBuf,
  734. IN DWORD StatusCode
  735. )
  736. {
  737. KIRQL OldIrql;
  738. PIRP pIrp;
  739. PARAPCONN pArapConn;
  740. PARAP_SEND_RECV_INFO pSndRcvInfo;
  741. NTSTATUS ReturnStatus=STATUS_SUCCESS;
  742. DBG_ARAP_CHECK_PAGED_CODE();
  743. pArapConn = pMnpSendBuf->pArapConn;
  744. if (StatusCode != ARAPERR_NO_ERROR)
  745. {
  746. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  747. ("ArapConnectComplete: (%x): conn setup failed (%d)!\n",
  748. pArapConn,StatusCode));
  749. //
  750. // BUGBUG: change ArapCleanup to accept StatusCode as a parm (currently,
  751. // the real reason behind disconnect is lost, so dll doesn't get it)
  752. //
  753. ArapCleanup(pArapConn);
  754. DerefMnpSendBuf(pMnpSendBuf, FALSE);
  755. return;
  756. }
  757. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  758. pIrp = pArapConn->pIoctlIrp;
  759. pArapConn->pIoctlIrp = NULL;
  760. pArapConn->SendsPending -= pMnpSendBuf->DataSize;
  761. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  762. ARAPTRACE(("Entered ArapConnectComplete (%lx %lx)\n",pIrp,pArapConn));
  763. // if there is an irp (under normal conditions, should be), complete it
  764. if (pIrp)
  765. {
  766. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  767. pSndRcvInfo->StatusCode = StatusCode;
  768. if (StatusCode != ARAPERR_NO_ERROR)
  769. {
  770. pSndRcvInfo->StatusCode = ARAPERR_DISCONNECT_IN_PROGRESS;
  771. }
  772. //
  773. // copy the frame we used to establish the connection. In case of
  774. // callback, dll will pass this back to initiate the connection
  775. //
  776. if (pSndRcvInfo->IoctlCode == IOCTL_ARAP_MNP_CONN_RESPOND)
  777. {
  778. pSndRcvInfo->DataLen = (DWORD)pMnpSendBuf->DataSize;
  779. RtlCopyMemory((PBYTE)&pSndRcvInfo->Data[0],
  780. (PBYTE)&pMnpSendBuf->Buffer[0],
  781. (DWORD)pMnpSendBuf->DataSize);
  782. }
  783. ARAP_COMPLETE_IRP(pIrp,
  784. pSndRcvInfo->DataLen + sizeof(ARAP_SEND_RECV_INFO),
  785. STATUS_SUCCESS, &ReturnStatus);
  786. }
  787. else
  788. {
  789. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  790. ("ArapConnectComplete: (%x): no irp available!\n",pArapConn));
  791. }
  792. DerefMnpSendBuf(pMnpSendBuf, FALSE);
  793. }
  794. //***
  795. //
  796. // Function: ArapDisconnect
  797. // Disconnect the connection
  798. //
  799. // Parameters: pIrp - the irp to process
  800. //
  801. // Return: result of the operation
  802. //
  803. //***$
  804. NTSTATUS
  805. ArapDisconnect(
  806. IN PIRP pIrp
  807. )
  808. {
  809. PARAPCONN pArapConn;
  810. PARAP_SEND_RECV_INFO pSndRcvInfo;
  811. DBG_ARAP_CHECK_PAGED_CODE();
  812. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  813. pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
  814. if ((pArapConn == NULL) || (pArapConn == ARAP_INVALID_CONTEXT))
  815. {
  816. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  817. ("ArapDisconnect: null conn\n"));
  818. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  819. return(STATUS_SUCCESS);
  820. }
  821. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  822. ("ArapDisconnect: rcvd DISCONNECT on %lx (irp=%lx)\n",pArapConn,pIrp));
  823. // UserCode = 0xFF
  824. pSndRcvInfo->StatusCode = ArapSendLDPacket(pArapConn, 0xFF);
  825. ArapCleanup(pArapConn);
  826. //
  827. // done. let this irp complete: we'll notify the dll of
  828. // 'disconnect-complete' (via select irp) when our cleanup completes
  829. //
  830. return(STATUS_SUCCESS);
  831. }
  832. //***
  833. //
  834. // Function: ArapGetAddr
  835. // Get a network address for the remote client
  836. // (if doing dynamic addressing, go to the net; otherwise, get one
  837. // from the table we maintain)
  838. //
  839. // Parameters: pIrp - the irp to process
  840. //
  841. // Return: result of the operation
  842. //
  843. //***$
  844. NTSTATUS
  845. ArapGetAddr(
  846. IN PIRP pIrp
  847. )
  848. {
  849. PARAPCONN pArapConn;
  850. PARAP_SEND_RECV_INFO pSndRcvInfo;
  851. DWORD StatusCode = ARAPERR_NO_NETWORK_ADDR;
  852. DBG_ARAP_CHECK_PAGED_CODE();
  853. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  854. pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
  855. ARAPTRACE(("Entered ArapGetAddr (%lx %lx)\n",pIrp,pArapConn));
  856. if (pArapConn == NULL)
  857. {
  858. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  859. ("ArapGetAddr: null conn\n"));
  860. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  861. return(STATUS_SUCCESS);
  862. }
  863. if (ArapGlobs.DynamicMode)
  864. {
  865. StatusCode = ArapGetDynamicAddr(pArapConn);
  866. }
  867. #if ARAP_STATIC_MODE
  868. else
  869. {
  870. StatusCode = ArapGetStaticAddr(pArapConn);
  871. }
  872. #endif //ARAP_STATIC_MODE
  873. pSndRcvInfo->StatusCode = StatusCode;
  874. if (StatusCode == ARAPERR_NO_ERROR)
  875. {
  876. pSndRcvInfo->ClientAddr.ata_Network = pArapConn->NetAddr.atn_Network;
  877. pSndRcvInfo->ClientAddr.ata_Node = pArapConn->NetAddr.atn_Node;
  878. }
  879. else
  880. {
  881. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  882. ("ArapGetAddr: returning %d\n", StatusCode));
  883. }
  884. return( STATUS_SUCCESS );
  885. }
  886. // we don't really support this: why have the code!
  887. #if 0
  888. //***
  889. //
  890. // Function: ArapGetStats
  891. // Return statistics (bytes in, bytes out, compressed etc.) about
  892. // the specified connection
  893. //
  894. // Parameters: pIrp - the irp to process
  895. //
  896. // Return: result of the operation
  897. //
  898. //***$
  899. NTSTATUS
  900. ArapGetStats(
  901. IN PIRP pIrp
  902. )
  903. {
  904. PARAPCONN pArapConn;
  905. PARAP_SEND_RECV_INFO pSndRcvInfo;
  906. KIRQL OldIrql;
  907. PSTAT_INFO pStatInfo;
  908. DBG_ARAP_CHECK_PAGED_CODE();
  909. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  910. pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
  911. if (pArapConn == NULL)
  912. {
  913. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  914. ("ArapGetStats: null conn\n"));
  915. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  916. return(STATUS_SUCCESS);
  917. }
  918. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  919. ("ArapGetStats: returning stats for (%lx)\n",pArapConn));
  920. pStatInfo = (PSTAT_INFO)&pSndRcvInfo->Data[0];
  921. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  922. *pStatInfo = pArapConn->StatInfo;
  923. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  924. pSndRcvInfo->StatusCode = ARAPERR_NO_ERROR;
  925. return( STATUS_SUCCESS );
  926. }
  927. #endif // #if 0 around ArapGetStats
  928. //***
  929. //
  930. // Function: ArapIoctlSend
  931. // Send the buffer given by the dll to the remote client.
  932. // This routine calls the routine to prepare the send (v42bis
  933. // compression and MNP bookkeeping) and then sends it out
  934. //
  935. // Parameters: pIrp - the irp to process
  936. //
  937. // Return: result of the operation
  938. //
  939. //***$
  940. NTSTATUS
  941. ArapIoctlSend(
  942. IN PIRP pIrp
  943. )
  944. {
  945. KIRQL OldIrql;
  946. BUFFER_DESC OrgBuffDesc;
  947. PARAPCONN pArapConn;
  948. PARAP_SEND_RECV_INFO pSndRcvInfo;
  949. DWORD StatusCode=ARAPERR_NO_ERROR;
  950. DBG_ARAP_CHECK_PAGED_CODE();
  951. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  952. pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
  953. if (pArapConn == NULL)
  954. {
  955. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  956. ("ArapIoctlSend: null conn\n"));
  957. pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
  958. return(STATUS_SUCCESS);
  959. }
  960. ARAPTRACE(("Entered ArapIoctlSend (%lx %lx)\n",pIrp,pArapConn));
  961. // save the irp so we can complete it in the completion routine
  962. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  963. // we only allow one irp to be in progress at a time
  964. if (pArapConn->pIoctlIrp != NULL)
  965. {
  966. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapIoctlSend: rejecting send \
  967. (irp already in progress) %lx\n", pArapConn));
  968. pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
  969. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  970. return(STATUS_SUCCESS);
  971. }
  972. pArapConn->pIoctlIrp = pIrp;
  973. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  974. ASSERT(pSndRcvInfo->DataLen <= 618);
  975. DBGDUMPBYTES("Dll send:", &pSndRcvInfo->Data[0],pSndRcvInfo->DataLen,1);
  976. //
  977. // get the send ready (compression, MNP bookkeeping etc.)
  978. //
  979. OrgBuffDesc.bd_Next = NULL;
  980. OrgBuffDesc.bd_Length = (SHORT)pSndRcvInfo->DataLen;
  981. OrgBuffDesc.bd_CharBuffer = &pSndRcvInfo->Data[0];
  982. OrgBuffDesc.bd_Flags = BD_CHAR_BUFFER;
  983. StatusCode = ArapSendPrepare( pArapConn,
  984. &OrgBuffDesc,
  985. ARAP_SEND_PRIORITY_HIGH );
  986. if (StatusCode == ARAPERR_NO_ERROR)
  987. {
  988. //
  989. // now, send that send over. Note that we don't care about the return
  990. // code here: if this particular send fails, we still tell the dll that
  991. // the send succeeded because our retransmission logic will take care
  992. // of ensuring that the send gets there.
  993. //
  994. ArapNdisSend( pArapConn, &pArapConn->HighPriSendQ );
  995. }
  996. else
  997. {
  998. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  999. ("ArapIoctlSend (%lx): ArapSendPrepare failed (%ld)\n",
  1000. pArapConn,StatusCode));
  1001. }
  1002. ArapIoctlSendComplete(StatusCode, pArapConn);
  1003. return( STATUS_PENDING );
  1004. }
  1005. //***
  1006. //
  1007. // Function: ArapProcessSelect
  1008. // Process the select irp issued by the dll
  1009. // This routine saves the select irp so that any connection that
  1010. // needs it can take it. Also, it sees if any of the connections
  1011. // is waiting for an irp to indicate a disconnect-complete or
  1012. // data to the dll. If so, that is completed here.
  1013. //
  1014. // Parameters: pIrp - the select irp to process
  1015. //
  1016. // Return: result of the operation
  1017. //
  1018. //***$
  1019. NTSTATUS
  1020. ArapProcessSelect(
  1021. IN PIRP pIrp
  1022. )
  1023. {
  1024. KIRQL OldIrql;
  1025. KIRQL OldIrql2;
  1026. PARAPCONN pDiscArapConn=NULL;
  1027. PARAPCONN pRcvArapConn=NULL;
  1028. PARAP_SEND_RECV_INFO pSndRcvInfo;
  1029. PLIST_ENTRY pList;
  1030. DWORD dwBytesToDll;
  1031. DWORD StatusCode;
  1032. NTSTATUS ReturnStatus;
  1033. ARAPTRACE(("Entered ArapProcessSelect (%lx)\n",pIrp));
  1034. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  1035. pDiscArapConn = NULL;
  1036. pRcvArapConn = NULL;
  1037. //
  1038. // it's possible that between the time the last select irp completed and
  1039. // this select came down, some activity that needs a select irp occured
  1040. // (e.g. a disconnect). See if we have hit such a condition
  1041. //
  1042. ArapDelayedNotify(&pDiscArapConn, &pRcvArapConn);
  1043. //
  1044. // if we found an arapconn that was waiting for a select irp to notify the
  1045. // dll of disconnect, do the good deed!
  1046. //
  1047. if (pDiscArapConn)
  1048. {
  1049. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1050. ("ArapProcessSelect: completing delayed disconnect on %lx!\n", pDiscArapConn));
  1051. dwBytesToDll = 0;
  1052. #if DBG
  1053. //
  1054. // if we have some sniff info that we couldn't deliver earlier through
  1055. // the sniff irp, then give them through this irp: it's going back
  1056. // "empty" anyway!
  1057. //
  1058. if (pDiscArapConn->pDbgTraceBuffer && pDiscArapConn->SniffedBytes > 0)
  1059. {
  1060. dwBytesToDll = ArapFillIrpWithSniffInfo(pDiscArapConn,pIrp);
  1061. }
  1062. #endif
  1063. dwBytesToDll += sizeof(ARAP_SEND_RECV_INFO);
  1064. //
  1065. // no need for spinlock here
  1066. //
  1067. if (pDiscArapConn->Flags & ARAP_REMOTE_DISCONN)
  1068. {
  1069. StatusCode = ARAPERR_RDISCONNECT_COMPLETE;
  1070. }
  1071. else
  1072. {
  1073. StatusCode = ARAPERR_LDISCONNECT_COMPLETE;
  1074. }
  1075. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  1076. pSndRcvInfo->pDllContext = pDiscArapConn->pDllContext;
  1077. pSndRcvInfo->StatusCode = StatusCode;
  1078. pSndRcvInfo->DataLen = dwBytesToDll;
  1079. // we told (rather, will very shortly tell) dll: remove this link
  1080. pDiscArapConn->pDllContext = NULL;
  1081. // now that we told dll, remove 1 refcount
  1082. DerefArapConn( pDiscArapConn );
  1083. return(STATUS_SUCCESS);
  1084. }
  1085. IoAcquireCancelSpinLock(&OldIrql);
  1086. if (pIrp->Cancel)
  1087. {
  1088. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1089. ("ArapProcessSelect: select irp %lx already cancelled!\n", pIrp));
  1090. IoReleaseCancelSpinLock(OldIrql);
  1091. ARAP_COMPLETE_IRP(pIrp, 0, STATUS_CANCELLED, &ReturnStatus);
  1092. return(ReturnStatus);
  1093. }
  1094. ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql2);
  1095. if (ArapSelectIrp != NULL)
  1096. {
  1097. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1098. ("ArapProcessSelect: select irp %lx already in progress!\n", ArapSelectIrp));
  1099. ASSERT(0);
  1100. pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
  1101. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql2);
  1102. IoReleaseCancelSpinLock(OldIrql);
  1103. return( STATUS_SUCCESS );
  1104. }
  1105. //
  1106. // does arap engine need to be told about some change?
  1107. //
  1108. if ( (ArapStackState == ARAP_STATE_ACTIVE_WAITING) ||
  1109. (ArapStackState == ARAP_STATE_INACTIVE_WAITING) )
  1110. {
  1111. if (ArapStackState == ARAP_STATE_ACTIVE_WAITING)
  1112. {
  1113. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1114. ("ArapProcessSelect: delayed notify: stack is now active!\n"));
  1115. ArapStackState = ARAP_STATE_ACTIVE;
  1116. pSndRcvInfo->StatusCode = ARAPERR_STACK_IS_ACTIVE;
  1117. }
  1118. else if (ArapStackState == ARAP_STATE_INACTIVE_WAITING)
  1119. {
  1120. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1121. ("ArapProcessSelect: delayed notify: stack is now inactive!\n"));
  1122. ArapStackState = ARAP_STATE_INACTIVE;
  1123. pSndRcvInfo->StatusCode = ARAPERR_STACK_IS_NOT_ACTIVE;
  1124. }
  1125. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql2);
  1126. IoReleaseCancelSpinLock(OldIrql);
  1127. return( STATUS_SUCCESS );
  1128. }
  1129. //
  1130. // ok, most common case: we just need to stash this select irp!
  1131. //
  1132. ArapSelectIrp = pIrp;
  1133. RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql2);
  1134. IoSetCancelRoutine(pIrp, (PDRIVER_CANCEL)AtalkTdiCancel);
  1135. IoReleaseCancelSpinLock(OldIrql);
  1136. //
  1137. // if there was an arapconn waiting for a select irp, pass on the data!
  1138. //
  1139. if (pRcvArapConn)
  1140. {
  1141. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
  1142. ("ArapProcessSelect: getting delayed data on %lx at %ld\n",
  1143. pRcvArapConn,AtalkGetCurrentTick()));
  1144. ARAP_DBG_TRACE(pRcvArapConn,11105,0,0,0,0);
  1145. ArapDataToDll( pRcvArapConn );
  1146. }
  1147. return(STATUS_PENDING);
  1148. }
  1149. //***
  1150. //
  1151. // Function: ArapDelayedNotify
  1152. // This routine checks to see if any of the arap connections was
  1153. // waiting for a select irp to come down to notify the dll that
  1154. // either the connection went away, or if there was any data waiting on a
  1155. // connection.
  1156. //
  1157. // Parameters: ppDiscArapConn - if a "disconnected" connection exists, it's returned
  1158. // in this pointer. If many exist, the first one lucks out.
  1159. // If none exists, null is returned here
  1160. // ppRecvArapConn - same as above except that the connection returned is
  1161. // the one where some data is waiting
  1162. //
  1163. // Return: none
  1164. //
  1165. //***$
  1166. VOID
  1167. ArapDelayedNotify(
  1168. OUT PARAPCONN *ppDiscArapConn,
  1169. OUT PARAPCONN *ppRecvArapConn
  1170. )
  1171. {
  1172. KIRQL OldIrql;
  1173. PARAPCONN pArapConn=NULL;
  1174. PLIST_ENTRY pList;
  1175. PARAPCONN pDiscArapConn=NULL;
  1176. PARAPCONN pRecvArapConn=NULL;
  1177. *ppDiscArapConn = NULL;
  1178. *ppRecvArapConn = NULL;
  1179. if (!RasPortDesc)
  1180. {
  1181. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1182. ("ArapDelayedNotify: RasPortDesc is NULL!\n"));
  1183. ASSERT(0);
  1184. return;
  1185. }
  1186. ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
  1187. pList = RasPortDesc->pd_ArapConnHead.Flink;
  1188. while (pList != &RasPortDesc->pd_ArapConnHead)
  1189. {
  1190. pArapConn = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
  1191. pList = pArapConn->Linkage.Flink;
  1192. ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
  1193. //
  1194. // if a connection has been disconnected and is waiting for a select
  1195. // irp to show up, find out who that is and let the caller know
  1196. //
  1197. if ((pArapConn->State == MNP_DISCONNECTED) &&
  1198. (pArapConn->Flags & DISCONNECT_NO_IRP))
  1199. {
  1200. pArapConn->Flags &= ~DISCONNECT_NO_IRP;
  1201. pDiscArapConn = pArapConn;
  1202. RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
  1203. break;
  1204. }
  1205. //
  1206. // if a connection has some data come in on it while select irp wasn't
  1207. // down yet, note down this connection
  1208. //
  1209. if ((pArapConn->State == MNP_UP) &&
  1210. (pArapConn->Flags & ARAP_CONNECTION_UP) &&
  1211. (!IsListEmpty(&pArapConn->ArapDataQ)))
  1212. {
  1213. pRecvArapConn = pArapConn;
  1214. }
  1215. RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
  1216. }
  1217. RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock,OldIrql);
  1218. if (pDiscArapConn)
  1219. {
  1220. *ppDiscArapConn = pDiscArapConn;
  1221. }
  1222. else if (pRecvArapConn)
  1223. {
  1224. *ppRecvArapConn = pRecvArapConn;
  1225. }
  1226. }
  1227. //***
  1228. //
  1229. // Function: ArapSendPrepare
  1230. // This routine takes an incoming buffer descriptor, compresses
  1231. // each of the buffers in it and passes the compressed data on to
  1232. // another routine which splits (or stuffs) the compressed bytes
  1233. // into MNP-level packets.
  1234. //
  1235. // Parameters: pArapConn - the connection in question
  1236. // pOrgBuffDesc - the buffer descriptor containing data buffer(s)
  1237. // Priority - how important is the data (highest priority = 1)
  1238. // 1 - directed DDP dgrams (all except NBP)
  1239. // 2 - directed DDP dgrams (NBP)
  1240. // 3 - all DDP-level broadcast (NBP only)
  1241. //
  1242. // Return: ARAPERR_NO_ERROR if things go well, otherwise errorcode
  1243. //
  1244. //***$
  1245. DWORD
  1246. ArapSendPrepare(
  1247. IN PARAPCONN pArapConn,
  1248. IN PBUFFER_DESC pOrgBuffDesc,
  1249. IN DWORD Priority
  1250. )
  1251. {
  1252. KIRQL OldIrql;
  1253. DWORD StatusCode=ARAPERR_NO_ERROR;
  1254. SHORT EthLen, MnpLen;
  1255. PBYTE pCurrBuff;
  1256. DWORD CurrBuffLen;
  1257. DWORD UncompressedDataLen;
  1258. PBYTE pCompressedData;
  1259. PBYTE pCompressedDataBuffer;
  1260. DWORD CompressedDataLen;
  1261. DWORD CDataLen;
  1262. PBUFFER_DESC pBuffDesc;
  1263. DWORD CompBufDataSize;
  1264. DBG_ARAP_CHECK_PAGED_CODE();
  1265. // BUGBUG: this line put in for now: remove it and make sure priority queue stuff works
  1266. Priority = ARAP_SEND_PRIORITY_HIGH;
  1267. ARAPTRACE(("Entered ArapSendPrepare (%lx %lx)\n",pArapConn,pOrgBuffDesc));
  1268. //
  1269. // it's essential to hold this lock until the entire send is compressed and
  1270. // put on the queue (Otherwise, we risk mixing up different sends!)
  1271. //
  1272. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  1273. // are we disconnecting (or not up yet)? if so, don't accept this send
  1274. if (pArapConn->State != MNP_UP)
  1275. {
  1276. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1277. ("ArapSendPrepare: (%lx) state=%d, rejecting send\n",
  1278. pArapConn,pArapConn->State));
  1279. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1280. return( ARAPERR_DISCONNECT_IN_PROGRESS );
  1281. }
  1282. // do we have too many sends queued up? if so, just drop this send
  1283. if (pArapConn->SendsPending > ARAP_SENDQ_UPPER_LIMIT)
  1284. {
  1285. // make sure it's not gone negative..
  1286. ASSERT(pArapConn->SendsPending < 0x100000);
  1287. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1288. return( ARAPERR_OUT_OF_RESOURCES );
  1289. }
  1290. //
  1291. // allocate memory to store the compressed data
  1292. //
  1293. pCompressedDataBuffer = AtalkBPAllocBlock(BLKID_ARAP_SNDPKT);
  1294. if (pCompressedDataBuffer == NULL)
  1295. {
  1296. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1297. ("ArapSendPrepare: alloc for compressing data failed (%lx)\n", pArapConn));
  1298. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1299. return( ARAPERR_OUT_OF_RESOURCES );
  1300. }
  1301. pBuffDesc = pOrgBuffDesc; // first buffer
  1302. CompressedDataLen = 0; // length of compressed data
  1303. CompBufDataSize = ARAP_SENDBUF_SIZE; // size of buffer in which to compress
  1304. pCompressedData = pCompressedDataBuffer; // ptr to buffer in which to compress
  1305. UncompressedDataLen = 0; // size of uncompressed data
  1306. #if DBG
  1307. //
  1308. // put in a guard signature to catch buffer overrun
  1309. //
  1310. *((DWORD *)&(pCompressedDataBuffer[ARAP_SENDBUF_SIZE-4])) = 0xdeadbeef;
  1311. #endif
  1312. //
  1313. // first, walk through the buffer descriptor chain and compress all the
  1314. // buffers.
  1315. //
  1316. while (pBuffDesc)
  1317. {
  1318. //
  1319. // is this a buffer?
  1320. //
  1321. if (pBuffDesc->bd_Flags & BD_CHAR_BUFFER)
  1322. {
  1323. pCurrBuff = pBuffDesc->bd_CharBuffer;
  1324. CurrBuffLen = pBuffDesc->bd_Length;
  1325. }
  1326. //
  1327. // nope, it's an mdl!
  1328. //
  1329. else
  1330. {
  1331. pCurrBuff = MmGetSystemAddressForMdlSafe(
  1332. pBuffDesc->bd_OpaqueBuffer,
  1333. NormalPagePriority);
  1334. if (pCurrBuff == NULL)
  1335. {
  1336. ASSERT(0);
  1337. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1338. AtalkBPFreeBlock(pCompressedDataBuffer);
  1339. return( ARAPERR_OUT_OF_RESOURCES );
  1340. }
  1341. CurrBuffLen = MmGetMdlByteCount(pBuffDesc->bd_OpaqueBuffer);
  1342. }
  1343. DBGDUMPBYTES("ArapSendPrepare (current buffer): ",pCurrBuff,CurrBuffLen,2);
  1344. UncompressedDataLen += CurrBuffLen;
  1345. ASSERT(UncompressedDataLen <= ARAP_LGPKT_SIZE);
  1346. // exclude the 2 srp length bytes
  1347. if (UncompressedDataLen > ARAP_MAXPKT_SIZE_OUTGOING+2)
  1348. {
  1349. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1350. ("ArapSendPrepare (%lx): send pkt exceeds limit\n",pArapConn));
  1351. ASSERT(0);
  1352. }
  1353. //
  1354. // compress the packet (if v42bis is on, that is)
  1355. //
  1356. if (pArapConn->Flags & MNP_V42BIS_NEGOTIATED)
  1357. {
  1358. StatusCode = v42bisCompress(pArapConn,
  1359. pCurrBuff,
  1360. CurrBuffLen,
  1361. pCompressedData,
  1362. CompBufDataSize,
  1363. &CDataLen);
  1364. }
  1365. //
  1366. // hmmm, no v42bis! just copy it as is and skip compression!
  1367. //
  1368. else
  1369. {
  1370. ASSERT(CompBufDataSize >= CurrBuffLen);
  1371. RtlCopyMemory(pCompressedData,
  1372. pCurrBuff,
  1373. CurrBuffLen);
  1374. CDataLen = CurrBuffLen;
  1375. StatusCode = ARAPERR_NO_ERROR;
  1376. }
  1377. #if DBG
  1378. // ... and, check our guard signature
  1379. ASSERT (*((DWORD *)&(pCompressedDataBuffer[ARAP_SENDBUF_SIZE-4])) == 0xdeadbeef);
  1380. #endif
  1381. if (StatusCode != ARAPERR_NO_ERROR)
  1382. {
  1383. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapSendPrepare (%lx):\
  1384. v42bisCompress returned %ld\n", pArapConn,StatusCode));
  1385. ASSERT(0);
  1386. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1387. AtalkBPFreeBlock(pCompressedDataBuffer);
  1388. return(StatusCode);
  1389. }
  1390. pCompressedData += CDataLen;
  1391. CompressedDataLen += CDataLen;
  1392. CompBufDataSize -= CDataLen;
  1393. pBuffDesc = pBuffDesc->bd_Next;
  1394. }
  1395. // we are about to send so many uncompressed bytes: update stats
  1396. pArapConn->StatInfo.BytesTransmittedUncompressed += UncompressedDataLen;
  1397. // this is how many bytes will go out on the wire: update stats
  1398. pArapConn->StatInfo.BytesTransmittedCompressed += CompressedDataLen;
  1399. //
  1400. // this is how many bytes will go out on the wire: update stats
  1401. // Note that we will be adding the start/stop etc. bytes to this count somewhere else
  1402. //
  1403. pArapConn->StatInfo.BytesSent += CompressedDataLen;
  1404. #if DBG
  1405. ArapStatistics.SendPreCompMax =
  1406. (UncompressedDataLen > ArapStatistics.SendPreCompMax)?
  1407. UncompressedDataLen : ArapStatistics.SendPreCompMax;
  1408. ArapStatistics.SendPostCompMax =
  1409. (CompressedDataLen > ArapStatistics.SendPostCompMax)?
  1410. CompressedDataLen : ArapStatistics.SendPostCompMax;
  1411. ArapStatistics.SendPreCompMin =
  1412. (UncompressedDataLen < ArapStatistics.SendPreCompMin)?
  1413. UncompressedDataLen : ArapStatistics.SendPreCompMin;
  1414. ArapStatistics.SendPostCompMin =
  1415. (CompressedDataLen < ArapStatistics.SendPostCompMin)?
  1416. CompressedDataLen : ArapStatistics.SendPostCompMin;
  1417. #endif
  1418. ARAP_DBG_TRACE(pArapConn,11205,pOrgBuffDesc,Priority,0,0);
  1419. // now go put the send on the queue (And yes: hold that lock)
  1420. StatusCode = ArapQueueSendBytes(pArapConn,
  1421. pCompressedDataBuffer,
  1422. CompressedDataLen,
  1423. Priority);
  1424. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1425. AtalkBPFreeBlock(pCompressedDataBuffer);
  1426. return(StatusCode);
  1427. }
  1428. //***
  1429. //
  1430. // Function: ArapMnpSendComplete
  1431. // Free up the buffer used for the MNP send. If the send failed
  1432. // then kill the connection (remember, it's not just one send
  1433. // failing but a failure after all the retransmission jing-bang)
  1434. //
  1435. // Parameters: pMnpSendBuf - the send buff that contained the LR response
  1436. // StatusCode - how did it go?
  1437. //
  1438. // Return: none
  1439. //
  1440. //***$
  1441. VOID ArapMnpSendComplete(
  1442. IN PMNPSENDBUF pMnpSendBuf,
  1443. IN DWORD StatusCode
  1444. )
  1445. {
  1446. PARAPCONN pArapConn;
  1447. DWORD State;
  1448. KIRQL OldIrql;
  1449. DBG_ARAP_CHECK_PAGED_CODE();
  1450. pArapConn = pMnpSendBuf->pArapConn;
  1451. ARAPTRACE(("Entered ArapMnpSendComplete (%lx %lx %lx)\n",
  1452. pMnpSendBuf,StatusCode,pArapConn));
  1453. // the send buffer is getting freed up: update the counter
  1454. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  1455. State = pArapConn->State;
  1456. pArapConn->SendsPending -= pMnpSendBuf->DataSize;
  1457. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1458. if ((StatusCode != ARAPERR_NO_ERROR) && (State < MNP_LDISCONNECTING))
  1459. {
  1460. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1461. ("ArapMnpSendComplete (%lx %lx): bad link? Tearing down connection\n",
  1462. StatusCode,pArapConn));
  1463. // link must have gone down: kill the connection!
  1464. ArapCleanup(pArapConn);
  1465. }
  1466. // mark that compl. routine has run
  1467. #if DBG
  1468. pMnpSendBuf->Signature -= 0x100;
  1469. #endif
  1470. // the send has been acked: take away the MNP refcount on the send
  1471. DerefMnpSendBuf(pMnpSendBuf, FALSE);
  1472. }
  1473. //***
  1474. //
  1475. // Function: ArapIoctlSendComplete
  1476. // This routine is called right after the send is done in
  1477. // ArapIoctlSend, to let the dll know what happened to the send.
  1478. //
  1479. // Parameters: Status - did the send actually succeed
  1480. // pArapConn - the connection in quesion
  1481. //
  1482. // Return: none
  1483. //
  1484. //***$
  1485. VOID
  1486. ArapIoctlSendComplete(
  1487. DWORD StatusCode,
  1488. PARAPCONN pArapConn
  1489. )
  1490. {
  1491. PIRP pIrp;
  1492. KIRQL OldIrql;
  1493. PARAP_SEND_RECV_INFO pSndRcvInfo;
  1494. NTSTATUS ReturnStatus=STATUS_SUCCESS;
  1495. DBG_ARAP_CHECK_PAGED_CODE();
  1496. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  1497. pIrp = pArapConn->pIoctlIrp;
  1498. pArapConn->pIoctlIrp = NULL;
  1499. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1500. ARAPTRACE(("Entered ArapIoctlSendComplete (%lx %lx)\n",pArapConn,pIrp));
  1501. //
  1502. // if there is a user-level irp pending, complete it here
  1503. //
  1504. if (pIrp)
  1505. {
  1506. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  1507. pSndRcvInfo->StatusCode = StatusCode;
  1508. // complete the irp (irp always completes successfully!)
  1509. ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
  1510. }
  1511. }
  1512. //***
  1513. //
  1514. // Function: ArapDataToDll
  1515. // This routine tries to complete a receive posted on a connection.
  1516. // When data arrives, if the Arap connection is established then
  1517. // this routine tries to complete a receive via the "select" irp.
  1518. // If the Arap connection is not yet established, then a receive
  1519. // is completed via a "direct" irp.
  1520. //
  1521. // Parameters: pArapConn - connection element in question
  1522. //
  1523. // Return: Number of bytes transferred to the dll
  1524. //
  1525. //***$
  1526. DWORD
  1527. ArapDataToDll(
  1528. IN PARAPCONN pArapConn
  1529. )
  1530. {
  1531. KIRQL OldIrql;
  1532. PLIST_ENTRY pRcvList;
  1533. PARAPBUF pArapBuf;
  1534. PARAP_SEND_RECV_INFO pSndRcvInfo=NULL;
  1535. PIRP pIrp;
  1536. USHORT SrpModLen;
  1537. DWORD dwBytesToDll;
  1538. DWORD StatusCode;
  1539. NTSTATUS ReturnStatus=STATUS_SUCCESS;
  1540. DBG_ARAP_CHECK_PAGED_CODE();
  1541. ARAPTRACE(("Entered ArapDataToDll (%lx)\n",pArapConn));
  1542. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  1543. if (IsListEmpty(&pArapConn->ArapDataQ))
  1544. {
  1545. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1546. return( 0 );
  1547. }
  1548. pRcvList = pArapConn->ArapDataQ.Flink;
  1549. pArapBuf = CONTAINING_RECORD(pRcvList, ARAPBUF, Linkage);
  1550. //
  1551. // if the ARAP connection is established, we can hand the data only
  1552. // to a select irp (dll won't post direct rcv's anymore)
  1553. //
  1554. if ( pArapConn->Flags & ARAP_CONNECTION_UP )
  1555. {
  1556. ArapGetSelectIrp(&pIrp);
  1557. StatusCode = ARAPERR_DATA;
  1558. }
  1559. //
  1560. // if the ARAP connection is not established yet, we must guarantee that
  1561. // we hand the data only to a direct rcv irp for this connection
  1562. //
  1563. else
  1564. {
  1565. pIrp = pArapConn->pRecvIoctlIrp;
  1566. pArapConn->pRecvIoctlIrp = NULL;
  1567. StatusCode = ARAPERR_NO_ERROR;
  1568. }
  1569. // no irp? just have to wait then
  1570. if (!pIrp)
  1571. {
  1572. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
  1573. ("ArapDataToDll: no select irp, data waiting %lx at %ld\n", pArapConn,AtalkGetCurrentTick()));
  1574. ARAP_DBG_TRACE(pArapConn,11505,0,0,0,0);
  1575. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1576. return( 0 );
  1577. }
  1578. //
  1579. // now that we have irp, fill in the info, after unlinking the recv buf
  1580. //
  1581. RemoveEntryList(&pArapBuf->Linkage);
  1582. ASSERT(pArapConn->RecvsPending >= pArapBuf->DataSize);
  1583. pArapConn->RecvsPending -= pArapBuf->DataSize;
  1584. ARAP_ADJUST_RECVCREDIT(pArapConn);
  1585. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1586. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  1587. ASSERT(pSndRcvInfo->DataLen >= pArapBuf->DataSize);
  1588. SrpModLen = pArapBuf->DataSize;
  1589. // ok, copy the data in
  1590. RtlCopyMemory( &pSndRcvInfo->Data[0],
  1591. pArapBuf->CurrentBuffer,
  1592. pArapBuf->DataSize );
  1593. // set the info (contexts need to be set each time in case of select)
  1594. pSndRcvInfo->AtalkContext = pArapConn;
  1595. pSndRcvInfo->pDllContext = pArapConn->pDllContext;
  1596. pSndRcvInfo->DataLen = SrpModLen;
  1597. pSndRcvInfo->StatusCode = StatusCode;
  1598. dwBytesToDll = SrpModLen + sizeof(ARAP_SEND_RECV_INFO);
  1599. DBGDUMPBYTES("Dll recv:", &pSndRcvInfo->Data[0],pSndRcvInfo->DataLen,1);
  1600. // ok, complete that irp now!
  1601. ARAP_COMPLETE_IRP(pIrp, dwBytesToDll, STATUS_SUCCESS, &ReturnStatus);
  1602. // done with that buffer: free it here
  1603. ARAP_FREE_RCVBUF(pArapBuf);
  1604. return(SrpModLen);
  1605. }
  1606. //***
  1607. //
  1608. // Function: MnpSendAckIfReqd
  1609. // This routine sends an ack to the remote client after making
  1610. // sure that condition(s) do exist warranting sending of an Ack.
  1611. //
  1612. // Parameters: pArapConn - connection element in question
  1613. //
  1614. // Return: none
  1615. //
  1616. //***$
  1617. VOID
  1618. MnpSendAckIfReqd(
  1619. IN PARAPCONN pArapConn,
  1620. IN BOOLEAN fForceAck
  1621. )
  1622. {
  1623. KIRQL OldIrql;
  1624. BYTE SeqToAck;
  1625. BYTE RecvCredit;
  1626. PMNPSENDBUF pMnpSendBuf;
  1627. PBYTE pFrame, pFrameStart;
  1628. BOOLEAN fOptimized=TRUE;
  1629. USHORT FrameLen;
  1630. PNDIS_PACKET ndisPacket;
  1631. NDIS_STATUS ndisStatus;
  1632. DWORD StatusCode;
  1633. BOOLEAN fMustSend;
  1634. DBG_ARAP_CHECK_PAGED_CODE();
  1635. ARAPTRACE(("Entered MnpSendAckIfReqd (%lx)\n",pArapConn));
  1636. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  1637. //
  1638. // if we are not up yet (or are disconnecting), forget about this ack
  1639. //
  1640. if (pArapConn->State != MNP_UP)
  1641. {
  1642. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1643. return;
  1644. }
  1645. fMustSend = FALSE;
  1646. //
  1647. // first, find out if we need to send an ack at all
  1648. //
  1649. //
  1650. // if we are told to send, just send it: don't question the decision!
  1651. //
  1652. if (fForceAck)
  1653. {
  1654. fMustSend = TRUE;
  1655. }
  1656. //
  1657. // spec says if we have one or more unacked pkts and there is no user data
  1658. // to send, then send it (what's user data got to do with this??)
  1659. //
  1660. // BUGBUG: for now, don't check for IsListEmpty(&pArapConn->HighPriSendQ)
  1661. #if 0
  1662. else if ( (pArapConn->MnpState.UnAckedRecvs > 0) &&
  1663. (IsListEmpty(&pArapConn->HighPriSendQ)) )
  1664. {
  1665. fMustSend = TRUE;
  1666. }
  1667. #endif
  1668. else if (pArapConn->MnpState.UnAckedRecvs > 0)
  1669. {
  1670. fMustSend = TRUE;
  1671. }
  1672. //
  1673. // if we haven't acked for a while (i.e. have received more than the
  1674. // acceptable number of unacked packets) then send it
  1675. //
  1676. else if (pArapConn->MnpState.UnAckedRecvs >= pArapConn->MnpState.UnAckedLimit)
  1677. {
  1678. fMustSend = TRUE;
  1679. }
  1680. if (!fMustSend)
  1681. {
  1682. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1683. return;
  1684. }
  1685. StatusCode = ARAPERR_NO_ERROR;
  1686. // first, allocate a buff descriptor (before we change the state variables)
  1687. if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
  1688. {
  1689. StatusCode = ArapGetNdisPacket(pMnpSendBuf);
  1690. }
  1691. if ((pMnpSendBuf == NULL) || (StatusCode != ARAPERR_NO_ERROR))
  1692. {
  1693. if (pMnpSendBuf)
  1694. {
  1695. ArapNdisFreeBuf(pMnpSendBuf);
  1696. }
  1697. else
  1698. {
  1699. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1700. ("MnpSendAckIfReqd: AtalkBPAllocBlock failed on %lx\n", pArapConn))
  1701. }
  1702. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1703. return;
  1704. }
  1705. // BUGBUG: for now, always send full size
  1706. //RecvCredit = pArapConn->MnpState.RecvCredit;
  1707. RecvCredit = pArapConn->MnpState.WindowSize;
  1708. // tell the client which is the last packet we got successfully
  1709. SeqToAck = pArapConn->MnpState.LastSeqRcvd;
  1710. #if DBG
  1711. if ((SeqToAck == pArapConn->MnpState.LastAckSent) && (pArapConn->MnpState.HoleInSeq++ > 1))
  1712. {
  1713. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
  1714. ("MnpSendAckIfReqd: ack %x already sent earlier\n",SeqToAck));
  1715. }
  1716. #endif
  1717. pArapConn->MnpState.LastAckSent = pArapConn->MnpState.LastSeqRcvd;
  1718. // with this ack, we will be acking all the outstanding recv's
  1719. pArapConn->MnpState.UnAckedRecvs = 0;
  1720. // "stop" the 402 timer
  1721. pArapConn->LATimer = 0;
  1722. // reset the flow-control timer
  1723. pArapConn->FlowControlTimer = AtalkGetCurrentTick() +
  1724. pArapConn->T404Duration;
  1725. if (!(pArapConn->Flags & MNP_OPTIMIZED_DATA))
  1726. {
  1727. fOptimized = FALSE;
  1728. }
  1729. ARAP_DBG_TRACE(pArapConn,11605,0,SeqToAck,RecvCredit,0);
  1730. MNP_DBG_TRACE(pArapConn,SeqToAck,MNP_LA);
  1731. // put MNPSend refcount
  1732. pArapConn->RefCount++;
  1733. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1734. #if DBG
  1735. pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
  1736. InitializeListHead(&pMnpSendBuf->Linkage);
  1737. #endif
  1738. pMnpSendBuf->RetryCount = 0; // not relevant here
  1739. pMnpSendBuf->RefCount = 1; // remove when send completes
  1740. pMnpSendBuf->pArapConn = pArapConn;
  1741. pMnpSendBuf->ComplRoutine = NULL;
  1742. pMnpSendBuf->Flags = 1;
  1743. pFrame = pFrameStart = &pMnpSendBuf->Buffer[0];
  1744. AtalkNdisBuildARAPHdr(pFrame, pArapConn);
  1745. pFrame += WAN_LINKHDR_LEN;
  1746. //
  1747. // put the start flags
  1748. //
  1749. *pFrame++ = pArapConn->MnpState.SynByte;
  1750. *pFrame++ = pArapConn->MnpState.DleByte;
  1751. *pFrame++ = pArapConn->MnpState.StxByte;
  1752. //
  1753. // now, put the body of the Ack frame
  1754. //
  1755. if (fOptimized)
  1756. {
  1757. *pFrame++ = 3; // length indication
  1758. *pFrame++ = 5; // type indication
  1759. *pFrame++ = SeqToAck; // Receive seq number ( N(R) )
  1760. *pFrame++ = RecvCredit; // receive credit ( N(k) )
  1761. }
  1762. else
  1763. {
  1764. *pFrame++ = 7; // length indication
  1765. *pFrame++ = 5; // type indication
  1766. *pFrame++ = 1; // var type
  1767. *pFrame++ = 1; // var len
  1768. *pFrame++ = SeqToAck; // receive seq number ( N(R) )
  1769. *pFrame++ = 2; // var type
  1770. *pFrame++ = 1; // var len
  1771. *pFrame++ = RecvCredit; // receive credit ( N(k) )
  1772. }
  1773. //
  1774. // now finally, put the stop flags (no need for spinlock: this won't change!)
  1775. //
  1776. *pFrame++ = pArapConn->MnpState.DleByte;
  1777. *pFrame++ = pArapConn->MnpState.EtxByte;
  1778. FrameLen = (USHORT)(pFrame - pFrameStart);
  1779. AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
  1780. NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,FrameLen);
  1781. //
  1782. // send the packet over. We need to go directly, and not via ArapNdisSend
  1783. // because this packet needs to be delivered just once, regardless of
  1784. // whether send window is open
  1785. //
  1786. ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
  1787. NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
  1788. // if there was a problem sending, call the completion routine here
  1789. if (ndisStatus != NDIS_STATUS_PENDING)
  1790. {
  1791. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1792. ("MnpSendAckIfReqd: NdisSend failed %lx\n",ndisStatus));
  1793. ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
  1794. }
  1795. }
  1796. //***
  1797. //
  1798. // Function: MnpSendLNAck
  1799. // This routine sends an LN ack to the remote client, acknowleding
  1800. // receipt of an LN frame
  1801. //
  1802. // Parameters: pArapConn - connection element in question
  1803. //
  1804. // Return: none
  1805. //
  1806. //***$
  1807. VOID
  1808. MnpSendLNAck(
  1809. IN PARAPCONN pArapConn,
  1810. IN BYTE LnSeqToAck
  1811. )
  1812. {
  1813. KIRQL OldIrql;
  1814. PMNPSENDBUF pMnpSendBuf;
  1815. PBYTE pFrame, pFrameStart;
  1816. USHORT FrameLen;
  1817. PNDIS_PACKET ndisPacket;
  1818. NDIS_STATUS ndisStatus;
  1819. DWORD StatusCode;
  1820. DBG_ARAP_CHECK_PAGED_CODE();
  1821. ARAPTRACE(("Entered MnpSendLNAck (%lx), %d\n",pArapConn,LnSeqToAck));
  1822. StatusCode = ARAPERR_NO_ERROR;
  1823. // first, allocate a buff descriptor
  1824. if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
  1825. {
  1826. StatusCode = ArapGetNdisPacket(pMnpSendBuf);
  1827. }
  1828. if (pMnpSendBuf == NULL || (StatusCode != ARAPERR_NO_ERROR))
  1829. {
  1830. if (pMnpSendBuf)
  1831. {
  1832. ArapNdisFreeBuf(pMnpSendBuf);
  1833. }
  1834. else
  1835. {
  1836. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1837. ("MnpSendLNAck: AtalkBPAllocBlock failed on %lx\n", pArapConn))
  1838. }
  1839. return;
  1840. }
  1841. #if DBG
  1842. pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
  1843. InitializeListHead(&pMnpSendBuf->Linkage);
  1844. #endif
  1845. pMnpSendBuf->RetryCount = 0; // not relevant here
  1846. pMnpSendBuf->RefCount = 1; // remove when send completes
  1847. pMnpSendBuf->pArapConn = pArapConn;
  1848. pMnpSendBuf->ComplRoutine = NULL;
  1849. pMnpSendBuf->Flags = 1;
  1850. pFrame = pFrameStart = &pMnpSendBuf->Buffer[0];
  1851. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  1852. // if we are disconnecting, forget about sending this ack
  1853. if (pArapConn->State >= MNP_LDISCONNECTING)
  1854. {
  1855. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1856. ArapNdisFreeBuf(pMnpSendBuf);
  1857. return;
  1858. }
  1859. // put MNPSend refcount
  1860. pArapConn->RefCount++;
  1861. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1862. AtalkNdisBuildARAPHdr(pFrame, pArapConn);
  1863. pFrame += WAN_LINKHDR_LEN;
  1864. //
  1865. // put the start flags
  1866. //
  1867. *pFrame++ = pArapConn->MnpState.SynByte;
  1868. *pFrame++ = pArapConn->MnpState.DleByte;
  1869. *pFrame++ = pArapConn->MnpState.StxByte;
  1870. //
  1871. // now, put the body of the Ack frame
  1872. //
  1873. *pFrame++ = 4; // length indication
  1874. *pFrame++ = 7; // type indication
  1875. *pFrame++ = 1; // var type
  1876. *pFrame++ = 1; // var len
  1877. *pFrame++ = LnSeqToAck; //
  1878. //
  1879. // now finally, put the stop flags
  1880. //
  1881. *pFrame++ = pArapConn->MnpState.DleByte;
  1882. *pFrame++ = pArapConn->MnpState.EtxByte;
  1883. FrameLen = (USHORT)(pFrame - pFrameStart);
  1884. AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
  1885. NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,FrameLen);
  1886. //
  1887. // send the packet over. We need to go directly, and not via ArapNdisSend
  1888. // because this packet needs to be delivered just once, regardless of
  1889. // whether send window is open
  1890. //
  1891. ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
  1892. NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
  1893. // if there was a problem sending, call the completion routine here
  1894. if (ndisStatus != NDIS_STATUS_PENDING)
  1895. {
  1896. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1897. ("MnpSendLNAck: NdisSend failed %lx\n",ndisStatus));
  1898. ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
  1899. }
  1900. }
  1901. //***
  1902. //
  1903. // Function: ArapSendLDPacket
  1904. // This routine sends a Disconnect (LD) packet to the client
  1905. //
  1906. // Parameters: pArapConn - the connection
  1907. //
  1908. // Return: result of the operation
  1909. //
  1910. //***$
  1911. DWORD
  1912. ArapSendLDPacket(
  1913. IN PARAPCONN pArapConn,
  1914. IN BYTE UserCode
  1915. )
  1916. {
  1917. PBYTE pFrame, pFrameStart;
  1918. USHORT FrameLen;
  1919. PNDIS_PACKET ndisPacket;
  1920. NDIS_STATUS ndisStatus;
  1921. PMNPSENDBUF pMnpSendBuf;
  1922. KIRQL OldIrql;
  1923. DWORD StatusCode;
  1924. DBG_ARAP_CHECK_PAGED_CODE();
  1925. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1926. ("ArapSendLDPacket: sending DISCONNECT on %lx\n",pArapConn));
  1927. StatusCode = ARAPERR_NO_ERROR;
  1928. //
  1929. // allocate buf to send out the disconnection request
  1930. //
  1931. if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
  1932. {
  1933. StatusCode = ArapGetNdisPacket(pMnpSendBuf);
  1934. }
  1935. if ((pMnpSendBuf == NULL) || (StatusCode != ARAPERR_NO_ERROR))
  1936. {
  1937. if (pMnpSendBuf)
  1938. {
  1939. ArapNdisFreeBuf(pMnpSendBuf);
  1940. }
  1941. else
  1942. {
  1943. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  1944. ("ArapSendLDPacket: AtalkBPAllocBlock failed on %lx\n", pArapConn));
  1945. }
  1946. return(ARAPERR_OUT_OF_RESOURCES);
  1947. }
  1948. #if DBG
  1949. pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
  1950. InitializeListHead(&pMnpSendBuf->Linkage);
  1951. #endif
  1952. pMnpSendBuf->RetryCount = 0; // not relevant here
  1953. pMnpSendBuf->RefCount = 1; // remove when send completes
  1954. pMnpSendBuf->pArapConn = pArapConn;
  1955. pMnpSendBuf->ComplRoutine = NULL;
  1956. pMnpSendBuf->Flags = 1;
  1957. ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
  1958. //
  1959. // if we are already disconnecting (say remote disconnected), just say ok
  1960. //
  1961. if (pArapConn->State >= MNP_LDISCONNECTING)
  1962. {
  1963. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapSendLDPacket: silently \
  1964. discarding disconnect (already in progress) %lx\n", pArapConn));
  1965. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1966. ArapNdisFreeBuf(pMnpSendBuf);
  1967. return(ARAPERR_DISCONNECT_IN_PROGRESS);
  1968. }
  1969. // Disconnect refcount: protect pArapConn until disconnect is complete
  1970. pArapConn->RefCount++;
  1971. // put MNPSend refcount
  1972. pArapConn->RefCount++;
  1973. pArapConn->State = MNP_LDISCONNECTING;
  1974. RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
  1975. pFrame = pFrameStart = &pMnpSendBuf->Buffer[0];
  1976. AtalkNdisBuildARAPHdr(pFrame, pArapConn);
  1977. pFrame += WAN_LINKHDR_LEN;
  1978. //
  1979. // put the start flags
  1980. //
  1981. *pFrame++ = pArapConn->MnpState.SynByte;
  1982. *pFrame++ = pArapConn->MnpState.DleByte;
  1983. *pFrame++ = pArapConn->MnpState.StxByte;
  1984. //
  1985. // now, put the body of the LD frame
  1986. //
  1987. *pFrame++ = 7; // length indication
  1988. *pFrame++ = 2; // type indication for LD
  1989. *pFrame++ = 1; // var type
  1990. *pFrame++ = 1; // var len
  1991. *pFrame++ = 0xFF; // User-initiated disconnect
  1992. *pFrame++ = 2; // var type
  1993. *pFrame++ = 1; // var len
  1994. *pFrame++ = UserCode;
  1995. //
  1996. // now finally, put the stop flags
  1997. //
  1998. *pFrame++ = pArapConn->MnpState.DleByte;
  1999. *pFrame++ = pArapConn->MnpState.EtxByte;
  2000. FrameLen = (USHORT)(pFrame - pFrameStart);
  2001. AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
  2002. NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,FrameLen);
  2003. ARAP_SET_NDIS_CONTEXT(pMnpSendBuf, NULL);
  2004. ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
  2005. // send the packet over (and don't bother checking return code!)
  2006. NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
  2007. // if there was a problem sending, call the completion routine here
  2008. if (ndisStatus != NDIS_STATUS_PENDING)
  2009. {
  2010. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2011. ("ArapSendLDPacket: NdisSend failed %lx\n",ndisStatus));
  2012. ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
  2013. }
  2014. // remove the disconnect refcount
  2015. DerefArapConn(pArapConn);
  2016. return(ARAPERR_NO_ERROR);
  2017. }
  2018. //***
  2019. //
  2020. // Function: ArapRetryTimer
  2021. // This is the general purpose timer routine for ARAP.
  2022. // It checks
  2023. // if the ack timer (LATimer) has expired (if yes, send ack)
  2024. // if the flowcontrol timer has expired (if yes, send ack)
  2025. // if the inactivity timer has expired (if yes, send ack)
  2026. // if the retransmit timer has expired (if yes, retransmit)
  2027. //
  2028. // Parameters: pTimer - the context for the timer that just fired
  2029. // TimerShuttingDown - this is TRUE if timer is shutting down
  2030. //
  2031. // Return: none
  2032. //
  2033. //***$
  2034. LONG FASTCALL
  2035. ArapRetryTimer(
  2036. IN PTIMERLIST pTimer,
  2037. IN BOOLEAN TimerShuttingDown
  2038. )
  2039. {
  2040. PARAPCONN pArapConn;
  2041. PLIST_ENTRY pList;
  2042. PMNPSENDBUF pMnpSendBuf;
  2043. BOOLEAN fRetransmit=FALSE;
  2044. BOOLEAN fMustSendAck = FALSE;
  2045. BOOLEAN fKill=FALSE;
  2046. BOOLEAN fMustFlowControl=FALSE;
  2047. BOOLEAN fInactiveClient=FALSE;
  2048. LONG CurrentTime;
  2049. PIRP pIrp=NULL;
  2050. NTSTATUS ReturnStatus=STATUS_SUCCESS;
  2051. DBG_ARAP_CHECK_PAGED_CODE();
  2052. pArapConn = CONTAINING_RECORD(pTimer, ARAPCONN, RetryTimer);
  2053. ARAPTRACE(("Entered ArapRetryTimer (%lx)\n",pArapConn));
  2054. ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
  2055. //
  2056. // if the global timer is shutting down, or if the connection isn't in the
  2057. // right state (e.g. it is disconnecting), then don't requeue the timer
  2058. //
  2059. if ( TimerShuttingDown ||
  2060. (pArapConn->State <= MNP_IDLE) || (pArapConn->State > MNP_UP) )
  2061. {
  2062. pArapConn->Flags &= ~RETRANSMIT_TIMER_ON;
  2063. RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
  2064. if (TimerShuttingDown)
  2065. {
  2066. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2067. ("ArapRetryTimer: timer shut down, killing conn (%lx)\n",pArapConn));
  2068. ArapCleanup(pArapConn);
  2069. }
  2070. else
  2071. {
  2072. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2073. ("ArapRetryTimer: (%lx) invalid state (%d), not requeing timer\n",
  2074. pArapConn,pArapConn->State));
  2075. }
  2076. // remove the timer refcount
  2077. DerefArapConn(pArapConn);
  2078. return ATALK_TIMER_NO_REQUEUE;
  2079. }
  2080. CurrentTime = AtalkGetCurrentTick();
  2081. //
  2082. // has the 402 timer expired? if yes, we must send an ack
  2083. // (a value of 0 signifies that the 402 timer is not "running")
  2084. //
  2085. if ( (pArapConn->LATimer != 0) && (CurrentTime >= pArapConn->LATimer) )
  2086. {
  2087. //
  2088. // make sure there is a receive that needs to be acked (if sent the ack
  2089. // just before this timer fired, don't send the ack again)
  2090. //
  2091. if (pArapConn->MnpState.UnAckedRecvs)
  2092. {
  2093. fMustSendAck = TRUE;
  2094. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2095. ("ArapRetryTimer: 402 timer fired, forcing ack out (%d, now %d)\n",
  2096. pArapConn->LATimer,CurrentTime));
  2097. }
  2098. else
  2099. {
  2100. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2101. ("ArapRetryTimer: saved on on ack (UnAckedRecvs = 0)\n",pArapConn));
  2102. }
  2103. }
  2104. //
  2105. // has the flow control timer "expired"? If so, we must send an ack and
  2106. // reset the timer
  2107. // (a value of 0 signifies that the flow control timer is not "running")
  2108. //
  2109. else if ( (pArapConn->FlowControlTimer != 0) &&
  2110. (CurrentTime >= pArapConn->FlowControlTimer) )
  2111. {
  2112. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
  2113. ("ArapRetryTimer: flow-control timer, forcing ack (%d, now %d)\n",
  2114. pArapConn->FlowControlTimer,CurrentTime));
  2115. fMustFlowControl = TRUE;
  2116. pArapConn->FlowControlTimer = CurrentTime + pArapConn->T404Duration;
  2117. }
  2118. //
  2119. // if the client been inactive for a long time, we must tell dll
  2120. //
  2121. else if (CurrentTime >= pArapConn->InactivityTimer)
  2122. {
  2123. // first make sure we can get the select irp
  2124. ArapGetSelectIrp(&pIrp);
  2125. // if we managed to get a select irp, reset the timer so we don't keep
  2126. // informing the dll after every tick after this point!
  2127. //
  2128. if (pIrp)
  2129. {
  2130. pArapConn->InactivityTimer = pArapConn->T403Duration + CurrentTime;
  2131. fInactiveClient = TRUE;
  2132. }
  2133. }
  2134. //
  2135. // Has the retransmit timer expired? If so, we need to retransmit
  2136. //
  2137. else
  2138. {
  2139. //
  2140. // look at the first entry of the retransmit queue. If it's time is up, do
  2141. // the retransmit thing. Otherwise, we are done. (All others in the queue
  2142. // will be retransmitted after this first one is acked, so ignore for now)
  2143. //
  2144. pList = pArapConn->RetransmitQ.Flink;
  2145. // no entries on the retransmit queue? we're done!
  2146. if (pList == &pArapConn->RetransmitQ)
  2147. {
  2148. RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
  2149. return ATALK_TIMER_REQUEUE;
  2150. }
  2151. pMnpSendBuf = CONTAINING_RECORD(pList, MNPSENDBUF, Linkage);
  2152. // is it time to retransmit yet?
  2153. if (CurrentTime >= pMnpSendBuf->RetryTime)
  2154. {
  2155. if (pMnpSendBuf->RetryCount >= ARAP_MAX_RETRANSMITS)
  2156. {
  2157. fKill = TRUE;
  2158. RemoveEntryList(&pMnpSendBuf->Linkage);
  2159. ASSERT(pArapConn->MnpState.UnAckedSends >= 1);
  2160. // not really important, since we're about to disconnect!
  2161. pArapConn->MnpState.UnAckedSends--;
  2162. ASSERT(pArapConn->SendsPending >= pMnpSendBuf->DataSize);
  2163. InitializeListHead(&pMnpSendBuf->Linkage);
  2164. }
  2165. else
  2166. {
  2167. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
  2168. ("ArapRetryTimer: timer fired, retransmitting....%x (%ld now %ld)\n",
  2169. pMnpSendBuf->SeqNum,pMnpSendBuf->RetryTime,CurrentTime));
  2170. if (pMnpSendBuf->RetryCount > 8)
  2171. {
  2172. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2173. ("ArapRetryTimer: buf %lx of %lx retransmitted %d times!\n",
  2174. pMnpSendBuf,pArapConn,pMnpSendBuf->RetryCount));
  2175. }
  2176. pArapConn->MnpState.RetransmitMode = TRUE;
  2177. pArapConn->MnpState.MustRetransmit = TRUE;
  2178. fRetransmit = TRUE;
  2179. }
  2180. }
  2181. }
  2182. RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
  2183. // force an ack out (that's what TRUE does)
  2184. if (fMustSendAck || fMustFlowControl)
  2185. {
  2186. MnpSendAckIfReqd(pArapConn, TRUE);
  2187. }
  2188. // if we must retransmit, go for it.
  2189. //
  2190. else if (fRetransmit)
  2191. {
  2192. ArapNdisSend(pArapConn, &pArapConn->RetransmitQ);
  2193. }
  2194. //
  2195. // if we retransmitted too many times, let the completion routine know.
  2196. // (it will probably kill the connection)
  2197. //
  2198. else if (fKill)
  2199. {
  2200. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2201. ("ArapRetryTimer: too many retransmits (%lx), disconnecting %lx\n",
  2202. pMnpSendBuf,pArapConn));
  2203. (pMnpSendBuf->ComplRoutine)(pMnpSendBuf, ARAPERR_SEND_FAILED);
  2204. }
  2205. //
  2206. // if the connection has been inactive for longer than the limit (given to
  2207. // us by the dll), then tell dll about it
  2208. //
  2209. else if (fInactiveClient)
  2210. {
  2211. PARAP_SEND_RECV_INFO pSndRcvInfo;
  2212. DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
  2213. ("ArapRetryTimer: (%lx) inactive, telling dll (%lx)\n",pArapConn, pIrp));
  2214. ASSERT(pIrp != NULL);
  2215. pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
  2216. pSndRcvInfo->pDllContext = pArapConn->pDllContext;
  2217. pSndRcvInfo->AtalkContext = pArapConn;
  2218. pSndRcvInfo->StatusCode = ARAPERR_CONN_INACTIVE;
  2219. ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
  2220. return ReturnStatus;
  2221. }
  2222. return ATALK_TIMER_REQUEUE;
  2223. }