Mtftp6Wrq.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. /** @file
  2. Mtftp6 Wrq process functions implementation.
  3. Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "Mtftp6Impl.h"
  7. /**
  8. Build and send a Mtftp6 data packet for upload.
  9. @param[in] Instance The pointer to the Mtftp6 instance.
  10. @param[in] BlockNum The block num to be sent.
  11. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
  12. @retval EFI_SUCCESS The data packet was sent.
  13. @retval EFI_ABORTED The user aborted this process.
  14. **/
  15. EFI_STATUS
  16. Mtftp6WrqSendBlock (
  17. IN MTFTP6_INSTANCE *Instance,
  18. IN UINT16 BlockNum
  19. )
  20. {
  21. EFI_MTFTP6_PACKET *Packet;
  22. EFI_MTFTP6_TOKEN *Token;
  23. NET_BUF *UdpPacket;
  24. EFI_STATUS Status;
  25. UINT16 DataLen;
  26. UINT8 *DataBuf;
  27. UINT64 Start;
  28. //
  29. // Allocate net buffer to create data packet.
  30. //
  31. UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP6_DATA_HEAD_LEN);
  32. if (UdpPacket == NULL) {
  33. return EFI_OUT_OF_RESOURCES;
  34. }
  35. Packet = (EFI_MTFTP6_PACKET *)NetbufAllocSpace (
  36. UdpPacket,
  37. MTFTP6_DATA_HEAD_LEN,
  38. FALSE
  39. );
  40. ASSERT (Packet != NULL);
  41. Packet->Data.OpCode = HTONS (EFI_MTFTP6_OPCODE_DATA);
  42. Packet->Data.Block = HTONS (BlockNum);
  43. //
  44. // Read the block from either the buffer or PacketNeeded callback
  45. //
  46. Token = Instance->Token;
  47. DataLen = Instance->BlkSize;
  48. if (Token->Buffer != NULL) {
  49. Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);
  50. if (Token->BufferSize < Start + Instance->BlkSize) {
  51. DataLen = (UINT16)(Token->BufferSize - Start);
  52. Instance->LastBlk = BlockNum;
  53. Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
  54. }
  55. if (DataLen > 0) {
  56. NetbufAllocSpace (UdpPacket, DataLen, FALSE);
  57. CopyMem (Packet->Data.Data, (UINT8 *)Token->Buffer + Start, DataLen);
  58. }
  59. } else {
  60. //
  61. // Get data from PacketNeeded
  62. //
  63. DataBuf = NULL;
  64. Status = Token->PacketNeeded (&Instance->Mtftp6, Token, &DataLen, (VOID *)&DataBuf);
  65. if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
  66. if (DataBuf != NULL) {
  67. gBS->FreePool (DataBuf);
  68. }
  69. //
  70. // The received packet has already been freed.
  71. //
  72. Mtftp6SendError (
  73. Instance,
  74. EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
  75. (UINT8 *)"User aborted the transfer"
  76. );
  77. return EFI_ABORTED;
  78. }
  79. if (DataLen < Instance->BlkSize) {
  80. Instance->LastBlk = BlockNum;
  81. Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
  82. }
  83. if (DataLen > 0) {
  84. NetbufAllocSpace (UdpPacket, DataLen, FALSE);
  85. CopyMem (Packet->Data.Data, DataBuf, DataLen);
  86. gBS->FreePool (DataBuf);
  87. }
  88. }
  89. //
  90. // Reset current retry count of the instance.
  91. //
  92. Instance->CurRetry = 0;
  93. return Mtftp6TransmitPacket (Instance, UdpPacket);
  94. }
  95. /**
  96. Function to handle received ACK packet. If the ACK number matches the
  97. expected block number, with more data pending, send the next
  98. block. Otherwise, tell the caller that we are done.
  99. @param[in] Instance The pointer to the Mtftp6 instance.
  100. @param[in] Packet The pointer to the received packet.
  101. @param[in] Len The length of the packet.
  102. @param[out] UdpPacket The net buf of received packet.
  103. @param[out] IsCompleted If TRUE, the upload has been completed.
  104. Otherwise, the upload has not been completed.
  105. @retval EFI_SUCCESS The ACK packet successfully processed.
  106. @retval EFI_TFTP_ERROR The block number loops back.
  107. @retval Others Failed to transmit the next data packet.
  108. **/
  109. EFI_STATUS
  110. Mtftp6WrqHandleAck (
  111. IN MTFTP6_INSTANCE *Instance,
  112. IN EFI_MTFTP6_PACKET *Packet,
  113. IN UINT32 Len,
  114. OUT NET_BUF **UdpPacket,
  115. OUT BOOLEAN *IsCompleted
  116. )
  117. {
  118. UINT16 AckNum;
  119. INTN Expected;
  120. UINT64 BlockCounter;
  121. *IsCompleted = FALSE;
  122. AckNum = NTOHS (Packet->Ack.Block[0]);
  123. Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
  124. ASSERT (Expected >= 0);
  125. //
  126. // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp6WrqInput
  127. // restart receive.
  128. //
  129. if (Expected != AckNum) {
  130. return EFI_SUCCESS;
  131. }
  132. //
  133. // Remove the acked block number, if this is the last block number,
  134. // tell the Mtftp6WrqInput to finish the transfer. This is the last
  135. // block number if the block range are empty.
  136. //
  137. Mtftp6RemoveBlockNum (&Instance->BlkList, AckNum, *IsCompleted, &BlockCounter);
  138. Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
  139. if (Expected < 0) {
  140. //
  141. // The block range is empty. It may either because the last
  142. // block has been ACKed, or the sequence number just looped back,
  143. // that is, there is more than 0xffff blocks.
  144. //
  145. if (Instance->LastBlk == AckNum) {
  146. ASSERT (Instance->LastBlk >= 1);
  147. *IsCompleted = TRUE;
  148. return EFI_SUCCESS;
  149. } else {
  150. //
  151. // Free the received packet before send new packet in ReceiveNotify,
  152. // since the udpio might need to be reconfigured.
  153. //
  154. NetbufFree (*UdpPacket);
  155. *UdpPacket = NULL;
  156. //
  157. // Send the Mtftp6 error message if block number rolls back.
  158. //
  159. Mtftp6SendError (
  160. Instance,
  161. EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
  162. (UINT8 *)"Block number rolls back, not supported, try blksize option"
  163. );
  164. return EFI_TFTP_ERROR;
  165. }
  166. }
  167. //
  168. // Free the receive buffer before send new packet since it might need
  169. // reconfigure udpio.
  170. //
  171. NetbufFree (*UdpPacket);
  172. *UdpPacket = NULL;
  173. return Mtftp6WrqSendBlock (Instance, (UINT16)Expected);
  174. }
  175. /**
  176. Check whether the received OACK is valid. The OACK is valid
  177. only if:
  178. 1. It only include options requested by us.
  179. 2. It can only include a smaller block size.
  180. 3. It can't change the proposed time out value.
  181. 4. Other requirements of the individal MTFTP6 options as required.
  182. @param[in] ReplyInfo The pointer to options information in reply packet.
  183. @param[in] RequestInfo The pointer to requested options information.
  184. @retval TRUE If the option in OACK is valid.
  185. @retval FALSE If the option is invalid.
  186. **/
  187. BOOLEAN
  188. Mtftp6WrqOackValid (
  189. IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,
  190. IN MTFTP6_EXT_OPTION_INFO *RequestInfo
  191. )
  192. {
  193. //
  194. // It is invalid for server to return options we don't request
  195. //
  196. if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
  197. return FALSE;
  198. }
  199. //
  200. // Server can only specify a smaller block size to be used and
  201. // return the timeout matches that requested.
  202. //
  203. if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
  204. (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
  205. )
  206. {
  207. return FALSE;
  208. }
  209. return TRUE;
  210. }
  211. /**
  212. Process the OACK packet for Wrq.
  213. @param[in] Instance The pointer to the Mtftp6 instance.
  214. @param[in] Packet The pointer to the received packet.
  215. @param[in] Len The length of the packet.
  216. @param[out] UdpPacket The net buf of received packet.
  217. @param[out] IsCompleted If TRUE, the upload has been completed.
  218. Otherwise, the upload has not been completed.
  219. @retval EFI_SUCCESS The OACK packet successfully processed.
  220. @retval EFI_TFTP_ERROR An TFTP communication error happened.
  221. @retval Others Failed to process the OACK packet.
  222. **/
  223. EFI_STATUS
  224. Mtftp6WrqHandleOack (
  225. IN MTFTP6_INSTANCE *Instance,
  226. IN EFI_MTFTP6_PACKET *Packet,
  227. IN UINT32 Len,
  228. OUT NET_BUF **UdpPacket,
  229. OUT BOOLEAN *IsCompleted
  230. )
  231. {
  232. EFI_MTFTP6_OPTION *Options;
  233. UINT32 Count;
  234. MTFTP6_EXT_OPTION_INFO ExtInfo;
  235. EFI_MTFTP6_PACKET Dummy;
  236. EFI_STATUS Status;
  237. INTN Expected;
  238. *IsCompleted = FALSE;
  239. Options = NULL;
  240. //
  241. // Ignore the OACK if already started the upload
  242. //
  243. Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
  244. if (Expected != 0) {
  245. return EFI_SUCCESS;
  246. }
  247. //
  248. // Parse and validate the options from server
  249. //
  250. ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
  251. Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
  252. if (EFI_ERROR (Status)) {
  253. return Status;
  254. }
  255. ASSERT (Options != NULL);
  256. Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, Instance->Operation, &ExtInfo);
  257. if (EFI_ERROR (Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) {
  258. //
  259. // Don't send a MTFTP error packet when out of resource, it can
  260. // only make it worse.
  261. //
  262. if (Status != EFI_OUT_OF_RESOURCES) {
  263. //
  264. // Free the received packet before send new packet in ReceiveNotify,
  265. // since the udpio might need to be reconfigured.
  266. //
  267. NetbufFree (*UdpPacket);
  268. *UdpPacket = NULL;
  269. //
  270. // Send the Mtftp6 error message if invalid Oack packet received.
  271. //
  272. Mtftp6SendError (
  273. Instance,
  274. EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
  275. (UINT8 *)"Malformatted OACK packet"
  276. );
  277. }
  278. return EFI_TFTP_ERROR;
  279. }
  280. if (ExtInfo.BlkSize != 0) {
  281. Instance->BlkSize = ExtInfo.BlkSize;
  282. }
  283. if (ExtInfo.Timeout != 0) {
  284. Instance->Timeout = ExtInfo.Timeout;
  285. }
  286. //
  287. // Build a bogus ACK0 packet then pass it to the Mtftp6WrqHandleAck,
  288. // which will start the transmission of the first data block.
  289. //
  290. Dummy.Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);
  291. Dummy.Ack.Block[0] = 0;
  292. return Mtftp6WrqHandleAck (
  293. Instance,
  294. &Dummy,
  295. sizeof (EFI_MTFTP6_ACK_HEADER),
  296. UdpPacket,
  297. IsCompleted
  298. );
  299. }
  300. /**
  301. The packet process callback for Mtftp6 upload.
  302. @param[in] UdpPacket The pointer to the packet received.
  303. @param[in] UdpEpt The pointer to the Udp6 access point.
  304. @param[in] IoStatus The status from Udp6 instance.
  305. @param[in] Context The pointer to the context.
  306. **/
  307. VOID
  308. EFIAPI
  309. Mtftp6WrqInput (
  310. IN NET_BUF *UdpPacket,
  311. IN UDP_END_POINT *UdpEpt,
  312. IN EFI_STATUS IoStatus,
  313. IN VOID *Context
  314. )
  315. {
  316. MTFTP6_INSTANCE *Instance;
  317. EFI_MTFTP6_PACKET *Packet;
  318. BOOLEAN IsCompleted;
  319. EFI_STATUS Status;
  320. UINT32 TotalNum;
  321. UINT32 Len;
  322. UINT16 Opcode;
  323. Instance = (MTFTP6_INSTANCE *)Context;
  324. NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
  325. IsCompleted = FALSE;
  326. Packet = NULL;
  327. Status = EFI_SUCCESS;
  328. TotalNum = 0;
  329. //
  330. // Return error status if Udp6 instance failed to receive.
  331. //
  332. if (EFI_ERROR (IoStatus)) {
  333. Status = IoStatus;
  334. goto ON_EXIT;
  335. }
  336. ASSERT (UdpPacket != NULL);
  337. if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
  338. goto ON_EXIT;
  339. }
  340. //
  341. // Client send initial request to server's listening port. Server
  342. // will select a UDP port to communicate with the client.
  343. //
  344. if (UdpEpt->RemotePort != Instance->ServerDataPort) {
  345. if (Instance->ServerDataPort != 0) {
  346. goto ON_EXIT;
  347. } else {
  348. Instance->ServerDataPort = UdpEpt->RemotePort;
  349. }
  350. }
  351. //
  352. // Copy the MTFTP packet to a continuous buffer if it isn't already so.
  353. //
  354. Len = UdpPacket->TotalSize;
  355. TotalNum = UdpPacket->BlockOpNum;
  356. if (TotalNum > 1) {
  357. Packet = AllocateZeroPool (Len);
  358. if (Packet == NULL) {
  359. Status = EFI_OUT_OF_RESOURCES;
  360. goto ON_EXIT;
  361. }
  362. NetbufCopy (UdpPacket, 0, Len, (UINT8 *)Packet);
  363. } else {
  364. Packet = (EFI_MTFTP6_PACKET *)NetbufGetByte (UdpPacket, 0, NULL);
  365. ASSERT (Packet != NULL);
  366. }
  367. Opcode = NTOHS (Packet->OpCode);
  368. //
  369. // Callback to the user's CheckPacket if provided. Abort the transmission
  370. // if CheckPacket returns an EFI_ERROR code.
  371. //
  372. if ((Instance->Token->CheckPacket != NULL) &&
  373. ((Opcode == EFI_MTFTP6_OPCODE_OACK) || (Opcode == EFI_MTFTP6_OPCODE_ERROR))
  374. )
  375. {
  376. Status = Instance->Token->CheckPacket (
  377. &Instance->Mtftp6,
  378. Instance->Token,
  379. (UINT16)Len,
  380. Packet
  381. );
  382. if (EFI_ERROR (Status)) {
  383. //
  384. // Send an error message to the server to inform it
  385. //
  386. if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
  387. //
  388. // Free the received packet before send new packet in ReceiveNotify,
  389. // since the udpio might need to be reconfigured.
  390. //
  391. NetbufFree (UdpPacket);
  392. UdpPacket = NULL;
  393. //
  394. // Send the Mtftp6 error message if user aborted the current session.
  395. //
  396. Mtftp6SendError (
  397. Instance,
  398. EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
  399. (UINT8 *)"User aborted the transfer"
  400. );
  401. }
  402. Status = EFI_ABORTED;
  403. goto ON_EXIT;
  404. }
  405. }
  406. //
  407. // Switch the process routines by the operation code.
  408. //
  409. switch (Opcode) {
  410. case EFI_MTFTP6_OPCODE_ACK:
  411. if (Len != MTFTP6_OPCODE_LEN + MTFTP6_BLKNO_LEN) {
  412. goto ON_EXIT;
  413. }
  414. //
  415. // Handle the Ack packet of Wrq.
  416. //
  417. Status = Mtftp6WrqHandleAck (Instance, Packet, Len, &UdpPacket, &IsCompleted);
  418. break;
  419. case EFI_MTFTP6_OPCODE_OACK:
  420. if (Len <= MTFTP6_OPCODE_LEN) {
  421. goto ON_EXIT;
  422. }
  423. //
  424. // Handle the Oack packet of Wrq.
  425. //
  426. Status = Mtftp6WrqHandleOack (Instance, Packet, Len, &UdpPacket, &IsCompleted);
  427. break;
  428. default:
  429. //
  430. // Drop and return eror if received error message.
  431. //
  432. Status = EFI_TFTP_ERROR;
  433. break;
  434. }
  435. ON_EXIT:
  436. //
  437. // Free the resources, then if !EFI_ERROR (Status) and not completed,
  438. // restart the receive, otherwise end the session.
  439. //
  440. if ((Packet != NULL) && (TotalNum > 1)) {
  441. FreePool (Packet);
  442. }
  443. if (UdpPacket != NULL) {
  444. NetbufFree (UdpPacket);
  445. }
  446. if (!EFI_ERROR (Status) && !IsCompleted) {
  447. Status = UdpIoRecvDatagram (
  448. Instance->UdpIo,
  449. Mtftp6WrqInput,
  450. Instance,
  451. 0
  452. );
  453. }
  454. //
  455. // Clean up the current session if failed to continue.
  456. //
  457. if (EFI_ERROR (Status) || IsCompleted) {
  458. Mtftp6OperationClean (Instance, Status);
  459. }
  460. }
  461. /**
  462. Start the Mtftp6 instance to upload. It will first init some states,
  463. then send the WRQ request packet, and start to receive the packet.
  464. @param[in] Instance The pointer to the Mtftp6 instance.
  465. @param[in] Operation The operation code of the current packet.
  466. @retval EFI_SUCCESS The Mtftp6 was started to upload.
  467. @retval Others Failed to start to upload.
  468. **/
  469. EFI_STATUS
  470. Mtftp6WrqStart (
  471. IN MTFTP6_INSTANCE *Instance,
  472. IN UINT16 Operation
  473. )
  474. {
  475. EFI_STATUS Status;
  476. //
  477. // The valid block number range are [0, 0xffff]. For example:
  478. // the client sends an WRQ request to the server, the server
  479. // ACK with an ACK0 to let client start transfer the first
  480. // packet.
  481. //
  482. Status = Mtftp6InitBlockRange (&Instance->BlkList, 0, 0xffff);
  483. if (EFI_ERROR (Status)) {
  484. return Status;
  485. }
  486. Status = Mtftp6SendRequest (Instance, Operation);
  487. if (EFI_ERROR (Status)) {
  488. return Status;
  489. }
  490. return UdpIoRecvDatagram (
  491. Instance->UdpIo,
  492. Mtftp6WrqInput,
  493. Instance,
  494. 0
  495. );
  496. }