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.

729 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. atkact.c
  5. Abstract:
  6. This module contains the TDI action support code.
  7. Author:
  8. Jameel Hyder (jameelh@microsoft.com)
  9. Nikhil Kamkolkar (nikhilk@microsoft.com)
  10. Revision History:
  11. 19 Jun 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #include <atalk.h>
  15. #pragma hdrstop
  16. #define FILENUM ATKACT
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE_NZ, AtalkNbpTdiAction)
  19. #pragma alloc_text(PAGE_NZ, AtalkZipTdiAction)
  20. #pragma alloc_text(PAGE, AtalkAspTdiAction)
  21. #pragma alloc_text(PAGE, AtalkAdspTdiAction)
  22. #pragma alloc_text(PAGE_PAP, AtalkPapTdiAction)
  23. #pragma alloc_text(PAGEASPC, AtalkAspCTdiAction)
  24. #endif
  25. ATALK_ERROR
  26. AtalkStatTdiAction(
  27. IN PVOID pObject, // Address or Connection object
  28. IN struct _ActionReq * pActReq // Pointer to action request
  29. )
  30. /*++
  31. Routine Description:
  32. This is the entry for Statistics TdiAction call. There are no input parameters.
  33. The statistics structure is returned.
  34. Arguments:
  35. Return Value:
  36. --*/
  37. {
  38. ATALK_ERROR Error = ATALK_NO_ERROR;
  39. PPORT_DESCRIPTOR pPortDesc;
  40. KIRQL OldIrql;
  41. ULONG BytesCopied;
  42. LONG Offset;
  43. if (pActReq->ar_MdlSize < (SHORT)(sizeof(ATALK_STATS) +
  44. sizeof(ATALK_PORT_STATS) * AtalkNumberOfPorts))
  45. Error = ATALK_BUFFER_TOO_SMALL;
  46. else
  47. {
  48. #ifdef PROFILING
  49. // This is the only place where this is changed. And it always increases.
  50. // Also the stats are changed using ExInterlocked calls. Acquiring a lock
  51. // does little in terms of protection anyways.
  52. AtalkStatistics.stat_ElapsedTime = AtalkTimerCurrentTick/ATALK_TIMER_FACTOR;
  53. #endif
  54. TdiCopyBufferToMdl(&AtalkStatistics,
  55. 0,
  56. sizeof(ATALK_STATS),
  57. pActReq->ar_pAMdl,
  58. 0,
  59. &BytesCopied);
  60. ASSERT(BytesCopied == sizeof(ATALK_STATS));
  61. ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
  62. for (pPortDesc = AtalkPortList, Offset = sizeof(ATALK_STATS);
  63. pPortDesc != NULL;
  64. pPortDesc = pPortDesc->pd_Next)
  65. {
  66. TdiCopyBufferToMdl(&pPortDesc->pd_PortStats,
  67. 0,
  68. sizeof(ATALK_PORT_STATS),
  69. pActReq->ar_pAMdl,
  70. Offset,
  71. &BytesCopied);
  72. Offset += sizeof(ATALK_PORT_STATS);
  73. ASSERT(BytesCopied == sizeof(ATALK_PORT_STATS));
  74. }
  75. RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
  76. }
  77. (*pActReq->ar_Completion)(Error, pActReq);
  78. return ATALK_PENDING;
  79. }
  80. ATALK_ERROR
  81. AtalkNbpTdiAction(
  82. IN PVOID pObject, // Address or Connection object
  83. IN PACTREQ pActReq // Pointer to action request
  84. )
  85. /*++
  86. Routine Description:
  87. This is the entry for NBP TdiAction calls. The parameters are validated and
  88. the calls are dispacthed to the appropriate NBP routines.
  89. Arguments:
  90. Return Value:
  91. --*/
  92. {
  93. ATALK_ERROR error = ATALK_NO_ERROR;
  94. PDDP_ADDROBJ pDdpAddr;
  95. PNBPTUPLE pNbpTuple;
  96. PAGED_CODE ();
  97. // Lock the Nbp stuff, if this is the first nbp action
  98. AtalkLockNbpIfNecessary();
  99. ASSERT (VALID_ACTREQ(pActReq));
  100. // First get the Ddp address out of the pObject for the device
  101. switch (pActReq->ar_DevType)
  102. {
  103. case ATALK_DEV_DDP:
  104. pDdpAddr = (PDDP_ADDROBJ)pObject;
  105. break;
  106. case ATALK_DEV_ASPC:
  107. pDdpAddr = AtalkAspCGetDdpAddress((PASPC_ADDROBJ)pObject);
  108. break;
  109. case ATALK_DEV_ASP:
  110. pDdpAddr = AtalkAspGetDdpAddress((PASP_ADDROBJ)pObject);
  111. break;
  112. case ATALK_DEV_PAP:
  113. pDdpAddr = AtalkPapGetDdpAddress((PPAP_ADDROBJ)pObject);
  114. break;
  115. case ATALK_DEV_ADSP:
  116. pDdpAddr = AtalkAdspGetDdpAddress((PADSP_ADDROBJ)pObject);
  117. break;
  118. default:
  119. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
  120. ("AtalkNbpTdiAction: Invalid device type !!\n"));
  121. error = ATALK_INVALID_REQUEST;
  122. break;
  123. }
  124. // reference the Ddp address.
  125. if ((pActReq->ar_ActionCode == COMMON_ACTION_NBPREGISTER_BY_ADDR) ||
  126. (pActReq->ar_ActionCode == COMMON_ACTION_NBPREMOVE_BY_ADDR))
  127. {
  128. // In this case, we don't want to access the object related to
  129. // the filehandle in the IO request, we want to access the object
  130. // related to a specific user socket address.
  131. pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisterTuple);
  132. AtalkDdpReferenceByAddr(AtalkDefaultPort,
  133. &(pNbpTuple->tpl_Address),
  134. &pDdpAddr,
  135. &error);
  136. }
  137. else
  138. {
  139. AtalkDdpReferenceByPtr(pDdpAddr, &error);
  140. }
  141. if (!ATALK_SUCCESS(error))
  142. {
  143. AtalkUnlockNbpIfNecessary();
  144. return error;
  145. }
  146. // Call Nbp to do the right stuff
  147. switch (pActReq->ar_ActionCode)
  148. {
  149. case COMMON_ACTION_NBPLOOKUP:
  150. pNbpTuple = (PNBPTUPLE)(&((PNBP_LOOKUP_PARAMS)(pActReq->ar_pParms))->LookupTuple);
  151. error = AtalkNbpAction(pDdpAddr,
  152. FOR_LOOKUP,
  153. pNbpTuple,
  154. pActReq->ar_pAMdl,
  155. (USHORT)(pActReq->ar_MdlSize/sizeof(NBPTUPLE)),
  156. pActReq);
  157. break;
  158. case COMMON_ACTION_NBPCONFIRM:
  159. pNbpTuple = (PNBPTUPLE)(&((PNBP_CONFIRM_PARAMS)(pActReq->ar_pParms))->ConfirmTuple);
  160. error = AtalkNbpAction(pDdpAddr,
  161. FOR_CONFIRM,
  162. pNbpTuple,
  163. NULL,
  164. 0,
  165. pActReq);
  166. break;
  167. case COMMON_ACTION_NBPREGISTER:
  168. pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisterTuple);
  169. error = AtalkNbpAction(pDdpAddr,
  170. FOR_REGISTER,
  171. pNbpTuple,
  172. NULL,
  173. 0,
  174. pActReq);
  175. break;
  176. case COMMON_ACTION_NBPREMOVE:
  177. pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisteredTuple);
  178. error = AtalkNbpRemove(pDdpAddr,
  179. pNbpTuple,
  180. pActReq);
  181. break;
  182. case COMMON_ACTION_NBPREGISTER_BY_ADDR:
  183. pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisterTuple);
  184. error = AtalkNbpAction(pDdpAddr,
  185. FOR_REGISTER,
  186. pNbpTuple,
  187. NULL,
  188. 0,
  189. pActReq);
  190. break;
  191. case COMMON_ACTION_NBPREMOVE_BY_ADDR:
  192. pNbpTuple = (PNBPTUPLE)(&((PNBP_REGDEREG_PARAMS)(pActReq->ar_pParms))->RegisteredTuple);
  193. error = AtalkNbpRemove(pDdpAddr,
  194. pNbpTuple,
  195. pActReq);
  196. break;
  197. default:
  198. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
  199. ("AtalkNbpTdiAction: Invalid Nbp Action !!\n"));
  200. error = ATALK_INVALID_REQUEST;
  201. break;
  202. }
  203. AtalkDdpDereference(pDdpAddr);
  204. if (error != ATALK_PENDING)
  205. {
  206. AtalkUnlockNbpIfNecessary();
  207. }
  208. return error;
  209. }
  210. ATALK_ERROR
  211. AtalkZipTdiAction(
  212. IN PVOID pObject, // Address or Connection object
  213. IN PACTREQ pActReq // Pointer to action request
  214. )
  215. /*++
  216. Routine Description:
  217. This is the entry for ZIP TdiAction calls. The parameters are validated and
  218. the calls are dispacthed to the appropriate ZIP routines.
  219. Arguments:
  220. Return Value:
  221. --*/
  222. {
  223. ATALK_ERROR error = ATALK_INVALID_PARAMETER;
  224. PPORT_DESCRIPTOR pPortDesc = AtalkDefaultPort;
  225. PWCHAR PortName = NULL;
  226. USHORT PortNameLen;
  227. UNICODE_STRING AdapterName, UpcaseAdapterName;
  228. WCHAR UpcaseBuffer[MAX_INTERNAL_PORTNAME_LEN];
  229. KIRQL OldIrql;
  230. int i;
  231. PAGED_CODE ();
  232. // Lock the Zip stuff, if this is the first zip action
  233. AtalkLockZipIfNecessary();
  234. ASSERT (VALID_ACTREQ(pActReq));
  235. if ((pActReq->ar_ActionCode == COMMON_ACTION_ZIPGETLZONESONADAPTER) ||
  236. (pActReq->ar_ActionCode == COMMON_ACTION_ZIPGETADAPTERDEFAULTS))
  237. {
  238. // Map the port name to the port descriptor
  239. if ((pActReq->ar_pAMdl != NULL) && (pActReq->ar_MdlSize > 0))
  240. {
  241. PortName = (PWCHAR)AtalkGetAddressFromMdlSafe(
  242. pActReq->ar_pAMdl,
  243. NormalPagePriority);
  244. }
  245. if (PortName == NULL)
  246. {
  247. AtalkUnlockZipIfNecessary();
  248. return ATALK_INVALID_PARAMETER;
  249. }
  250. PortNameLen = pActReq->ar_MdlSize/sizeof(WCHAR);
  251. // make sure there is a NULL char in the buffer
  252. for (i=0; i<PortNameLen; i++)
  253. {
  254. if (PortName[i] == UNICODE_NULL)
  255. {
  256. break;
  257. }
  258. }
  259. // didn't find null char within limit? bad parameter..
  260. if (i >= MAX_INTERNAL_PORTNAME_LEN)
  261. {
  262. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
  263. ("AtalkZipTdiAction: port name too big (%d) for %lx\n",PortNameLen,PortName));
  264. ASSERT(0);
  265. return ATALK_INVALID_PARAMETER;
  266. }
  267. PortNameLen = (USHORT)i;
  268. AdapterName.Buffer = PortName;
  269. AdapterName.Length = (PortNameLen)*sizeof(WCHAR);
  270. AdapterName.MaximumLength = (PortNameLen+1)*sizeof(WCHAR);
  271. UpcaseAdapterName.Buffer = UpcaseBuffer;
  272. UpcaseAdapterName.Length =
  273. UpcaseAdapterName.MaximumLength = sizeof(UpcaseBuffer);
  274. RtlUpcaseUnicodeString(&UpcaseAdapterName,
  275. &AdapterName,
  276. FALSE);
  277. ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
  278. // Find the port corres. to the port descriptor
  279. for (pPortDesc = AtalkPortList;
  280. pPortDesc != NULL;
  281. pPortDesc = pPortDesc->pd_Next)
  282. {
  283. if ((UpcaseAdapterName.Length == pPortDesc->pd_AdapterName.Length) &&
  284. RtlEqualMemory(UpcaseAdapterName.Buffer,
  285. pPortDesc->pd_AdapterName.Buffer,
  286. UpcaseAdapterName.Length))
  287. {
  288. break;
  289. }
  290. }
  291. RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
  292. if (pPortDesc == NULL)
  293. {
  294. AtalkUnlockZipIfNecessary();
  295. return ATALK_INVALID_PARAMETER;
  296. }
  297. }
  298. else if (pActReq->ar_ActionCode == COMMON_ACTION_ZIPGETZONELIST)
  299. {
  300. PPORT_DESCRIPTOR pTempPortDesc = NULL;
  301. // This is to take care of cases when zone list is requested
  302. // but the default adapter has gone away during PnP, and
  303. // AtalkDefaultPort points to NULL
  304. if (pPortDesc == NULL)
  305. {
  306. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
  307. ("COMMON_ACTION_ZIPGETZONELIST: PortDesc points to NULL\n"));
  308. AtalkUnlockZipIfNecessary();
  309. return ATALK_PORT_INVALID;
  310. }
  311. // Check if the AtalkDefaultPort is still in the list
  312. // It is possible that AtalkDefaultPort holds a non-NULL value, but
  313. // the adapter has gone away during a PnP
  314. ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
  315. // Find the port corres. to the port descriptor
  316. for (pTempPortDesc = AtalkPortList;
  317. pTempPortDesc != NULL;
  318. pTempPortDesc = pTempPortDesc->pd_Next)
  319. {
  320. if (pTempPortDesc == pPortDesc)
  321. {
  322. break;
  323. }
  324. }
  325. RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
  326. if (pTempPortDesc == NULL)
  327. {
  328. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
  329. ("COMMON_ACTION_ZIPGETZONELIST: PortDesc structure has gone away during PnP\n"));
  330. AtalkUnlockZipIfNecessary();
  331. return ATALK_PORT_INVALID;
  332. }
  333. }
  334. switch (pActReq->ar_ActionCode)
  335. {
  336. case COMMON_ACTION_ZIPGETMYZONE:
  337. error = AtalkZipGetMyZone( pPortDesc,
  338. TRUE,
  339. pActReq->ar_pAMdl,
  340. pActReq->ar_MdlSize,
  341. pActReq);
  342. break;
  343. case COMMON_ACTION_ZIPGETZONELIST:
  344. error = AtalkZipGetZoneList(pPortDesc,
  345. FALSE,
  346. pActReq->ar_pAMdl,
  347. pActReq->ar_MdlSize,
  348. pActReq);
  349. break;
  350. case COMMON_ACTION_ZIPGETADAPTERDEFAULTS:
  351. // Copy the network range from the port and fall through
  352. ((PZIP_GETPORTDEF_PARAMS)(pActReq->ar_pParms))->NwRangeLowEnd =
  353. pPortDesc->pd_NetworkRange.anr_FirstNetwork;
  354. ((PZIP_GETPORTDEF_PARAMS)(pActReq->ar_pParms))->NwRangeHighEnd =
  355. pPortDesc->pd_NetworkRange.anr_LastNetwork;
  356. error = AtalkZipGetMyZone(pPortDesc,
  357. FALSE,
  358. pActReq->ar_pAMdl,
  359. pActReq->ar_MdlSize,
  360. pActReq);
  361. break;
  362. case COMMON_ACTION_ZIPGETLZONESONADAPTER:
  363. case COMMON_ACTION_ZIPGETLZONES:
  364. error = AtalkZipGetZoneList(pPortDesc,
  365. TRUE,
  366. pActReq->ar_pAMdl,
  367. pActReq->ar_MdlSize,
  368. pActReq);
  369. break;
  370. default:
  371. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
  372. ("AtalkZipTdiAction: Invalid Zip Action !!\n"));
  373. error = ATALK_INVALID_REQUEST;
  374. break;
  375. }
  376. if (error != ATALK_PENDING)
  377. {
  378. AtalkUnlockZipIfNecessary();
  379. }
  380. return error;
  381. }
  382. ATALK_ERROR
  383. AtalkAspTdiAction(
  384. IN PVOID pObject, // Address or Connection object
  385. IN PACTREQ pActReq // Pointer to action request
  386. )
  387. /*++
  388. Routine Description:
  389. This is the entry for ASP TdiAction calls. The parameters are validated and
  390. the calls are dispacthed to the appropriate ASP routines.
  391. The only ASP Action is: ASP_XCHG_ENTRIES
  392. Arguments:
  393. Return Value:
  394. --*/
  395. {
  396. ATALK_ERROR error = ATALK_INVALID_REQUEST;
  397. PAGED_CODE ();
  398. ASSERT(VALID_ACTREQ(pActReq));
  399. if (pActReq->ar_ActionCode == ACTION_ASP_BIND)
  400. {
  401. if (AtalkAspReferenceAddr((PASP_ADDROBJ)pObject) != NULL)
  402. {
  403. error = AtalkAspBind((PASP_ADDROBJ)pObject,
  404. (PASP_BIND_PARAMS)(pActReq->ar_pParms),
  405. pActReq);
  406. AtalkAspDereferenceAddr((PASP_ADDROBJ)pObject);
  407. }
  408. }
  409. return error;
  410. }
  411. ATALK_ERROR
  412. AtalkAdspTdiAction(
  413. IN PVOID pObject, // Address or Connection object
  414. IN PACTREQ pActReq // Pointer to action request
  415. )
  416. /*++
  417. Routine Description:
  418. This is the entry for ADSP TdiAction calls. The parameters are validated and
  419. the calls are dispacthed to the appropriate ADSP routines.
  420. Arguments:
  421. Return Value:
  422. --*/
  423. {
  424. ATALK_ERROR error = ATALK_NO_ERROR;
  425. PAGED_CODE ();
  426. ASSERT (VALID_ACTREQ(pActReq));
  427. return error;
  428. }
  429. ATALK_ERROR
  430. AtalkAspCTdiAction(
  431. IN PVOID pObject, // Address or Connection object
  432. IN PACTREQ pActReq // Pointer to action request
  433. )
  434. /*++
  435. Routine Description:
  436. This is the entry for ASP Client TdiAction calls. The parameters are validated
  437. and the calls are dispatched to the appropriate ASP routines.
  438. Arguments:
  439. Return Value:
  440. --*/
  441. {
  442. ATALK_ERROR error = ATALK_NO_ERROR;
  443. PAMDL pReplyMdl;
  444. ATALK_ADDR atalkAddr;
  445. BOOLEAN fWrite;
  446. PAGED_CODE ();
  447. ASSERT (VALID_ACTREQ(pActReq));
  448. switch (pActReq->ar_ActionCode)
  449. {
  450. case ACTION_ASPCGETSTATUS:
  451. AtalkAspCAddrReference((PASPC_ADDROBJ)pObject, &error);
  452. if (ATALK_SUCCESS(error))
  453. {
  454. TDI_TO_ATALKADDR(&atalkAddr,
  455. &(((PASPC_GETSTATUS_PARAMS)pActReq->ar_pParms)->ServerAddr));
  456. error = AtalkAspCGetStatus((PASPC_ADDROBJ)pObject,
  457. &atalkAddr,
  458. pActReq->ar_pAMdl,
  459. pActReq->ar_MdlSize,
  460. pActReq);
  461. AtalkAspCAddrDereference((PASPC_ADDROBJ)pObject);
  462. }
  463. break;
  464. case ACTION_ASPCCOMMAND:
  465. case ACTION_ASPCWRITE:
  466. // Split the mdl into command and reply/write mdls. The already constructed mdl
  467. // serves as the command mdl
  468. // First validate that the sizes are valid
  469. if (pActReq->ar_MdlSize < (((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->CmdSize +
  470. ((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->WriteAndReplySize))
  471. {
  472. error = ATALK_BUFFER_TOO_SMALL;
  473. break;
  474. }
  475. pReplyMdl = AtalkSubsetAmdl(pActReq->ar_pAMdl,
  476. ((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->CmdSize,
  477. ((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->WriteAndReplySize);
  478. if (pReplyMdl == NULL)
  479. {
  480. error = ATALK_RESR_MEM;
  481. break;
  482. }
  483. AtalkAspCConnReference((PASPC_CONNOBJ)pObject, &error);
  484. if (ATALK_SUCCESS(error))
  485. {
  486. fWrite = (pActReq->ar_ActionCode == ACTION_ASPCWRITE) ? TRUE : FALSE;
  487. error = AtalkAspCCmdOrWrite((PASPC_CONNOBJ)pObject,
  488. pActReq->ar_pAMdl,
  489. ((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->CmdSize,
  490. pReplyMdl,
  491. ((PASPC_COMMAND_OR_WRITE_PARAMS)pActReq->ar_pParms)->WriteAndReplySize,
  492. fWrite,
  493. pActReq);
  494. AtalkAspCConnDereference((PASPC_CONNOBJ)pObject);
  495. }
  496. break;
  497. default:
  498. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
  499. ("AtalkAspCTdiAction: Invalid Asp Client Action !!\n"));
  500. error = ATALK_INVALID_REQUEST;
  501. break;
  502. }
  503. return error;
  504. }
  505. ATALK_ERROR
  506. AtalkPapTdiAction(
  507. IN PVOID pObject, // Address or Connection object
  508. IN PACTREQ pActReq // Pointer to action request
  509. )
  510. /*++
  511. Routine Description:
  512. This is the entry for PAP TdiAction calls. The parameters are validated and
  513. the calls are dispacthed to the appropriate PAP routines.
  514. Arguments:
  515. Return Value:
  516. --*/
  517. {
  518. ATALK_ERROR error;
  519. ATALK_ADDR atalkAddr;
  520. PAGED_CODE ();
  521. ASSERT (VALID_ACTREQ(pActReq));
  522. switch (pActReq->ar_ActionCode)
  523. {
  524. case ACTION_PAPGETSTATUSSRV:
  525. AtalkPapAddrReference((PPAP_ADDROBJ)pObject, &error);
  526. if (ATALK_SUCCESS(error))
  527. {
  528. TDI_TO_ATALKADDR(
  529. &atalkAddr,
  530. &(((PPAP_GETSTATUSSRV_PARAMS)pActReq->ar_pParms)->ServerAddr));
  531. error = AtalkPapGetStatus((PPAP_ADDROBJ)pObject,
  532. &atalkAddr,
  533. pActReq->ar_pAMdl,
  534. pActReq->ar_MdlSize,
  535. pActReq);
  536. AtalkPapAddrDereference((PPAP_ADDROBJ)pObject);
  537. }
  538. break;
  539. case ACTION_PAPSETSTATUS:
  540. AtalkPapAddrReference((PPAP_ADDROBJ)pObject, &error);
  541. if (ATALK_SUCCESS(error))
  542. {
  543. error = AtalkPapSetStatus((PPAP_ADDROBJ)pObject,
  544. pActReq->ar_pAMdl,
  545. pActReq);
  546. AtalkPapAddrDereference((PPAP_ADDROBJ)pObject);
  547. }
  548. break;
  549. case ACTION_PAPPRIMEREAD:
  550. AtalkPapConnReferenceByPtr((PPAP_CONNOBJ)pObject, &error);
  551. if (ATALK_SUCCESS(error))
  552. {
  553. error = AtalkPapPrimeRead((PPAP_CONNOBJ)pObject, pActReq);
  554. AtalkPapConnDereference((PPAP_CONNOBJ)pObject);
  555. }
  556. break;
  557. default:
  558. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_FATAL,
  559. ("AtalkPapTdiAction: Invalid Pap Action !!\n"));
  560. error = ATALK_INVALID_REQUEST;
  561. break;
  562. }
  563. return error;
  564. }