]>
Commit | Line | Data |
---|---|---|
7dc13291 | 1 | /** @file\r |
2 | This is a simple TFTP server application\r | |
3 | \r | |
bcb96695 MK |
4 | Copyright (c) 2011, 2012, Intel Corporation. All rights reserved.\r |
5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
f6e5cdd5 | 6 | \r |
7dc13291 | 7 | **/\r |
8 | \r | |
9 | #include <TftpServer.h>\r | |
10 | \r | |
f6e5cdd5 | 11 | TSDT_TFTP_SERVER mTftpServer; ///< TFTP server's control structure\r |
12 | volatile BOOLEAN mbTftpServerExit; ///< Set TRUE to cause TFTP server to exit\r | |
7dc13291 | 13 | \r |
14 | \r | |
15 | /**\r | |
f6e5cdd5 | 16 | Read file data into a buffer\r |
7dc13291 | 17 | \r |
f6e5cdd5 | 18 | @param [in] pContext Connection context structure address\r |
7dc13291 | 19 | \r |
f6e5cdd5 | 20 | @retval TRUE if a read error occurred\r |
7dc13291 | 21 | \r |
22 | **/\r | |
f6e5cdd5 | 23 | BOOLEAN\r |
24 | BufferFill (\r | |
25 | IN TSDT_CONNECTION_CONTEXT * pContext\r | |
7dc13291 | 26 | )\r |
27 | {\r | |
f6e5cdd5 | 28 | BOOLEAN bReadError;\r |
29 | size_t BytesRead;\r | |
30 | UINT64 LengthInBytes;\r | |
7dc13291 | 31 | \r |
32 | DBG_ENTER ( );\r | |
33 | \r | |
34 | //\r | |
f6e5cdd5 | 35 | // Use break instead of goto\r |
7dc13291 | 36 | //\r |
f6e5cdd5 | 37 | bReadError = FALSE;\r |
7dc13291 | 38 | for ( ; ; ) {\r |
39 | //\r | |
f6e5cdd5 | 40 | // Determine if there is any work to do\r |
41 | //\r | |
42 | LengthInBytes = DIM ( pContext->FileData ) >> 1;\r | |
43 | if (( pContext->ValidBytes > LengthInBytes )\r | |
44 | || ( 0 == pContext->BytesRemaining )) {\r | |
45 | break;\r | |
46 | }\r | |
47 | \r | |
48 | //\r | |
49 | // Determine the number of bytes to read\r | |
50 | //\r | |
51 | if ( LengthInBytes > pContext->BytesRemaining ) {\r | |
52 | LengthInBytes = pContext->BytesRemaining;\r | |
53 | }\r | |
54 | \r | |
55 | //\r | |
56 | // Read in the next portion of the file\r | |
57 | //\r | |
58 | BytesRead = fread ( pContext->pFill,\r | |
59 | 1,\r | |
60 | (size_t)LengthInBytes,\r | |
61 | pContext->File );\r | |
62 | if ( -1 == BytesRead ) {\r | |
63 | bReadError = TRUE;\r | |
7dc13291 | 64 | break;\r |
65 | }\r | |
66 | \r | |
f6e5cdd5 | 67 | //\r |
68 | // Account for the file data read\r | |
69 | //\r | |
70 | pContext->BytesRemaining -= BytesRead;\r | |
71 | pContext->ValidBytes += BytesRead;\r | |
72 | DEBUG (( DEBUG_FILE_BUFFER,\r | |
73 | "0x%08x: Buffer filled with %Ld bytes, %Ld bytes ramaining\r\n",\r | |
74 | pContext->pFill,\r | |
75 | BytesRead,\r | |
76 | pContext->BytesRemaining ));\r | |
77 | \r | |
78 | //\r | |
79 | // Set the next buffer location\r | |
80 | //\r | |
81 | pContext->pFill += BytesRead;\r | |
82 | if ( pContext->pEnd <= pContext->pFill ) {\r | |
83 | pContext->pFill = &pContext->FileData[ 0 ];\r | |
84 | }\r | |
85 | \r | |
86 | //\r | |
87 | // Verify that the end of the buffer is reached\r | |
88 | //\r | |
89 | ASSERT ( 0 == ( DIM ( pContext->FileData ) & 1 ));\r | |
90 | break;\r | |
91 | }\r | |
92 | \r | |
93 | //\r | |
94 | // Return the read status\r | |
95 | //\r | |
96 | DBG_EXIT ( );\r | |
97 | return bReadError;\r | |
98 | }\r | |
99 | \r | |
100 | \r | |
101 | /**\r | |
102 | Add a connection context to the list of connection contexts.\r | |
103 | \r | |
104 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r | |
105 | @param [in] SocketFd Socket file descriptor\r | |
106 | \r | |
107 | @retval Context structure address, NULL if allocation fails\r | |
108 | \r | |
109 | **/\r | |
110 | TSDT_CONNECTION_CONTEXT *\r | |
111 | ContextAdd (\r | |
112 | IN TSDT_TFTP_SERVER * pTftpServer,\r | |
113 | IN int SocketFd\r | |
114 | )\r | |
115 | {\r | |
116 | TSDT_CONNECTION_CONTEXT * pContext;\r | |
117 | TFTP_PACKET * pEnd;\r | |
118 | TFTP_PACKET * pPacket;\r | |
119 | \r | |
120 | DBG_ENTER ( );\r | |
121 | \r | |
122 | //\r | |
123 | // Allocate a new context\r | |
124 | //\r | |
125 | pContext = (TSDT_CONNECTION_CONTEXT *)AllocateZeroPool ( sizeof ( *pContext ));\r | |
126 | if ( NULL != pContext ) {\r | |
7dc13291 | 127 | //\r |
128 | // Initialize the context\r | |
129 | //\r | |
f6e5cdd5 | 130 | pContext->SocketFd = SocketFd;\r |
7dc13291 | 131 | CopyMem ( &pContext->RemoteAddress,\r |
132 | &pTftpServer->RemoteAddress,\r | |
133 | sizeof ( pContext->RemoteAddress ));\r | |
f6e5cdd5 | 134 | pContext->BlockSize = 512;\r |
135 | \r | |
136 | //\r | |
137 | // Buffer management\r | |
138 | //\r | |
139 | pContext->pFill = &pContext->FileData[ 0 ];\r | |
140 | pContext->pEnd = &pContext->FileData[ sizeof ( pContext->FileData )];\r | |
141 | pContext->pBuffer = pContext->pFill;\r | |
142 | \r | |
143 | //\r | |
144 | // Window management\r | |
145 | //\r | |
146 | pContext->MaxTimeout = MultU64x32 ( PcdGet32 ( Tftp_MaxTimeoutInSec ),\r | |
147 | 2 * 1000 * 1000 * 1000 );\r | |
148 | pContext->Rtt2x = pContext->MaxTimeout;\r | |
149 | pContext->WindowSize = MAX_PACKETS;\r | |
150 | WindowTimeout ( pContext );\r | |
151 | \r | |
152 | //\r | |
153 | // Place the packets on the free list\r | |
154 | //\r | |
155 | pPacket = &pContext->Tx[ 0 ];\r | |
156 | pEnd = &pPacket[ DIM ( pContext->Tx )];\r | |
157 | while ( pEnd > pPacket ) {\r | |
158 | PacketFree ( pContext, pPacket );\r | |
159 | pPacket += 1;\r | |
160 | }\r | |
7dc13291 | 161 | \r |
162 | //\r | |
163 | // Display the new context\r | |
164 | //\r | |
f6e5cdd5 | 165 | if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r |
166 | DEBUG (( DEBUG_PORT_WORK,\r | |
167 | "0x%08x: Context for %d.%d.%d.%d:%d\r\n",\r | |
168 | pContext,\r | |
169 | (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r | |
170 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r | |
171 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r | |
172 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r | |
173 | htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r | |
174 | }\r | |
175 | else {\r | |
176 | DEBUG (( DEBUG_PORT_WORK,\r | |
177 | "0x%08x: Context for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r | |
178 | pContext,\r | |
179 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r | |
180 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r | |
181 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r | |
182 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r | |
183 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r | |
184 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r | |
185 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r | |
186 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r | |
187 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r | |
188 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r | |
189 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r | |
190 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r | |
191 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r | |
192 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r | |
193 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r | |
194 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r | |
195 | htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r | |
196 | }\r | |
7dc13291 | 197 | \r |
198 | //\r | |
199 | // Add the context to the context list\r | |
200 | //\r | |
201 | pContext->pNext = pTftpServer->pContextList;\r | |
202 | pTftpServer->pContextList = pContext;\r | |
7dc13291 | 203 | }\r |
204 | \r | |
205 | //\r | |
206 | // Return the connection context\r | |
207 | //\r | |
208 | DBG_EXIT_STATUS ( pContext );\r | |
209 | return pContext;\r | |
210 | }\r | |
211 | \r | |
212 | \r | |
213 | /**\r | |
214 | Locate a remote connection context.\r | |
215 | \r | |
f6e5cdd5 | 216 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r |
7dc13291 | 217 | @param [in] pIpAddress The start of the remote IP address in network order\r |
7dc13291 | 218 | @param [in] Port The remote port number\r |
219 | \r | |
220 | @retval Context structure address, NULL if not found\r | |
221 | \r | |
222 | **/\r | |
223 | TSDT_CONNECTION_CONTEXT *\r | |
224 | ContextFind (\r | |
225 | IN TSDT_TFTP_SERVER * pTftpServer\r | |
226 | )\r | |
227 | {\r | |
228 | TSDT_CONNECTION_CONTEXT * pContext;\r | |
229 | \r | |
230 | DBG_ENTER ( );\r | |
231 | \r | |
232 | //\r | |
233 | // Walk the list of connection contexts\r | |
234 | //\r | |
235 | pContext = pTftpServer->pContextList;\r | |
236 | while ( NULL != pContext ) {\r | |
237 | //\r | |
238 | // Attempt to locate the remote network connection\r | |
239 | //\r | |
f6e5cdd5 | 240 | if ( 0 == memcmp ( &pTftpServer->RemoteAddress,\r |
241 | &pContext->RemoteAddress,\r | |
242 | pTftpServer->RemoteAddress.v6.sin6_len )) {\r | |
7dc13291 | 243 | //\r |
244 | // The connection was found\r | |
245 | //\r | |
246 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
247 | "0x%08x: pContext found\r\n",\r | |
248 | pContext ));\r | |
249 | break;\r | |
250 | }\r | |
251 | \r | |
252 | //\r | |
253 | // Set the next context\r | |
254 | //\r | |
255 | pContext = pContext->pNext;\r | |
256 | }\r | |
257 | \r | |
258 | //\r | |
259 | // Return the connection context structure address\r | |
260 | //\r | |
261 | DBG_EXIT_HEX ( pContext );\r | |
262 | return pContext;\r | |
263 | }\r | |
264 | \r | |
265 | \r | |
266 | /**\r | |
267 | Remove a context from the list.\r | |
268 | \r | |
f6e5cdd5 | 269 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r |
270 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r | |
7dc13291 | 271 | \r |
272 | **/\r | |
273 | VOID\r | |
274 | ContextRemove (\r | |
275 | IN TSDT_TFTP_SERVER * pTftpServer,\r | |
276 | IN TSDT_CONNECTION_CONTEXT * pContext\r | |
277 | )\r | |
278 | {\r | |
279 | TSDT_CONNECTION_CONTEXT * pNextContext;\r | |
280 | TSDT_CONNECTION_CONTEXT * pPreviousContext;\r | |
281 | \r | |
282 | DBG_ENTER ( );\r | |
283 | \r | |
284 | //\r | |
285 | // Attempt to locate the context in the list\r | |
286 | //\r | |
287 | pPreviousContext = NULL;\r | |
288 | pNextContext = pTftpServer->pContextList;\r | |
289 | while ( NULL != pNextContext ) {\r | |
290 | //\r | |
291 | // Determine if the context was found\r | |
292 | //\r | |
293 | if ( pNextContext == pContext ) {\r | |
294 | //\r | |
295 | // Remove the context from the list\r | |
296 | //\r | |
297 | if ( NULL == pPreviousContext ) {\r | |
298 | pTftpServer->pContextList = pContext->pNext;\r | |
299 | }\r | |
300 | else {\r | |
301 | pPreviousContext->pNext = pContext->pNext;\r | |
302 | }\r | |
303 | break;\r | |
304 | }\r | |
305 | \r | |
306 | //\r | |
307 | // Set the next context\r | |
308 | //\r | |
309 | pPreviousContext = pNextContext;\r | |
310 | pNextContext = pNextContext->pNext;\r | |
311 | }\r | |
312 | \r | |
313 | //\r | |
314 | // Determine if the context was found\r | |
315 | //\r | |
316 | if ( NULL != pContext ) {\r | |
317 | //\r | |
318 | // Return the resources\r | |
319 | //\r | |
320 | gBS->FreePool ( pContext );\r | |
321 | }\r | |
322 | \r | |
323 | DBG_EXIT ( );\r | |
324 | }\r | |
325 | \r | |
326 | \r | |
327 | /**\r | |
f6e5cdd5 | 328 | Queue data packets for transmission\r |
329 | \r | |
330 | @param [in] pContext Connection context structure address\r | |
7dc13291 | 331 | \r |
f6e5cdd5 | 332 | @retval TRUE if a read error occurred\r |
7dc13291 | 333 | \r |
334 | **/\r | |
f6e5cdd5 | 335 | BOOLEAN\r |
336 | PacketFill (\r | |
337 | IN TSDT_CONNECTION_CONTEXT * pContext\r | |
7dc13291 | 338 | )\r |
339 | {\r | |
f6e5cdd5 | 340 | BOOLEAN bReadError;\r |
341 | UINT64 LengthInBytes;\r | |
342 | UINT8 * pBuffer;\r | |
343 | TFTP_PACKET * pPacket;\r | |
7dc13291 | 344 | \r |
345 | DBG_ENTER ( );\r | |
346 | \r | |
347 | //\r | |
f6e5cdd5 | 348 | // Use break instead of goto\r |
7dc13291 | 349 | //\r |
f6e5cdd5 | 350 | bReadError = FALSE;\r |
351 | for ( ; ; ) {\r | |
7dc13291 | 352 | //\r |
f6e5cdd5 | 353 | // Fill the buffer if necessary\r |
7dc13291 | 354 | //\r |
f6e5cdd5 | 355 | bReadError = BufferFill ( pContext );\r |
356 | if ( bReadError ) {\r | |
7dc13291 | 357 | //\r |
f6e5cdd5 | 358 | // File access mode not supported\r |
7dc13291 | 359 | //\r |
f6e5cdd5 | 360 | DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r |
361 | "ERROR - File read failure!\r\n" ));\r | |
7dc13291 | 362 | \r |
363 | //\r | |
f6e5cdd5 | 364 | // Tell the client of the error\r |
7dc13291 | 365 | //\r |
f6e5cdd5 | 366 | SendError ( pContext,\r |
367 | TFTP_ERROR_SEE_MSG,\r | |
368 | (UINT8 *)"Read failure" );\r | |
369 | break;\r | |
7dc13291 | 370 | }\r |
f6e5cdd5 | 371 | \r |
372 | //\r | |
373 | // Determine if any packets can be filled\r | |
374 | //\r | |
375 | if ( pContext->bEofSent\r | |
376 | || ( NULL == pContext->pFreeList )) {\r | |
7dc13291 | 377 | //\r |
f6e5cdd5 | 378 | // All of the packets are filled\r |
7dc13291 | 379 | //\r |
f6e5cdd5 | 380 | break;\r |
7dc13291 | 381 | }\r |
7dc13291 | 382 | \r |
7dc13291 | 383 | //\r |
f6e5cdd5 | 384 | // Set the TFTP opcode and block number\r |
385 | //\r | |
386 | pPacket = PacketGet ( pContext );\r | |
387 | pBuffer = &pPacket->TxBuffer[ 0 ];\r | |
388 | *pBuffer++ = 0;\r | |
389 | *pBuffer++ = TFTP_OP_DATA;\r | |
390 | *pBuffer++ = (UINT8)( pContext->BlockNumber >> 8 );\r | |
391 | *pBuffer++ = (UINT8)pContext->BlockNumber;\r | |
392 | \r | |
393 | //\r | |
394 | // Determine how much data needs to be sent\r | |
395 | //\r | |
396 | LengthInBytes = pContext->BlockSize;\r | |
397 | if (( pContext->BytesToSend < TFTP_MAX_BLOCK_SIZE )\r | |
398 | && ( LengthInBytes > pContext->BytesToSend )) {\r | |
399 | LengthInBytes = pContext->BytesToSend;\r | |
400 | pContext->bEofSent = TRUE;\r | |
401 | }\r | |
402 | DEBUG (( DEBUG_TX_PACKET,\r | |
403 | "0x%08x: Packet, Block %d filled with %d bytes\r\n",\r | |
404 | pPacket,\r | |
405 | pContext->BlockNumber,\r | |
406 | (UINT32)LengthInBytes ));\r | |
407 | \r | |
408 | //\r | |
409 | // Copy the file data into the packet\r | |
410 | //\r | |
411 | pPacket->TxBytes = (ssize_t)( 2 + 2 + LengthInBytes );\r | |
412 | if ( 0 < LengthInBytes ) {\r | |
413 | CopyMem ( pBuffer,\r | |
414 | pContext->pBuffer,\r | |
415 | (UINTN)LengthInBytes );\r | |
416 | DEBUG (( DEBUG_FILE_BUFFER,\r | |
417 | "0x%08x: Buffer consumed %d bytes of file data\r\n",\r | |
418 | pContext->pBuffer,\r | |
419 | LengthInBytes ));\r | |
420 | \r | |
421 | //\r | |
422 | // Account for the file data consumed\r | |
423 | //\r | |
424 | pContext->ValidBytes -= LengthInBytes;\r | |
425 | pContext->BytesToSend -= LengthInBytes;\r | |
426 | pContext->pBuffer += LengthInBytes;\r | |
427 | if ( pContext->pEnd <= pContext->pBuffer ) {\r | |
428 | pContext->pBuffer = &pContext->FileData[ 0 ];\r | |
429 | }\r | |
430 | }\r | |
431 | \r | |
432 | //\r | |
433 | // Queue the packet for transmission\r | |
7dc13291 | 434 | //\r |
f6e5cdd5 | 435 | PacketQueue ( pContext, pPacket );\r |
7dc13291 | 436 | }\r |
437 | \r | |
f6e5cdd5 | 438 | //\r |
439 | // Return the read status\r | |
440 | //\r | |
7dc13291 | 441 | DBG_EXIT ( );\r |
f6e5cdd5 | 442 | return bReadError;\r |
7dc13291 | 443 | }\r |
444 | \r | |
445 | \r | |
446 | /**\r | |
f6e5cdd5 | 447 | Free the packet\r |
7dc13291 | 448 | \r |
f6e5cdd5 | 449 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r |
450 | @param [in] pPacket Address of a ::TFTP_PACKET structure\r | |
7dc13291 | 451 | \r |
452 | **/\r | |
453 | VOID\r | |
f6e5cdd5 | 454 | PacketFree(\r |
455 | IN TSDT_CONNECTION_CONTEXT * pContext,\r | |
456 | IN TFTP_PACKET * pPacket\r | |
7dc13291 | 457 | )\r |
458 | {\r | |
f6e5cdd5 | 459 | DBG_ENTER ( );\r |
7dc13291 | 460 | \r |
461 | //\r | |
f6e5cdd5 | 462 | // Don't free the error packet\r |
7dc13291 | 463 | //\r |
f6e5cdd5 | 464 | if ( pPacket != &pContext->ErrorPacket ) {\r |
7dc13291 | 465 | //\r |
f6e5cdd5 | 466 | // Place the packet on the free list\r |
7dc13291 | 467 | //\r |
f6e5cdd5 | 468 | pPacket->pNext = pContext->pFreeList;\r |
469 | pContext->pFreeList = pPacket;\r | |
470 | DEBUG (( DEBUG_TX_PACKET,\r | |
471 | "0x%08x: Packet queued to free list\r\n",\r | |
472 | pPacket ));\r | |
7dc13291 | 473 | }\r |
474 | \r | |
f6e5cdd5 | 475 | DBG_EXIT ( );\r |
7dc13291 | 476 | }\r |
477 | \r | |
478 | \r | |
479 | /**\r | |
f6e5cdd5 | 480 | Get a packet from the free list for transmission\r |
7dc13291 | 481 | \r |
f6e5cdd5 | 482 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r |
7dc13291 | 483 | \r |
f6e5cdd5 | 484 | @retval Address of a ::TFTP_PACKET structure\r |
7dc13291 | 485 | \r |
486 | **/\r | |
f6e5cdd5 | 487 | TFTP_PACKET *\r |
488 | PacketGet (\r | |
489 | IN TSDT_CONNECTION_CONTEXT * pContext\r | |
7dc13291 | 490 | )\r |
491 | {\r | |
f6e5cdd5 | 492 | TFTP_PACKET * pPacket;\r |
493 | \r | |
494 | DBG_ENTER ( );\r | |
495 | \r | |
7dc13291 | 496 | //\r |
f6e5cdd5 | 497 | // Get the next packet from the free list\r |
7dc13291 | 498 | //\r |
f6e5cdd5 | 499 | pPacket = pContext->pFreeList;\r |
500 | if ( NULL != pPacket ) {\r | |
501 | pContext->pFreeList = pPacket->pNext;\r | |
502 | pPacket->RetryCount = 0;\r | |
503 | DEBUG (( DEBUG_TX_PACKET,\r | |
504 | "0x%08x: Packet removed from free list\r\n",\r | |
505 | pPacket ));\r | |
7dc13291 | 506 | }\r |
507 | \r | |
508 | //\r | |
f6e5cdd5 | 509 | // Return the packet\r |
7dc13291 | 510 | //\r |
f6e5cdd5 | 511 | DBG_EXIT_HEX ( pPacket );\r |
512 | return pPacket;\r | |
7dc13291 | 513 | }\r |
514 | \r | |
515 | \r | |
516 | /**\r | |
f6e5cdd5 | 517 | Queue the packet for transmission\r |
7dc13291 | 518 | \r |
f6e5cdd5 | 519 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r |
520 | @param [in] pPacket Address of a ::TFTP_PACKET structure\r | |
7dc13291 | 521 | \r |
f6e5cdd5 | 522 | @retval TRUE if a transmission error has occurred\r |
7dc13291 | 523 | \r |
524 | **/\r | |
f6e5cdd5 | 525 | BOOLEAN\r |
526 | PacketQueue (\r | |
527 | IN TSDT_CONNECTION_CONTEXT * pContext,\r | |
528 | IN TFTP_PACKET * pPacket\r | |
7dc13291 | 529 | )\r |
530 | {\r | |
f6e5cdd5 | 531 | BOOLEAN bTransmitError;\r |
532 | TFTP_PACKET * pTail;\r | |
533 | EFI_STATUS Status;\r | |
534 | \r | |
535 | DBG_ENTER ( );\r | |
7dc13291 | 536 | \r |
537 | //\r | |
f6e5cdd5 | 538 | // Account for this data block\r |
7dc13291 | 539 | //\r |
f6e5cdd5 | 540 | pPacket->BlockNumber = pContext->BlockNumber;\r |
541 | pContext->BlockNumber += 1;\r | |
7dc13291 | 542 | \r |
f6e5cdd5 | 543 | //\r |
544 | // Queue the packet for transmission\r | |
545 | //\r | |
546 | pTail = pContext->pTxTail;\r | |
547 | if ( NULL == pTail ) {\r | |
548 | pContext->pTxHead = pPacket;\r | |
549 | }\r | |
550 | else {\r | |
551 | pTail->pNext = pPacket;\r | |
552 | }\r | |
553 | pContext->pTxTail = pPacket;\r | |
554 | pPacket->pNext = NULL;\r | |
555 | DEBUG (( DEBUG_TX_PACKET,\r | |
556 | "0x%08x: Packet queued to TX list\r\n",\r | |
557 | pPacket ));\r | |
7dc13291 | 558 | \r |
f6e5cdd5 | 559 | //\r |
560 | // Start the transmission if necessary\r | |
561 | //\r | |
562 | bTransmitError = FALSE;\r | |
563 | if ( pContext->PacketsInWindow < pContext->WindowSize ) {\r | |
564 | Status = PacketTx ( pContext, pPacket );\r | |
565 | bTransmitError = (BOOLEAN)( EFI_ERROR ( Status ));\r | |
566 | }\r | |
567 | \r | |
568 | //\r | |
569 | // Return the transmit status\r | |
570 | //\r | |
571 | DBG_EXIT_TF ( bTransmitError );\r | |
572 | return bTransmitError;\r | |
573 | }\r | |
574 | \r | |
575 | \r | |
576 | /**\r | |
577 | Remove a packet from the transmit queue\r | |
578 | \r | |
579 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r | |
580 | \r | |
581 | **/\r | |
582 | TFTP_PACKET *\r | |
583 | PacketRemove(\r | |
584 | IN TSDT_CONNECTION_CONTEXT * pContext\r | |
585 | )\r | |
586 | {\r | |
587 | TFTP_PACKET * pNext;\r | |
588 | TFTP_PACKET * pPacket;\r | |
589 | \r | |
590 | DBG_ENTER ( );\r | |
591 | \r | |
592 | //\r | |
593 | // Remove a packet from the transmit queue\r | |
594 | //\r | |
595 | //\r | |
596 | pPacket = pContext->pTxHead;\r | |
597 | if ( NULL != pPacket ) {\r | |
598 | pNext = pPacket->pNext;\r | |
599 | pContext->pTxHead = pNext;\r | |
600 | if ( NULL == pNext ) {\r | |
601 | pContext->pTxTail = NULL;\r | |
7dc13291 | 602 | }\r |
f6e5cdd5 | 603 | DEBUG (( DEBUG_TX_PACKET,\r |
604 | "0x%08x: Packet removed from TX list\r\n",\r | |
605 | pPacket ));\r | |
7dc13291 | 606 | \r |
607 | //\r | |
f6e5cdd5 | 608 | // Remove this packet from the window\r |
7dc13291 | 609 | //\r |
f6e5cdd5 | 610 | pContext->PacketsInWindow -= 1;\r |
611 | }\r | |
7dc13291 | 612 | \r |
613 | //\r | |
f6e5cdd5 | 614 | // Return the packet\r |
7dc13291 | 615 | //\r |
f6e5cdd5 | 616 | DBG_EXIT_HEX ( pPacket );\r |
617 | return pPacket;\r | |
7dc13291 | 618 | }\r |
619 | \r | |
620 | \r | |
621 | /**\r | |
f6e5cdd5 | 622 | Transmit the packet\r |
7dc13291 | 623 | \r |
f6e5cdd5 | 624 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r |
625 | @param [in] pPacket Address of a ::TFTP_PACKET structure\r | |
7dc13291 | 626 | \r |
627 | @retval EFI_SUCCESS Message processed successfully\r | |
628 | \r | |
629 | **/\r | |
630 | EFI_STATUS\r | |
f6e5cdd5 | 631 | PacketTx (\r |
632 | IN TSDT_CONNECTION_CONTEXT * pContext,\r | |
633 | IN TFTP_PACKET * pPacket\r | |
7dc13291 | 634 | )\r |
635 | {\r | |
f6e5cdd5 | 636 | ssize_t LengthInBytes;\r |
7dc13291 | 637 | EFI_STATUS Status;\r |
638 | \r | |
f6e5cdd5 | 639 | DBG_ENTER ( );\r |
640 | \r | |
7dc13291 | 641 | //\r |
f6e5cdd5 | 642 | // Assume success\r |
7dc13291 | 643 | //\r |
f6e5cdd5 | 644 | Status = EFI_SUCCESS;\r |
645 | \r | |
646 | //\r | |
647 | // Determine if this packet should be transmitted\r | |
648 | //\r | |
649 | if ( PcdGet32 ( Tftp_MaxRetry ) >= pPacket->RetryCount ) {\r | |
650 | pPacket->RetryCount += 1;\r | |
651 | \r | |
7dc13291 | 652 | //\r |
f6e5cdd5 | 653 | // Display the operation\r |
7dc13291 | 654 | //\r |
f6e5cdd5 | 655 | DEBUG (( DEBUG_TX_PACKET,\r |
656 | "0x%08x: Packet transmiting\r\n",\r | |
657 | pPacket ));\r | |
658 | DEBUG (( DEBUG_TX,\r | |
659 | "0x%08x: pContext sending 0x%08x bytes\r\n",\r | |
660 | pContext,\r | |
661 | pPacket->TxBytes ));\r | |
662 | \r | |
7dc13291 | 663 | //\r |
f6e5cdd5 | 664 | // Keep track of when the packet was transmitted\r |
7dc13291 | 665 | //\r |
f6e5cdd5 | 666 | if ( PcdGetBool ( Tftp_HighSpeed )) {\r |
667 | pPacket->TxTime = GetPerformanceCounter ( );\r | |
668 | }\r | |
7dc13291 | 669 | \r |
670 | //\r | |
f6e5cdd5 | 671 | // Send the TFTP packet\r |
7dc13291 | 672 | //\r |
f6e5cdd5 | 673 | pContext->PacketsInWindow += 1;\r |
674 | LengthInBytes = sendto ( pContext->SocketFd,\r | |
675 | &pPacket->TxBuffer[ 0 ],\r | |
676 | pPacket->TxBytes,\r | |
677 | 0,\r | |
678 | (struct sockaddr *)&pContext->RemoteAddress,\r | |
679 | pContext->RemoteAddress.sin6_len );\r | |
680 | if ( -1 == LengthInBytes ) {\r | |
681 | DEBUG (( DEBUG_ERROR | DEBUG_TX,\r | |
682 | "ERROR - Transmit failure, errno: 0x%08x\r\n",\r | |
683 | errno ));\r | |
684 | pContext->PacketsInWindow -= 1;\r | |
685 | Status = EFI_DEVICE_ERROR;\r | |
686 | }\r | |
687 | }\r | |
688 | else {\r | |
689 | //\r | |
690 | // Too many retries\r | |
691 | //\r | |
692 | Status = EFI_NO_RESPONSE;\r | |
693 | DEBUG (( DEBUG_WARN | DEBUG_WINDOW,\r | |
694 | "WARNING - No response from TFTP client\r\n" ));\r | |
7dc13291 | 695 | }\r |
7dc13291 | 696 | \r |
697 | //\r | |
698 | // Return the operation status\r | |
699 | //\r | |
f6e5cdd5 | 700 | DBG_EXIT_STATUS ( Status );\r |
7dc13291 | 701 | return Status;\r |
702 | }\r | |
703 | \r | |
704 | \r | |
705 | /**\r | |
f6e5cdd5 | 706 | Process the work for the sockets.\r |
7dc13291 | 707 | \r |
f6e5cdd5 | 708 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r |
709 | @param [in] pIndex Address of an index into the pollfd array\r | |
7dc13291 | 710 | \r |
711 | **/\r | |
f6e5cdd5 | 712 | VOID\r |
713 | PortWork (\r | |
714 | IN TSDT_TFTP_SERVER * pTftpServer,\r | |
715 | IN int * pIndex\r | |
7dc13291 | 716 | )\r |
717 | {\r | |
f6e5cdd5 | 718 | int Index;\r |
719 | TSDT_CONNECTION_CONTEXT * pContext;\r | |
720 | struct pollfd * pTftpPort;\r | |
721 | socklen_t RemoteAddressLength;\r | |
722 | int revents;\r | |
7dc13291 | 723 | \r |
f6e5cdd5 | 724 | DBG_ENTER ( );\r |
7dc13291 | 725 | \r |
726 | //\r | |
f6e5cdd5 | 727 | // Locate the port\r |
728 | //\r | |
729 | Index = *pIndex;\r | |
730 | if ( -1 != Index ) {\r | |
731 | pTftpPort = &pTftpServer->TftpPort[ *pIndex ];\r | |
732 | \r | |
733 | //\r | |
734 | // Handle input events\r | |
735 | //\r | |
736 | revents = pTftpPort->revents;\r | |
737 | pTftpPort->revents = 0;\r | |
738 | if ( 0 != ( revents & POLLRDNORM )) {\r | |
739 | //\r | |
740 | // Receive the message from the remote system\r | |
741 | //\r | |
742 | RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress );\r | |
743 | pTftpServer->RxBytes = recvfrom ( pTftpPort->fd,\r | |
744 | &pTftpServer->RxBuffer[ 0 ],\r | |
745 | sizeof ( pTftpServer->RxBuffer ),\r | |
746 | 0,\r | |
747 | (struct sockaddr *) &pTftpServer->RemoteAddress,\r | |
748 | &RemoteAddressLength );\r | |
749 | if ( -1 != pTftpServer->RxBytes ) {\r | |
750 | if ( PcdGetBool ( Tftp_HighSpeed )) {\r | |
751 | pTftpServer->RxTime = GetPerformanceCounter ( );\r | |
752 | }\r | |
753 | if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r | |
754 | DEBUG (( DEBUG_TFTP_PORT,\r | |
755 | "Received %d bytes from %d.%d.%d.%d:%d\r\n",\r | |
756 | pTftpServer->RxBytes,\r | |
757 | pTftpServer->RemoteAddress.v4.sin_addr.s_addr & 0xff,\r | |
758 | ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ) & 0xff,\r | |
759 | ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ) & 0xff,\r | |
760 | ( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ) & 0xff,\r | |
761 | htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r | |
762 | }\r | |
763 | else {\r | |
764 | DEBUG (( DEBUG_TFTP_PORT,\r | |
765 | "Received %d bytes from [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r | |
766 | pTftpServer->RxBytes,\r | |
767 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r | |
768 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r | |
769 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r | |
770 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r | |
771 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r | |
772 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r | |
773 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r | |
774 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r | |
775 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r | |
776 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r | |
777 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r | |
778 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r | |
779 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r | |
780 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r | |
781 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r | |
782 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r | |
783 | htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r | |
784 | }\r | |
785 | \r | |
786 | //\r | |
787 | // Lookup connection context using the remote system address and port\r | |
788 | // to determine if an existing connection to this remote\r | |
789 | // system exists\r | |
790 | //\r | |
791 | pContext = ContextFind ( pTftpServer );\r | |
792 | \r | |
793 | //\r | |
794 | // Process the received message\r | |
795 | //\r | |
796 | TftpProcessRequest ( pTftpServer, pContext, pTftpPort->fd );\r | |
797 | }\r | |
798 | else {\r | |
799 | //\r | |
800 | // Receive error on the TFTP server port\r | |
801 | // Close the server socket\r | |
802 | //\r | |
803 | DEBUG (( DEBUG_ERROR,\r | |
804 | "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n",\r | |
805 | errno ));\r | |
806 | revents |= POLLHUP;\r | |
807 | }\r | |
808 | }\r | |
809 | \r | |
810 | //\r | |
811 | // Handle the close event\r | |
812 | //\r | |
813 | if ( 0 != ( revents & POLLHUP )) {\r | |
814 | //\r | |
815 | // Close the port\r | |
816 | //\r | |
817 | close ( pTftpPort->fd );\r | |
818 | pTftpPort->fd = -1;\r | |
819 | *pIndex = -1;\r | |
820 | pTftpServer->Entries -= 1;\r | |
821 | ASSERT ( 0 <= pTftpServer->Entries );\r | |
822 | }\r | |
823 | }\r | |
824 | \r | |
825 | DBG_EXIT ( );\r | |
826 | }\r | |
827 | \r | |
828 | \r | |
829 | /**\r | |
830 | Build and send an error packet\r | |
831 | \r | |
832 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r | |
833 | @param [in] Error Error number for the packet\r | |
834 | @param [in] pError Zero terminated error string address\r | |
835 | \r | |
836 | @retval EFI_SUCCESS Message processed successfully\r | |
837 | \r | |
838 | **/\r | |
839 | EFI_STATUS\r | |
840 | SendError (\r | |
841 | IN TSDT_CONNECTION_CONTEXT * pContext,\r | |
842 | IN UINT16 Error,\r | |
843 | IN UINT8 * pError\r | |
844 | )\r | |
845 | {\r | |
846 | UINT8 Character;\r | |
847 | UINT8 * pBuffer;\r | |
848 | TFTP_PACKET * pPacket;\r | |
849 | EFI_STATUS Status;\r | |
850 | \r | |
851 | DBG_ENTER ( );\r | |
852 | \r | |
853 | //\r | |
854 | // Build the error packet\r | |
855 | //\r | |
856 | pPacket = &pContext->ErrorPacket;\r | |
857 | pBuffer = &pPacket->TxBuffer[ 0 ];\r | |
858 | pBuffer[ 0 ] = 0;\r | |
859 | pBuffer[ 1 ] = TFTP_OP_ERROR;\r | |
860 | pBuffer[ 2 ] = (UINT8)( Error >> 8 );\r | |
861 | pBuffer[ 3 ] = (UINT8)Error;\r | |
862 | \r | |
863 | //\r | |
864 | // Copy the zero terminated string into the buffer\r | |
865 | //\r | |
866 | pBuffer += 4;\r | |
867 | do {\r | |
868 | Character = *pError++;\r | |
869 | *pBuffer++ = Character;\r | |
870 | } while ( 0 != Character );\r | |
871 | \r | |
872 | //\r | |
873 | // Send the error message\r | |
874 | //\r | |
875 | pPacket->TxBytes = pBuffer - &pPacket->TxBuffer[ 0 ];\r | |
876 | Status = PacketTx ( pContext, pPacket );\r | |
877 | \r | |
878 | //\r | |
879 | // Return the operation status\r | |
880 | //\r | |
881 | DBG_EXIT_STATUS ( Status );\r | |
882 | return Status;\r | |
883 | }\r | |
884 | \r | |
885 | \r | |
886 | /**\r | |
887 | Scan the list of sockets and process any pending work\r | |
888 | \r | |
889 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r | |
890 | \r | |
891 | **/\r | |
892 | VOID\r | |
893 | SocketPoll (\r | |
894 | IN TSDT_TFTP_SERVER * pTftpServer\r | |
895 | )\r | |
896 | {\r | |
897 | int FDCount;\r | |
898 | \r | |
899 | DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" ));\r | |
900 | \r | |
901 | //\r | |
902 | // Determine if any ports are active\r | |
903 | //\r | |
904 | if ( 0 != pTftpServer->Entries ) {\r | |
905 | FDCount = poll ( &pTftpServer->TftpPort[ 0 ],\r | |
906 | pTftpServer->Entries,\r | |
907 | CLIENT_POLL_DELAY );\r | |
908 | if ( 0 < FDCount ) {\r | |
909 | //\r | |
910 | // Process this port\r | |
911 | //\r | |
912 | PortWork ( pTftpServer, &pTftpServer->Udpv4Index );\r | |
913 | PortWork ( pTftpServer, &pTftpServer->Udpv6Index );\r | |
914 | }\r | |
915 | }\r | |
916 | \r | |
917 | DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" ));\r | |
918 | }\r | |
919 | \r | |
920 | \r | |
921 | /**\r | |
922 | Process the ACK\r | |
923 | \r | |
924 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r | |
925 | @param [in] pContext Connection context structure address\r | |
926 | \r | |
927 | @retval TRUE if the context should be closed\r | |
928 | \r | |
929 | **/\r | |
930 | BOOLEAN\r | |
931 | TftpAck (\r | |
932 | IN TSDT_TFTP_SERVER * pTftpServer,\r | |
933 | IN TSDT_CONNECTION_CONTEXT * pContext\r | |
934 | )\r | |
935 | {\r | |
936 | INTN AckNumber;\r | |
937 | BOOLEAN bCloseContext;\r | |
938 | UINT16 BlockNumber;\r | |
939 | UINT8 * pBuffer;\r | |
940 | TFTP_PACKET * pPacket;\r | |
941 | EFI_STATUS Status;\r | |
942 | \r | |
943 | DBG_ENTER ( );\r | |
944 | \r | |
945 | //\r | |
946 | // Use break instead of goto\r | |
947 | //\r | |
948 | bCloseContext = FALSE;\r | |
949 | for ( ; ; ) {\r | |
950 | //\r | |
951 | // Validate the parameters\r | |
952 | //\r | |
953 | if ( NULL == pContext ) {\r | |
954 | if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r | |
955 | DEBUG (( DEBUG_ERROR,\r | |
956 | "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r | |
957 | (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r | |
958 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r | |
959 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r | |
960 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r | |
961 | htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r | |
962 | }\r | |
963 | else {\r | |
964 | DEBUG (( DEBUG_ERROR,\r | |
965 | "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r | |
966 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r | |
967 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r | |
968 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r | |
969 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r | |
970 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r | |
971 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r | |
972 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r | |
973 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r | |
974 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r | |
975 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r | |
976 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r | |
977 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r | |
978 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r | |
979 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r | |
980 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r | |
981 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r | |
982 | htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r | |
983 | }\r | |
984 | break;\r | |
985 | }\r | |
986 | \r | |
987 | //\r | |
988 | // Verify that the ACK was expected\r | |
989 | //\r | |
990 | pPacket = pContext->pTxHead;\r | |
991 | if ( NULL == pPacket ) {\r | |
992 | //\r | |
993 | // ACK not expected!\r | |
994 | //\r | |
995 | DEBUG (( DEBUG_ERROR,\r | |
996 | "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n",\r | |
997 | pContext ));\r | |
998 | break;\r | |
999 | }\r | |
1000 | \r | |
1001 | //\r | |
1002 | // Get the ACKed block number\r | |
1003 | //\r | |
1004 | pBuffer = &pTftpServer->RxBuffer[ 0 ];\r | |
1005 | BlockNumber = HTONS ( *(UINT16 *)&pBuffer[ 2 ]);\r | |
1006 | \r | |
1007 | //\r | |
1008 | // Determine if this is the correct ACK\r | |
1009 | //\r | |
1010 | DEBUG (( DEBUG_TFTP_ACK,\r | |
1011 | "ACK for block 0x%04x received\r\n",\r | |
1012 | BlockNumber ));\r | |
1013 | AckNumber = BlockNumber - pPacket->BlockNumber;\r | |
1014 | if (( 0 > AckNumber ) || ( AckNumber >= (INTN)pContext->PacketsInWindow )){\r | |
1015 | DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK,\r | |
1016 | "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n",\r | |
1017 | pPacket->BlockNumber,\r | |
1018 | BlockNumber ));\r | |
1019 | break;\r | |
1020 | }\r | |
1021 | \r | |
1022 | //\r | |
1023 | // Release the ACKed packets\r | |
1024 | //\r | |
1025 | do {\r | |
1026 | //\r | |
1027 | // Remove the packet from the transmit list and window\r | |
1028 | //\r | |
1029 | pPacket = PacketRemove ( pContext );\r | |
1030 | \r | |
1031 | //\r | |
1032 | // Get the block number of this packet\r | |
1033 | //\r | |
1034 | AckNumber = pPacket->BlockNumber;\r | |
1035 | \r | |
1036 | //\r | |
1037 | // Increase the size of the transmit window\r | |
1038 | //\r | |
1039 | if ( PcdGetBool ( Tftp_HighSpeed )\r | |
1040 | && ( AckNumber == BlockNumber )) {\r | |
1041 | WindowAck ( pTftpServer, pContext, pPacket );\r | |
1042 | }\r | |
1043 | \r | |
1044 | //\r | |
1045 | // Free this packet\r | |
1046 | //\r | |
1047 | PacketFree ( pContext, pPacket );\r | |
1048 | } while (( NULL != pContext->pTxHead ) && ( AckNumber != BlockNumber ));\r | |
1049 | \r | |
1050 | //\r | |
1051 | // Fill the window with packets\r | |
1052 | //\r | |
1053 | pPacket = pContext->pTxHead;\r | |
1054 | while (( NULL != pPacket )\r | |
1055 | && ( pContext->PacketsInWindow < pContext->WindowSize )\r | |
1056 | && ( !bCloseContext )) {\r | |
1057 | Status = PacketTx ( pContext, pPacket );\r | |
1058 | bCloseContext = (BOOLEAN)( EFI_ERROR ( Status ));\r | |
1059 | pPacket = pPacket->pNext;\r | |
1060 | }\r | |
1061 | \r | |
1062 | //\r | |
1063 | // Get more packets ready for transmission\r | |
1064 | //\r | |
1065 | PacketFill ( pContext );\r | |
1066 | \r | |
1067 | //\r | |
1068 | // Close the context when the last packet is ACKed\r | |
1069 | //\r | |
1070 | if ( 0 == pContext->PacketsInWindow ) {\r | |
1071 | bCloseContext = TRUE;\r | |
1072 | \r | |
1073 | //\r | |
1074 | // Display the bandwidth\r | |
1075 | //\r | |
1076 | if ( PcdGetBool ( Tftp_Bandwidth )) {\r | |
1077 | UINT64 Bandwidth;\r | |
1078 | UINT64 DeltaTime;\r | |
1079 | UINT64 NanoSeconds;\r | |
1080 | UINT32 Value;\r | |
1081 | \r | |
1082 | //\r | |
1083 | // Compute the download time\r | |
1084 | //\r | |
1085 | DeltaTime = GetPerformanceCounter ( );\r | |
1086 | if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r | |
1087 | DeltaTime = DeltaTime - pContext->TimeStart;\r | |
1088 | }\r | |
1089 | else {\r | |
1090 | DeltaTime = pContext->TimeStart - DeltaTime;\r | |
1091 | }\r | |
1092 | NanoSeconds = GetTimeInNanoSecond ( DeltaTime );\r | |
1093 | Bandwidth = pContext->LengthInBytes;\r | |
1094 | DEBUG (( DEBUG_WINDOW,\r | |
1095 | "File Length %Ld, Transfer Time: %d.%03d Sec\r\n",\r | |
1096 | Bandwidth,\r | |
1097 | DivU64x32 ( NanoSeconds, 1000 * 1000 * 1000 ),\r | |
1098 | ((UINT32)DivU64x32 ( NanoSeconds, 1000 * 1000 )) % 1000 ));\r | |
1099 | \r | |
1100 | //\r | |
1101 | // Display the round trip time\r | |
1102 | //\r | |
1103 | Bandwidth = MultU64x32 ( Bandwidth, 8 * 1000 * 1000 );\r | |
1104 | Bandwidth /= NanoSeconds;\r | |
1105 | if ( 1000 > Bandwidth ) {\r | |
1106 | Value = (UINT32)Bandwidth;\r | |
1107 | Print ( L"Bandwidth: %d Kbits/Sec\r\n",\r | |
1108 | Value );\r | |
1109 | }\r | |
1110 | else if (( 1000 * 1000 ) > Bandwidth ) {\r | |
1111 | Value = (UINT32)Bandwidth;\r | |
1112 | Print ( L"Bandwidth: %d.%03d Mbits/Sec\r\n",\r | |
1113 | Value / 1000,\r | |
1114 | Value % 1000 );\r | |
1115 | }\r | |
1116 | else {\r | |
1117 | Value = (UINT32)DivU64x32 ( Bandwidth, 1000 );\r | |
1118 | Print ( L"Bandwidth: %d.%03d Gbits/Sec\r\n",\r | |
1119 | Value / 1000,\r | |
1120 | Value % 1000 );\r | |
1121 | }\r | |
1122 | }\r | |
1123 | }\r | |
1124 | break;\r | |
1125 | }\r | |
1126 | \r | |
1127 | //\r | |
1128 | // Return the operation status\r | |
1129 | //\r | |
1130 | DBG_EXIT ( );\r | |
1131 | return bCloseContext;\r | |
1132 | }\r | |
1133 | \r | |
1134 | \r | |
1135 | /**\r | |
1136 | Get the next TFTP option\r | |
1137 | \r | |
1138 | @param [in] pOption Address of a zero terminated option string\r | |
1139 | @param [in] pEnd End of buffer address\r | |
1140 | @param [in] ppNextOption Address to receive the address of the next\r | |
1141 | zero terminated option string\r | |
1142 | \r | |
1143 | @retval EFI_SUCCESS Message processed successfully\r | |
1144 | \r | |
1145 | **/\r | |
1146 | EFI_STATUS\r | |
1147 | TftpOptionGet (\r | |
1148 | IN UINT8 * pOption,\r | |
1149 | IN UINT8 * pEnd,\r | |
1150 | IN UINT8 ** ppNextOption\r | |
1151 | )\r | |
1152 | {\r | |
1153 | UINT8 * pNextOption;\r | |
1154 | EFI_STATUS Status;\r | |
1155 | \r | |
1156 | //\r | |
1157 | // Locate the end of the option\r | |
1158 | //\r | |
1159 | pNextOption = pOption;\r | |
1160 | while (( pEnd > pNextOption ) && ( 0 != *pNextOption )) {\r | |
1161 | pNextOption += 1;\r | |
1162 | }\r | |
1163 | if ( pEnd <= pNextOption ) {\r | |
1164 | //\r | |
1165 | // Error - end of buffer reached\r | |
1166 | //\r | |
1167 | DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r | |
1168 | "ERROR - Option without zero termination received!\r\n" ));\r | |
1169 | Status = EFI_INVALID_PARAMETER;\r | |
1170 | }\r | |
1171 | else {\r | |
1172 | //\r | |
1173 | // Zero terminated option found\r | |
1174 | //\r | |
1175 | pNextOption += 1;\r | |
1176 | \r | |
1177 | //\r | |
1178 | // Display the zero terminated ASCII option string\r | |
1179 | //\r | |
1180 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
1181 | "Option: %a\r\n",\r | |
1182 | pOption ));\r | |
1183 | Status = EFI_SUCCESS;\r | |
1184 | }\r | |
1185 | \r | |
1186 | //\r | |
1187 | // Return the next option address\r | |
1188 | //\r | |
1189 | *ppNextOption = pNextOption;\r | |
1190 | \r | |
1191 | //\r | |
1192 | // Return the operation status\r | |
1193 | //\r | |
1194 | return Status;\r | |
1195 | }\r | |
1196 | \r | |
1197 | \r | |
1198 | /**\r | |
1199 | Place an option value into the option acknowledgement\r | |
1200 | \r | |
1201 | @param [in] pOack Option acknowledgement address\r | |
1202 | @param [in] Value Value to translate into ASCII decimal\r | |
1203 | \r | |
1204 | @return Option acknowledgement address\r | |
1205 | \r | |
1206 | **/\r | |
1207 | UINT8 *\r | |
1208 | TftpOptionSet (\r | |
1209 | IN UINT8 * pOack,\r | |
1210 | IN UINT64 Value\r | |
1211 | )\r | |
1212 | {\r | |
1213 | UINT64 NextValue;\r | |
1214 | \r | |
1215 | //\r | |
1216 | // Determine the next value\r | |
1217 | //\r | |
1218 | NextValue = Value / 10;\r | |
1219 | \r | |
1220 | //\r | |
1221 | // Supress leading zeros\r | |
7dc13291 | 1222 | //\r |
1223 | if ( 0 != NextValue ) {\r | |
1224 | pOack = TftpOptionSet ( pOack, NextValue );\r | |
1225 | }\r | |
1226 | \r | |
1227 | //\r | |
1228 | // Output this digit\r | |
1229 | //\r | |
1230 | *pOack++ = (UINT8)( Value - ( NextValue * 10 ) + '0' );\r | |
1231 | \r | |
1232 | //\r | |
1233 | // Return the next option acknowledgement location\r | |
1234 | //\r | |
1235 | return pOack;\r | |
1236 | }\r | |
1237 | \r | |
1238 | \r | |
1239 | /**\r | |
1240 | Process the TFTP request\r | |
1241 | \r | |
f6e5cdd5 | 1242 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r |
7dc13291 | 1243 | @param [in] pOption Address of the first zero terminated option string\r |
1244 | @param [in] pEnd End of buffer address\r | |
1245 | \r | |
1246 | **/\r | |
1247 | VOID\r | |
1248 | TftpOptions (\r | |
1249 | IN TSDT_CONNECTION_CONTEXT * pContext,\r | |
1250 | IN UINT8 * pOption,\r | |
1251 | IN UINT8 * pEnd\r | |
1252 | )\r | |
1253 | {\r | |
1254 | UINT8 * pNextOption;\r | |
1255 | UINT8 * pOack;\r | |
f6e5cdd5 | 1256 | TFTP_PACKET * pPacket;\r |
7dc13291 | 1257 | UINT8 * pTemp;\r |
1258 | UINT8 * pValue;\r | |
1259 | EFI_STATUS Status;\r | |
1260 | INT32 Value;\r | |
1261 | \r | |
f6e5cdd5 | 1262 | //\r |
1263 | // Get a packet\r | |
1264 | //\r | |
1265 | pPacket = PacketGet ( pContext );\r | |
1266 | \r | |
7dc13291 | 1267 | //\r |
1268 | // Start the OACK packet\r | |
1269 | // Let the OACK handle the parsing errors\r | |
1270 | // See http://tools.ietf.org/html/rfc2347\r | |
1271 | //\r | |
f6e5cdd5 | 1272 | pOack = &pPacket->TxBuffer[ 0 ];\r |
7dc13291 | 1273 | *pOack++ = 0;\r |
1274 | *pOack++ = TFTP_OP_OACK;\r | |
f6e5cdd5 | 1275 | pPacket->TxBytes = 2;\r |
1276 | pPacket->BlockNumber = 0;\r | |
7dc13291 | 1277 | \r |
1278 | //\r | |
1279 | // Walk the list of options\r | |
1280 | //\r | |
1281 | do {\r | |
1282 | //\r | |
1283 | // Get the next option, skip junk at end of message\r | |
1284 | //\r | |
1285 | Status = TftpOptionGet ( pOption, pEnd, &pNextOption );\r | |
1286 | if ( !EFI_ERROR ( Status )) {\r | |
1287 | //\r | |
1288 | // Process the option\r | |
1289 | //\r | |
1290 | \r | |
1291 | //\r | |
1292 | // blksize - See http://tools.ietf.org/html/rfc2348\r | |
1293 | //\r | |
1294 | pValue = pNextOption;\r | |
f6e5cdd5 | 1295 | if ( 0 == strcasecmp ((char *)pOption, "blksize" )) {\r |
7dc13291 | 1296 | //\r |
1297 | // Get the value\r | |
1298 | //\r | |
1299 | Status = TftpOptionGet ( pValue, pEnd, &pNextOption );\r | |
1300 | if ( !EFI_ERROR ( Status )) {\r | |
1301 | //\r | |
1302 | // Validate the block size, skip non-numeric block sizes\r | |
1303 | //\r | |
1304 | Status = TftpOptionValue ( pValue, &Value );\r | |
1305 | if ( !EFI_ERROR ( Status )) {\r | |
1306 | //\r | |
1307 | // Propose a smaller block size if necessary\r | |
1308 | //\r | |
1309 | if ( Value > TFTP_MAX_BLOCK_SIZE ) {\r | |
1310 | Value = TFTP_MAX_BLOCK_SIZE;\r | |
1311 | }\r | |
1312 | \r | |
1313 | //\r | |
1314 | // Set the new block size\r | |
1315 | //\r | |
1316 | pContext->BlockSize = Value;\r | |
1317 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
1318 | "Using block size of %d bytes\r\n",\r | |
1319 | pContext->BlockSize ));\r | |
1320 | \r | |
1321 | //\r | |
1322 | // Update the OACK\r | |
1323 | //\r | |
1324 | pTemp = pOack;\r | |
1325 | *pOack++ = 'b';\r | |
1326 | *pOack++ = 'l';\r | |
1327 | *pOack++ = 'k';\r | |
1328 | *pOack++ = 's';\r | |
1329 | *pOack++ = 'i';\r | |
1330 | *pOack++ = 'z';\r | |
1331 | *pOack++ = 'e';\r | |
1332 | *pOack++ = 0;\r | |
1333 | pOack = TftpOptionSet ( pOack, pContext->BlockSize );\r | |
1334 | *pOack++ = 0;\r | |
f6e5cdd5 | 1335 | pPacket->TxBytes += pOack - pTemp;\r |
7dc13291 | 1336 | }\r |
1337 | }\r | |
1338 | }\r | |
1339 | \r | |
1340 | //\r | |
1341 | // timeout - See http://tools.ietf.org/html/rfc2349\r | |
1342 | //\r | |
f6e5cdd5 | 1343 | else if ( 0 == strcasecmp ((char *)pOption, "timeout" )) {\r |
7dc13291 | 1344 | //\r |
1345 | // Get the value\r | |
1346 | //\r | |
1347 | Status = TftpOptionGet ( pValue, pEnd, &pNextOption );\r | |
1348 | if ( !EFI_ERROR ( Status )) {\r | |
1349 | Status = TftpOptionValue ( pValue, &Value );\r | |
1350 | if ( !EFI_ERROR ( Status )) {\r | |
1351 | //\r | |
1352 | // Set the timeout value\r | |
1353 | //\r | |
f6e5cdd5 | 1354 | pContext->MaxTimeout = Value;\r |
7dc13291 | 1355 | DEBUG (( DEBUG_TFTP_REQUEST,\r |
1356 | "Using timeout of %d seconds\r\n",\r | |
f6e5cdd5 | 1357 | pContext->MaxTimeout ));\r |
7dc13291 | 1358 | \r |
1359 | //\r | |
1360 | // Update the OACK\r | |
1361 | //\r | |
1362 | pTemp = pOack;\r | |
1363 | *pOack++ = 't';\r | |
1364 | *pOack++ = 'i';\r | |
1365 | *pOack++ = 'm';\r | |
1366 | *pOack++ = 'e';\r | |
1367 | *pOack++ = 'o';\r | |
1368 | *pOack++ = 'u';\r | |
1369 | *pOack++ = 't';\r | |
1370 | *pOack++ = 0;\r | |
f6e5cdd5 | 1371 | pOack = TftpOptionSet ( pOack, pContext->MaxTimeout );\r |
7dc13291 | 1372 | *pOack++ = 0;\r |
f6e5cdd5 | 1373 | pPacket->TxBytes += pOack - pTemp;\r |
7dc13291 | 1374 | }\r |
1375 | }\r | |
1376 | }\r | |
1377 | \r | |
1378 | //\r | |
1379 | // tsize - See http://tools.ietf.org/html/rfc2349\r | |
1380 | //\r | |
f6e5cdd5 | 1381 | else if ( 0 == strcasecmp ((char *)pOption, "tsize" )) {\r |
7dc13291 | 1382 | //\r |
1383 | // Get the value\r | |
1384 | //\r | |
1385 | Status = TftpOptionGet ( pValue, pEnd, &pNextOption );\r | |
1386 | if ( !EFI_ERROR ( Status )) {\r | |
1387 | Status = TftpOptionValue ( pValue, &Value );\r | |
1388 | if ( !EFI_ERROR ( Status )) {\r | |
1389 | //\r | |
1390 | // Return the file size\r | |
1391 | //\r | |
1392 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
1393 | "Returning file size of %Ld bytes\r\n",\r | |
1394 | pContext->LengthInBytes ));\r | |
1395 | \r | |
1396 | //\r | |
1397 | // Update the OACK\r | |
1398 | //\r | |
1399 | pTemp = pOack;\r | |
1400 | *pOack++ = 't';\r | |
1401 | *pOack++ = 's';\r | |
1402 | *pOack++ = 'i';\r | |
1403 | *pOack++ = 'z';\r | |
1404 | *pOack++ = 'e';\r | |
1405 | *pOack++ = 0;\r | |
1406 | pOack = TftpOptionSet ( pOack, pContext->LengthInBytes );\r | |
1407 | *pOack++ = 0;\r | |
f6e5cdd5 | 1408 | pPacket->TxBytes += pOack - pTemp;\r |
7dc13291 | 1409 | }\r |
1410 | }\r | |
1411 | }\r | |
1412 | else {\r | |
1413 | //\r | |
1414 | // Unknown option - Ignore it\r | |
1415 | //\r | |
1416 | DEBUG (( DEBUG_WARN | DEBUG_TFTP_REQUEST,\r | |
1417 | "WARNING - Skipping unknown option: %a\r\n",\r | |
1418 | pOption ));\r | |
1419 | }\r | |
1420 | }\r | |
1421 | \r | |
1422 | //\r | |
1423 | // Set the next option\r | |
1424 | //\r | |
1425 | pOption = pNextOption;\r | |
1426 | } while ( pEnd > pOption );\r | |
f6e5cdd5 | 1427 | \r |
1428 | //\r | |
1429 | // Transmit the OACK if necessary\r | |
1430 | //\r | |
1431 | if ( 2 < pPacket->TxBytes ) {\r | |
1432 | PacketQueue ( pContext, pPacket );\r | |
1433 | }\r | |
1434 | else {\r | |
1435 | PacketFree ( pContext, pPacket );\r | |
1436 | }\r | |
7dc13291 | 1437 | }\r |
1438 | \r | |
1439 | \r | |
1440 | /**\r | |
1441 | Process the TFTP request\r | |
1442 | \r | |
1443 | @param [in] pOption Address of the first zero terminated option string\r | |
1444 | @param [in] pValue Address to receive the value\r | |
1445 | \r | |
1446 | @retval EFI_SUCCESS Option translated into a value\r | |
1447 | \r | |
1448 | **/\r | |
1449 | EFI_STATUS\r | |
1450 | TftpOptionValue (\r | |
1451 | IN UINT8 * pOption,\r | |
1452 | IN INT32 * pValue\r | |
1453 | )\r | |
1454 | {\r | |
1455 | UINT8 Digit;\r | |
1456 | EFI_STATUS Status;\r | |
1457 | INT32 Value;\r | |
1458 | \r | |
1459 | //\r | |
1460 | // Assume success\r | |
1461 | //\r | |
1462 | Status = EFI_SUCCESS;\r | |
1463 | \r | |
1464 | //\r | |
1465 | // Walk the characters in the option\r | |
1466 | //\r | |
1467 | Value = 0;\r | |
1468 | while ( 0 != *pOption ) {\r | |
1469 | //\r | |
1470 | // Convert the next digit to binary\r | |
1471 | //\r | |
1472 | Digit = *pOption++;\r | |
1473 | if (( '0' <= Digit ) && ( '9' >= Digit )) {\r | |
1474 | Value *= 10;\r | |
1475 | Value += Digit - '0';\r | |
1476 | }\r | |
1477 | else {\r | |
1478 | DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r | |
1479 | "ERROR - Invalid character '0x%02x' in the value\r\n",\r | |
1480 | Digit ));\r | |
1481 | Status = EFI_INVALID_PARAMETER;\r | |
1482 | break;\r | |
1483 | }\r | |
1484 | }\r | |
1485 | \r | |
1486 | //\r | |
1487 | // Return the value\r | |
1488 | //\r | |
1489 | *pValue = Value;\r | |
1490 | \r | |
1491 | //\r | |
1492 | // Return the conversion status\r | |
1493 | //\r | |
1494 | return Status;\r | |
1495 | }\r | |
1496 | \r | |
1497 | \r | |
1498 | /**\r | |
1499 | Process the TFTP request\r | |
1500 | \r | |
f6e5cdd5 | 1501 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r |
1502 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r | |
1503 | @param [in] SocketFd Socket file descriptor\r | |
7dc13291 | 1504 | \r |
1505 | **/\r | |
1506 | VOID\r | |
1507 | TftpProcessRequest (\r | |
1508 | IN TSDT_TFTP_SERVER * pTftpServer,\r | |
f6e5cdd5 | 1509 | IN TSDT_CONNECTION_CONTEXT * pContext,\r |
1510 | IN int SocketFd\r | |
7dc13291 | 1511 | )\r |
1512 | {\r | |
1513 | BOOLEAN bCloseContext;\r | |
7dc13291 | 1514 | UINT16 Opcode;\r |
7dc13291 | 1515 | \r |
1516 | DBG_ENTER ( );\r | |
1517 | \r | |
1518 | //\r | |
1519 | // Get the opcode\r | |
1520 | //\r | |
f6e5cdd5 | 1521 | Opcode = HTONS ( *(UINT16 *)&pTftpServer->RxBuffer[ 0 ]);\r |
1522 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
1523 | "TFTP Opcode: 0x%08x\r\n",\r | |
1524 | Opcode ));\r | |
7dc13291 | 1525 | \r |
1526 | //\r | |
1527 | // Validate the parameters\r | |
1528 | //\r | |
1529 | bCloseContext = FALSE;\r | |
7dc13291 | 1530 | switch ( Opcode ) {\r |
1531 | default:\r | |
1532 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
1533 | "ERROR - Unknown TFTP opcode: %d\r\n",\r | |
1534 | Opcode ));\r | |
f6e5cdd5 | 1535 | break;\r |
1536 | \r | |
1537 | case TFTP_OP_ACK:\r | |
1538 | bCloseContext = TftpAck ( pTftpServer, pContext );\r | |
7dc13291 | 1539 | break;\r |
1540 | \r | |
1541 | case TFTP_OP_READ_REQUEST:\r | |
f6e5cdd5 | 1542 | bCloseContext = TftpRead ( pTftpServer, pContext, SocketFd );\r |
7dc13291 | 1543 | break;\r |
1544 | \r | |
f6e5cdd5 | 1545 | \r |
1546 | \r | |
1547 | \r | |
7dc13291 | 1548 | case TFTP_OP_DATA:\r |
1549 | if ( NULL == pContext ) {\r | |
f6e5cdd5 | 1550 | if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r |
1551 | DEBUG (( DEBUG_ERROR,\r | |
1552 | "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r | |
1553 | (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r | |
1554 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r | |
1555 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r | |
1556 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r | |
1557 | htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r | |
1558 | }\r | |
1559 | else {\r | |
1560 | DEBUG (( DEBUG_ERROR,\r | |
1561 | "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r | |
1562 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r | |
1563 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r | |
1564 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r | |
1565 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r | |
1566 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r | |
1567 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r | |
1568 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r | |
1569 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r | |
1570 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r | |
1571 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r | |
1572 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r | |
1573 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r | |
1574 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r | |
1575 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r | |
1576 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r | |
1577 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r | |
1578 | htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r | |
1579 | }\r | |
7dc13291 | 1580 | break;\r |
1581 | }\r | |
f6e5cdd5 | 1582 | if ( 0 != pContext->PacketsInWindow ) {\r |
7dc13291 | 1583 | DEBUG (( DEBUG_ERROR,\r |
1584 | "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n",\r | |
1585 | pContext ));\r | |
7dc13291 | 1586 | break;\r |
1587 | }\r | |
59bc0593 | 1588 | if ( pTftpServer->RxBytes > (ssize_t)( pContext->BlockSize + 2 + 2 )) {\r |
7dc13291 | 1589 | DEBUG (( DEBUG_ERROR,\r |
1590 | "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n",\r | |
1591 | pTftpServer->RxBytes - 2 - 2,\r | |
1592 | pContext->BlockSize,\r | |
1593 | pContext ));\r | |
7dc13291 | 1594 | break;\r |
1595 | }\r | |
1596 | break;\r | |
1597 | \r | |
1598 | case TFTP_OP_ERROR:\r | |
1599 | if ( NULL == pContext ) {\r | |
f6e5cdd5 | 1600 | if ( AF_INET == pTftpServer->RemoteAddress.v4.sin_family ) {\r |
1601 | DEBUG (( DEBUG_ERROR,\r | |
1602 | "ERROR - File not open for %d.%d.%d.%d:%d\r\n",\r | |
1603 | (UINT8)pTftpServer->RemoteAddress.v4.sin_addr.s_addr,\r | |
1604 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 8 ),\r | |
1605 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 16 ),\r | |
1606 | (UINT8)( pTftpServer->RemoteAddress.v4.sin_addr.s_addr >> 24 ),\r | |
1607 | htons ( pTftpServer->RemoteAddress.v4.sin_port )));\r | |
7dc13291 | 1608 | }\r |
1609 | else {\r | |
f6e5cdd5 | 1610 | DEBUG (( DEBUG_ERROR,\r |
1611 | "ERROR - File not open for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",\r | |
1612 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 0 ],\r | |
1613 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 1 ],\r | |
1614 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 2 ],\r | |
1615 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 3 ],\r | |
1616 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 4 ],\r | |
1617 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 5 ],\r | |
1618 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 6 ],\r | |
1619 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 7 ],\r | |
1620 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 8 ],\r | |
1621 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 9 ],\r | |
1622 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 10 ],\r | |
1623 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 11 ],\r | |
1624 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 12 ],\r | |
1625 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 13 ],\r | |
1626 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 14 ],\r | |
1627 | pTftpServer->RemoteAddress.v6.sin6_addr.__u6_addr.__u6_addr8[ 15 ],\r | |
1628 | htons ( pTftpServer->RemoteAddress.v6.sin6_port )));\r | |
7dc13291 | 1629 | }\r |
7dc13291 | 1630 | }\r |
f6e5cdd5 | 1631 | break;\r |
7dc13291 | 1632 | }\r |
1633 | \r | |
1634 | //\r | |
1635 | // Determine if the context should be closed\r | |
1636 | //\r | |
1637 | if ( bCloseContext ) {\r | |
1638 | ContextRemove ( pTftpServer, pContext );\r | |
1639 | }\r | |
1640 | \r | |
1641 | DBG_EXIT ( );\r | |
1642 | }\r | |
1643 | \r | |
1644 | \r | |
1645 | /**\r | |
f6e5cdd5 | 1646 | Process the read request\r |
7dc13291 | 1647 | \r |
f6e5cdd5 | 1648 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r |
1649 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r | |
1650 | @param [in] SocketFd Socket file descriptor\r | |
7dc13291 | 1651 | \r |
f6e5cdd5 | 1652 | @retval TRUE if the context should be closed\r |
7dc13291 | 1653 | \r |
1654 | **/\r | |
f6e5cdd5 | 1655 | BOOLEAN\r |
1656 | TftpRead (\r | |
7dc13291 | 1657 | IN TSDT_TFTP_SERVER * pTftpServer,\r |
1658 | IN TSDT_CONNECTION_CONTEXT * pContext,\r | |
f6e5cdd5 | 1659 | IN int SocketFd\r |
7dc13291 | 1660 | )\r |
1661 | {\r | |
f6e5cdd5 | 1662 | BOOLEAN bCloseContext;\r |
1663 | struct stat FileStatus;\r | |
7dc13291 | 1664 | UINT8 * pBuffer;\r |
f6e5cdd5 | 1665 | UINT8 * pEnd;\r |
1666 | UINT8 * pFileName;\r | |
1667 | UINT8 * pMode;\r | |
1668 | UINT8 * pOption;\r | |
1669 | CHAR8 * pReadMode;\r | |
1670 | UINT64 TimeStart;\r | |
7dc13291 | 1671 | \r |
1672 | DBG_ENTER ( );\r | |
1673 | \r | |
1674 | //\r | |
f6e5cdd5 | 1675 | // Log the receive time\r |
7dc13291 | 1676 | //\r |
f6e5cdd5 | 1677 | TimeStart = 0;\r |
1678 | if ( PcdGetBool ( Tftp_Bandwidth )) {\r | |
1679 | TimeStart = GetPerformanceCounter ( );\r | |
1680 | }\r | |
7dc13291 | 1681 | \r |
1682 | //\r | |
f6e5cdd5 | 1683 | // Close the context if necessary\r |
7dc13291 | 1684 | //\r |
f6e5cdd5 | 1685 | bCloseContext = FALSE;\r |
1686 | if ( NULL != pContext ) {\r | |
1687 | ContextRemove ( pTftpServer, pContext );\r | |
1688 | }\r | |
7dc13291 | 1689 | \r |
1690 | //\r | |
f6e5cdd5 | 1691 | // Use break instead of goto\r |
7dc13291 | 1692 | //\r |
f6e5cdd5 | 1693 | for ( ; ; ) {\r |
1694 | //\r | |
1695 | // Create the connection context\r | |
1696 | //\r | |
1697 | pContext = ContextAdd ( pTftpServer, SocketFd );\r | |
1698 | if ( NULL == pContext ) {\r | |
1699 | break;\r | |
1700 | }\r | |
7dc13291 | 1701 | \r |
f6e5cdd5 | 1702 | //\r |
1703 | // Set the start time\r | |
1704 | //\r | |
1705 | if ( PcdGetBool ( Tftp_Bandwidth )) {\r | |
1706 | pContext->TimeStart = TimeStart;\r | |
1707 | }\r | |
7dc13291 | 1708 | \r |
f6e5cdd5 | 1709 | //\r |
1710 | // Locate the mode\r | |
1711 | //\r | |
1712 | pBuffer = &pTftpServer->RxBuffer[ 0 ];\r | |
1713 | pEnd = &pBuffer[ pTftpServer->RxBytes ];\r | |
1714 | pFileName = &pBuffer[ 2 ];\r | |
1715 | pMode = pFileName;\r | |
1716 | while (( pEnd > pMode ) && ( 0 != *pMode )) {\r | |
1717 | pMode += 1;\r | |
1718 | }\r | |
1719 | if ( pEnd <= pMode ) {\r | |
1720 | //\r | |
1721 | // Mode not found\r | |
1722 | //\r | |
1723 | DEBUG (( DEBUG_ERROR | DEBUG_RX,\r | |
1724 | "ERROR - File mode not found\r\n" ));\r | |
1725 | //\r | |
1726 | // Tell the client of the error\r | |
1727 | //\r | |
1728 | SendError ( pContext,\r | |
1729 | TFTP_ERROR_SEE_MSG,\r | |
1730 | (UINT8 *)"File open mode not found" );\r | |
1731 | break;\r | |
1732 | }\r | |
1733 | pMode += 1;\r | |
1734 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
1735 | "TFTP - FileName: %a\r\n",\r | |
1736 | pFileName ));\r | |
7dc13291 | 1737 | \r |
f6e5cdd5 | 1738 | //\r |
1739 | // Locate the options\r | |
1740 | //\r | |
1741 | pOption = pMode;\r | |
1742 | while (( pEnd > pOption ) && ( 0 != *pOption )) {\r | |
1743 | pOption += 1;\r | |
1744 | }\r | |
1745 | if ( pEnd <= pOption ) {\r | |
1746 | //\r | |
1747 | // End of mode not found\r | |
1748 | //\r | |
1749 | DEBUG (( DEBUG_ERROR | DEBUG_RX,\r | |
1750 | "ERROR - File mode not valid\r\n" ));\r | |
1751 | //\r | |
1752 | // Tell the client of the error\r | |
1753 | //\r | |
1754 | SendError ( pContext,\r | |
1755 | TFTP_ERROR_SEE_MSG,\r | |
1756 | (UINT8 *)"File open mode not valid" );\r | |
1757 | break;\r | |
1758 | }\r | |
1759 | pOption += 1;\r | |
1760 | DEBUG (( DEBUG_TFTP_REQUEST,\r | |
1761 | "TFTP - Mode: %a\r\n",\r | |
1762 | pMode ));\r | |
7dc13291 | 1763 | \r |
f6e5cdd5 | 1764 | //\r |
1765 | // Verify the mode is supported\r | |
1766 | //\r | |
1767 | pReadMode = "r";\r | |
1768 | if ( 0 == strcasecmp ((char *)pMode, "octet" )) {\r | |
1769 | //\r | |
1770 | // Read the file as binary input\r | |
1771 | //\r | |
1772 | pReadMode = "rb";\r | |
1773 | }\r | |
7dc13291 | 1774 | \r |
f6e5cdd5 | 1775 | //\r |
1776 | // Determine the file length\r | |
1777 | //\r | |
d3a595ce | 1778 | pContext->File = fopen ((const char *)pFileName, pReadMode );\r |
f6e5cdd5 | 1779 | if (( NULL == pContext->File )\r |
d3a595ce | 1780 | || ( -1 == stat ((const char *)pFileName, &FileStatus ))) {\r |
f6e5cdd5 | 1781 | //\r |
1782 | // File not found\r | |
1783 | //\r | |
1784 | DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST,\r | |
1785 | ( NULL == pContext->File )\r | |
1786 | ? "ERROR - File not found!\r\n"\r | |
1787 | : "ERROR - Unable to determine file %a size!\r\n",\r | |
1788 | pFileName ));\r | |
7dc13291 | 1789 | \r |
f6e5cdd5 | 1790 | //\r |
1791 | // Tell the client of the error\r | |
1792 | //\r | |
1793 | SendError ( pContext,\r | |
1794 | TFTP_ERROR_NOT_FOUND,\r | |
1795 | (UINT8 *)"File not found" );\r | |
1796 | break;\r | |
1797 | }\r | |
1798 | pContext->LengthInBytes = FileStatus.st_size;\r | |
1799 | pContext->BytesRemaining = pContext->LengthInBytes;\r | |
1800 | pContext->BytesToSend = pContext->LengthInBytes;\r | |
7dc13291 | 1801 | \r |
f6e5cdd5 | 1802 | //\r |
1803 | // Display the file size\r | |
1804 | //\r | |
1805 | DEBUG_CODE_BEGIN ( );\r | |
1806 | UINT32 Value;\r | |
1807 | \r | |
1808 | if ( 1024 > pContext->LengthInBytes ) {\r | |
1809 | Value = (UINT32)pContext->LengthInBytes;\r | |
1810 | DEBUG (( DEBUG_FILE_BUFFER,\r | |
1811 | "%a size: %d Bytes\r\n",\r | |
1812 | pFileName,\r | |
1813 | Value ));\r | |
1814 | }\r | |
1815 | else if (( 1024 * 1024 ) > pContext->LengthInBytes ) {\r | |
1816 | Value = (UINT32)pContext->LengthInBytes;\r | |
1817 | DEBUG (( DEBUG_FILE_BUFFER,\r | |
1818 | "%a size: %d.%03d KiBytes (%Ld Bytes)\r\n",\r | |
1819 | pFileName,\r | |
1820 | Value / 1024,\r | |
1821 | (( Value % 1024 ) * 1000 ) / 1024,\r | |
1822 | pContext->LengthInBytes ));\r | |
1823 | }\r | |
1824 | else if (( 1024 * 1024 * 1024 ) > pContext->LengthInBytes ) {\r | |
1825 | Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 );\r | |
1826 | DEBUG (( DEBUG_FILE_BUFFER,\r | |
1827 | "%a size: %d.%03d MiBytes (%Ld Bytes)\r\n",\r | |
1828 | pFileName,\r | |
1829 | Value / 1024,\r | |
1830 | (( Value % 1024 ) * 1000 ) / 1024,\r | |
1831 | pContext->LengthInBytes ));\r | |
1832 | }\r | |
1833 | else {\r | |
1834 | Value = (UINT32)DivU64x32 ( pContext->LengthInBytes, 1024 * 1024 );\r | |
1835 | DEBUG (( DEBUG_FILE_BUFFER,\r | |
1836 | "%a size: %d.%03d GiBytes (%Ld Bytes)\r\n",\r | |
1837 | pFileName,\r | |
1838 | Value / 1024,\r | |
1839 | (( Value % 1024 ) * 1000 ) / 1024,\r | |
1840 | pContext->LengthInBytes ));\r | |
1841 | }\r | |
1842 | DEBUG_CODE_END ( );\r | |
7dc13291 | 1843 | \r |
f6e5cdd5 | 1844 | //\r |
1845 | // Process the options\r | |
1846 | //\r | |
1847 | if ( pEnd > pOption ) {\r | |
1848 | TftpOptions ( pContext, pOption, pEnd );\r | |
1849 | }\r | |
1850 | else {\r | |
1851 | //\r | |
1852 | // Skip the open ACK\r | |
1853 | //\r | |
1854 | pContext->BlockNumber = 1;\r | |
1855 | }\r | |
7dc13291 | 1856 | \r |
f6e5cdd5 | 1857 | //\r |
1858 | // Send the first packet (OACK or data block)\r | |
1859 | //\r | |
1860 | bCloseContext = PacketFill ( pContext );\r | |
1861 | break;\r | |
7dc13291 | 1862 | }\r |
1863 | \r | |
1864 | //\r | |
f6e5cdd5 | 1865 | // Return the close status\r |
7dc13291 | 1866 | //\r |
f6e5cdd5 | 1867 | DBG_EXIT ( );\r |
1868 | return bCloseContext;\r | |
7dc13291 | 1869 | }\r |
1870 | \r | |
1871 | \r | |
1872 | /**\r | |
1873 | Create the port for the TFTP server\r | |
1874 | \r | |
1875 | This routine polls the network layer to create the TFTP port for the\r | |
1876 | TFTP server. More than one attempt may be necessary since it may take\r | |
1877 | some time to get the IP address and initialize the upper layers of\r | |
1878 | the network stack.\r | |
1879 | \r | |
f6e5cdd5 | 1880 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r |
1881 | @param [in] AddressFamily The address family to use for the conection.\r | |
1882 | @param [in] pIndex Address of the index into the port array\r | |
7dc13291 | 1883 | \r |
1884 | **/\r | |
1885 | VOID\r | |
f6e5cdd5 | 1886 | TftpServerSocket (\r |
1887 | IN TSDT_TFTP_SERVER * pTftpServer,\r | |
1888 | IN sa_family_t AddressFamily,\r | |
1889 | IN int * pIndex\r | |
7dc13291 | 1890 | )\r |
1891 | {\r | |
7dc13291 | 1892 | int SocketStatus;\r |
f6e5cdd5 | 1893 | struct pollfd * pTftpPort;\r |
1894 | UINT16 TftpPort;\r | |
1895 | union {\r | |
1896 | struct sockaddr_in v4;\r | |
1897 | struct sockaddr_in6 v6;\r | |
1898 | } TftpServerAddress;\r | |
7dc13291 | 1899 | \r |
f6e5cdd5 | 1900 | DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerListen\r\n" ));\r |
7dc13291 | 1901 | \r |
1902 | //\r | |
f6e5cdd5 | 1903 | // Determine if the socket is already initialized\r |
7dc13291 | 1904 | //\r |
f6e5cdd5 | 1905 | if ( -1 == *pIndex ) {\r |
7dc13291 | 1906 | //\r |
1907 | // Attempt to create the socket for the TFTP server\r | |
1908 | //\r | |
f6e5cdd5 | 1909 | pTftpPort = &pTftpServer->TftpPort[ pTftpServer->Entries ];\r |
1910 | pTftpPort->fd = socket ( AddressFamily,\r | |
1911 | SOCK_DGRAM,\r | |
1912 | IPPROTO_UDP );\r | |
1913 | if ( -1 != pTftpPort->fd ) {\r | |
1914 | //\r | |
1915 | // Initialize the poll structure\r | |
1916 | //\r | |
1917 | pTftpPort->events = POLLRDNORM | POLLHUP;\r | |
1918 | pTftpPort->revents = 0;\r | |
1919 | \r | |
7dc13291 | 1920 | //\r |
1921 | // Set the socket address\r | |
1922 | //\r | |
7dc13291 | 1923 | TftpPort = 69;\r |
f6e5cdd5 | 1924 | ZeroMem ( &TftpServerAddress, sizeof ( TftpServerAddress ));\r |
1925 | TftpServerAddress.v4.sin_port = htons ( TftpPort );\r | |
1926 | if ( AF_INET == AddressFamily ) {\r | |
1927 | TftpServerAddress.v4.sin_len = sizeof ( TftpServerAddress.v4 );\r | |
1928 | TftpServerAddress.v4.sin_family = AF_INET;\r | |
1929 | }\r | |
1930 | else {\r | |
1931 | TftpServerAddress.v6.sin6_len = sizeof ( TftpServerAddress.v6 );\r | |
1932 | TftpServerAddress.v6.sin6_family = AF_INET6;\r | |
1933 | }\r | |
7dc13291 | 1934 | \r |
1935 | //\r | |
1936 | // Bind the socket to the TFTP port\r | |
1937 | //\r | |
f6e5cdd5 | 1938 | SocketStatus = bind ( pTftpPort->fd,\r |
1939 | (struct sockaddr *) &TftpServerAddress,\r | |
1940 | TftpServerAddress.v6.sin6_len );\r | |
7dc13291 | 1941 | if ( -1 != SocketStatus ) {\r |
1942 | DEBUG (( DEBUG_TFTP_PORT,\r | |
1943 | "0x%08x: Socket bound to port %d\r\n",\r | |
f6e5cdd5 | 1944 | pTftpPort->fd,\r |
7dc13291 | 1945 | TftpPort ));\r |
f6e5cdd5 | 1946 | \r |
1947 | //\r | |
1948 | // Account for this connection\r | |
1949 | //\r | |
1950 | *pIndex = pTftpServer->Entries;\r | |
1951 | pTftpServer->Entries += 1;\r | |
1952 | ASSERT ( DIM ( pTftpServer->TftpPort ) >= pTftpServer->Entries );\r | |
7dc13291 | 1953 | }\r |
1954 | \r | |
1955 | //\r | |
1956 | // Release the socket if necessary\r | |
1957 | //\r | |
1958 | if ( -1 == SocketStatus ) {\r | |
f6e5cdd5 | 1959 | close ( pTftpPort->fd );\r |
1960 | pTftpPort->fd = -1;\r | |
7dc13291 | 1961 | }\r |
1962 | }\r | |
f6e5cdd5 | 1963 | }\r |
7dc13291 | 1964 | \r |
f6e5cdd5 | 1965 | DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerListen\r\n" ));\r |
7dc13291 | 1966 | }\r |
1967 | \r | |
1968 | \r | |
1969 | /**\r | |
f6e5cdd5 | 1970 | Update the window due to the ACK\r |
7dc13291 | 1971 | \r |
f6e5cdd5 | 1972 | @param [in] pTftpServer Address of the ::TSDT_TFTP_SERVER structure\r |
1973 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r | |
1974 | @param [in] pPacket Address of a ::TFTP_PACKET structure\r | |
7dc13291 | 1975 | \r |
1976 | **/\r | |
f6e5cdd5 | 1977 | VOID\r |
1978 | WindowAck (\r | |
1979 | IN TSDT_TFTP_SERVER * pTftpServer,\r | |
1980 | IN TSDT_CONNECTION_CONTEXT * pContext,\r | |
1981 | IN TFTP_PACKET * pPacket\r | |
7dc13291 | 1982 | )\r |
1983 | {\r | |
f6e5cdd5 | 1984 | if ( PcdGetBool ( Tftp_HighSpeed )) {\r |
1985 | UINT64 DeltaTime;\r | |
1986 | UINT64 NanoSeconds;\r | |
7dc13291 | 1987 | \r |
f6e5cdd5 | 1988 | DBG_ENTER ( );\r |
7dc13291 | 1989 | \r |
7dc13291 | 1990 | //\r |
f6e5cdd5 | 1991 | // Compute the round trip time\r |
7dc13291 | 1992 | //\r |
f6e5cdd5 | 1993 | if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r |
1994 | DeltaTime = pTftpServer->RxTime - pPacket->TxTime;\r | |
7dc13291 | 1995 | }\r |
1996 | else {\r | |
f6e5cdd5 | 1997 | DeltaTime = pPacket->TxTime - pTftpServer->RxTime;\r |
7dc13291 | 1998 | }\r |
7dc13291 | 1999 | \r |
f6e5cdd5 | 2000 | //\r |
2001 | // Adjust the round trip time\r | |
2002 | //\r | |
2003 | NanoSeconds = GetTimeInNanoSecond ( DeltaTime );\r | |
2004 | DeltaTime = RShiftU64 ( pContext->Rtt2x, ACK_SHIFT );\r | |
2005 | pContext->Rtt2x += NanoSeconds + NanoSeconds - DeltaTime;\r | |
2006 | if ( pContext->Rtt2x > pContext->MaxTimeout ) {\r | |
2007 | pContext->Rtt2x = pContext->MaxTimeout;\r | |
2008 | }\r | |
2009 | \r | |
2010 | //\r | |
2011 | // Account for the ACK\r | |
2012 | //\r | |
2013 | if ( pContext->WindowSize < MAX_PACKETS ) {\r | |
2014 | pContext->AckCount -= 1;\r | |
2015 | if ( 0 == pContext->AckCount ) {\r | |
2016 | //\r | |
2017 | // Increase the window\r | |
2018 | //\r | |
2019 | pContext->WindowSize += 1;\r | |
2020 | \r | |
2021 | //\r | |
2022 | // Set the ACK count\r | |
2023 | //\r | |
2024 | if ( pContext->WindowSize < pContext->Threshold ) {\r | |
2025 | pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );\r | |
2026 | }\r | |
2027 | else {\r | |
2028 | pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;\r | |
2029 | }\r | |
2030 | \r | |
2031 | //\r | |
2032 | // Display the round trip time\r | |
2033 | //\r | |
2034 | DEBUG_CODE_BEGIN ( );\r | |
2035 | UINT32 Value;\r | |
2036 | \r | |
2037 | DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );\r | |
2038 | if ( 1000 > DeltaTime ) {\r | |
2039 | DEBUG (( DEBUG_WINDOW,\r | |
2040 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",\r | |
2041 | pContext->WindowSize,\r | |
2042 | pContext->Threshold,\r | |
2043 | pContext->AckCount,\r | |
2044 | DeltaTime ));\r | |
2045 | }\r | |
2046 | else if (( 1000 * 1000 ) > DeltaTime ) {\r | |
2047 | Value = (UINT32)DeltaTime;\r | |
2048 | DEBUG (( DEBUG_WINDOW,\r | |
2049 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",\r | |
2050 | pContext->WindowSize,\r | |
2051 | pContext->Threshold,\r | |
2052 | pContext->AckCount,\r | |
2053 | Value / 1000,\r | |
2054 | Value % 1000 ));\r | |
2055 | }\r | |
2056 | else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {\r | |
2057 | Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );\r | |
2058 | DEBUG (( DEBUG_WINDOW,\r | |
2059 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",\r | |
2060 | pContext->WindowSize,\r | |
2061 | pContext->Threshold,\r | |
2062 | pContext->AckCount,\r | |
2063 | Value / 1000,\r | |
2064 | Value % 1000 ));\r | |
2065 | }\r | |
2066 | else {\r | |
2067 | Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );\r | |
2068 | DEBUG (( DEBUG_WINDOW,\r | |
2069 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",\r | |
2070 | pContext->WindowSize,\r | |
2071 | pContext->Threshold,\r | |
2072 | pContext->AckCount,\r | |
2073 | Value / 1000,\r | |
2074 | Value % 1000 ));\r | |
2075 | }\r | |
2076 | DEBUG_CODE_END ( );\r | |
2077 | }\r | |
2078 | }\r | |
2079 | \r | |
2080 | DBG_EXIT ( );\r | |
2081 | }\r | |
7dc13291 | 2082 | }\r |
2083 | \r | |
2084 | \r | |
2085 | /**\r | |
f6e5cdd5 | 2086 | A timeout has occurred, close the window\r |
7dc13291 | 2087 | \r |
f6e5cdd5 | 2088 | @param [in] pContext Address of a ::TSDT_CONNECTION_CONTEXT structure\r |
7dc13291 | 2089 | \r |
2090 | **/\r | |
f6e5cdd5 | 2091 | VOID\r |
2092 | WindowTimeout (\r | |
2093 | IN TSDT_CONNECTION_CONTEXT * pContext\r | |
7dc13291 | 2094 | )\r |
2095 | {\r | |
f6e5cdd5 | 2096 | if ( PcdGetBool ( Tftp_HighSpeed )) {\r |
2097 | TFTP_PACKET * pPacket;\r | |
7dc13291 | 2098 | \r |
f6e5cdd5 | 2099 | DBG_ENTER ( );\r |
7dc13291 | 2100 | \r |
7dc13291 | 2101 | //\r |
f6e5cdd5 | 2102 | // Set the threshold at half the previous window size\r |
7dc13291 | 2103 | //\r |
f6e5cdd5 | 2104 | pContext->Threshold = ( pContext->WindowSize + 1 ) >> 1;\r |
7dc13291 | 2105 | \r |
f6e5cdd5 | 2106 | //\r |
2107 | // Close the transmit window\r | |
2108 | //\r | |
2109 | pContext->WindowSize = 1;\r | |
2110 | pContext->PacketsInWindow = 0;\r | |
2111 | \r | |
2112 | //\r | |
2113 | // Double the round trip time\r | |
2114 | //\r | |
2115 | pContext->Rtt2x = LShiftU64 ( pContext->Rtt2x, 1 );\r | |
2116 | if ( pContext->Rtt2x > pContext->MaxTimeout ) {\r | |
2117 | pContext->Rtt2x = pContext->MaxTimeout;\r | |
2118 | }\r | |
2119 | \r | |
2120 | //\r | |
2121 | // Set the ACK count\r | |
2122 | //\r | |
2123 | if ( pContext->WindowSize < pContext->Threshold ) {\r | |
2124 | pContext->AckCount = pContext->WindowSize * PcdGet32 ( Tftp_AckMultiplier );\r | |
7dc13291 | 2125 | }\r |
2126 | else {\r | |
f6e5cdd5 | 2127 | pContext->AckCount = PcdGet32 ( Tftp_AckLogBase ) << pContext->WindowSize;\r |
7dc13291 | 2128 | }\r |
7dc13291 | 2129 | \r |
f6e5cdd5 | 2130 | //\r |
2131 | // Display the round trip time\r | |
2132 | //\r | |
2133 | DEBUG_CODE_BEGIN ( );\r | |
2134 | UINT64 DeltaTime;\r | |
2135 | UINT32 Value;\r | |
2136 | \r | |
2137 | DeltaTime = RShiftU64 ( pContext->Rtt2x, 1 );\r | |
2138 | if ( 1000 > DeltaTime ) {\r | |
2139 | DEBUG (( DEBUG_WINDOW,\r | |
2140 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %Ld nSec\r\n",\r | |
2141 | pContext->WindowSize,\r | |
2142 | pContext->Threshold,\r | |
2143 | pContext->AckCount,\r | |
2144 | DeltaTime ));\r | |
2145 | }\r | |
2146 | else if (( 1000 * 1000 ) > DeltaTime ) {\r | |
2147 | Value = (UINT32)DeltaTime;\r | |
2148 | DEBUG (( DEBUG_WINDOW,\r | |
2149 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d uSec\r\n",\r | |
2150 | pContext->WindowSize,\r | |
2151 | pContext->Threshold,\r | |
2152 | pContext->AckCount,\r | |
2153 | Value / 1000,\r | |
2154 | Value % 1000 ));\r | |
2155 | }\r | |
2156 | else if (( 1000 * 1000 * 1000 ) > DeltaTime ) {\r | |
2157 | Value = (UINT32)DivU64x32 ( DeltaTime, 1000 );\r | |
2158 | DEBUG (( DEBUG_WINDOW,\r | |
2159 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d mSec\r\n",\r | |
2160 | pContext->WindowSize,\r | |
2161 | pContext->Threshold,\r | |
2162 | pContext->AckCount,\r | |
2163 | Value / 1000,\r | |
2164 | Value % 1000 ));\r | |
2165 | }\r | |
2166 | else {\r | |
2167 | Value = (UINT32)DivU64x32 ( DeltaTime, 1000 * 1000 );\r | |
2168 | DEBUG (( DEBUG_WINDOW,\r | |
2169 | "WindowSize: %d, Threshold: %d, AckCount: %4d, RTT: %d.%03d Sec\r\n",\r | |
2170 | pContext->WindowSize,\r | |
2171 | pContext->Threshold,\r | |
2172 | pContext->AckCount,\r | |
2173 | Value / 1000,\r | |
2174 | Value % 1000 ));\r | |
2175 | }\r | |
2176 | DEBUG_CODE_END ( );\r | |
7dc13291 | 2177 | \r |
f6e5cdd5 | 2178 | //\r |
2179 | // Retransmit the first packet in the window\r | |
2180 | //\r | |
2181 | pPacket = pContext->pTxHead;\r | |
2182 | if ( NULL != pPacket ) {\r | |
2183 | PacketTx ( pContext, pPacket );\r | |
2184 | }\r | |
2185 | \r | |
2186 | DBG_EXIT ( );\r | |
7dc13291 | 2187 | }\r |
7dc13291 | 2188 | }\r |
2189 | \r | |
2190 | \r | |
2191 | /**\r | |
2192 | Entry point for the TFTP server application.\r | |
2193 | \r | |
2194 | @param [in] Argc The number of arguments\r | |
2195 | @param [in] Argv The argument value array\r | |
2196 | \r | |
2197 | @retval 0 The application exited normally.\r | |
2198 | @retval Other An error occurred.\r | |
2199 | **/\r | |
2200 | int\r | |
2201 | main (\r | |
2202 | IN int Argc,\r | |
2203 | IN char **Argv\r | |
2204 | )\r | |
2205 | {\r | |
f6e5cdd5 | 2206 | UINTN Index;\r |
7dc13291 | 2207 | TSDT_TFTP_SERVER * pTftpServer;\r |
2208 | EFI_STATUS Status;\r | |
f6e5cdd5 | 2209 | UINT64 TriggerTime;\r |
7dc13291 | 2210 | \r |
2211 | //\r | |
f6e5cdd5 | 2212 | // Get the performance counter characteristics\r |
7dc13291 | 2213 | //\r |
2214 | pTftpServer = &mTftpServer;\r | |
f6e5cdd5 | 2215 | if ( PcdGetBool ( Tftp_HighSpeed )\r |
2216 | || PcdGetBool ( Tftp_Bandwidth )) {\r | |
2217 | pTftpServer->ClockFrequency = GetPerformanceCounterProperties ( &pTftpServer->Time1,\r | |
2218 | &pTftpServer->Time2 );\r | |
2219 | }\r | |
2220 | \r | |
2221 | //\r | |
2222 | // Create a timer event to start TFTP port\r | |
2223 | //\r | |
7dc13291 | 2224 | Status = gBS->CreateEvent ( EVT_TIMER,\r |
2225 | TPL_TFTP_SERVER,\r | |
2226 | NULL,\r | |
2227 | NULL,\r | |
2228 | &pTftpServer->TimerEvent );\r | |
2229 | if ( !EFI_ERROR ( Status )) {\r | |
f6e5cdd5 | 2230 | //\r |
2231 | // Compute the poll interval\r | |
2232 | //\r | |
2233 | TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 );\r | |
2234 | Status = gBS->SetTimer ( pTftpServer->TimerEvent,\r | |
2235 | TimerPeriodic,\r | |
2236 | TriggerTime );\r | |
7dc13291 | 2237 | if ( !EFI_ERROR ( Status )) {\r |
f6e5cdd5 | 2238 | DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" ));\r |
2239 | \r | |
7dc13291 | 2240 | //\r |
2241 | // Run the TFTP server forever\r | |
2242 | //\r | |
f6e5cdd5 | 2243 | pTftpServer->Udpv4Index = -1;\r |
2244 | pTftpServer->Udpv6Index = -1;\r | |
2245 | do {\r | |
7dc13291 | 2246 | //\r |
2247 | // Poll the network layer to create the TFTP port\r | |
2248 | // for the tftp server. More than one attempt may\r | |
2249 | // be necessary since it may take some time to get\r | |
2250 | // the IP address and initialize the upper layers\r | |
2251 | // of the network stack.\r | |
2252 | //\r | |
f6e5cdd5 | 2253 | if ( DIM ( pTftpServer->TftpPort ) != pTftpServer->Entries ) {\r |
2254 | do {\r | |
2255 | //\r | |
2256 | // Wait a while before polling for a connection\r | |
2257 | //\r | |
2258 | if ( EFI_SUCCESS != gBS->CheckEvent ( pTftpServer->TimerEvent )) {\r | |
2259 | if ( 0 == pTftpServer->Entries ) {\r | |
2260 | break;\r | |
2261 | }\r | |
2262 | gBS->WaitForEvent ( 1, &pTftpServer->TimerEvent, &Index );\r | |
2263 | }\r | |
2264 | \r | |
2265 | //\r | |
2266 | // Poll for a network connection\r | |
2267 | //\r | |
2268 | TftpServerSocket ( pTftpServer,\r | |
2269 | AF_INET,\r | |
2270 | &pTftpServer->Udpv4Index );\r | |
2271 | TftpServerSocket ( pTftpServer,\r | |
2272 | AF_INET6,\r | |
2273 | &pTftpServer->Udpv6Index );\r | |
2274 | } while ( 0 == pTftpServer->Entries );\r | |
2275 | }\r | |
7dc13291 | 2276 | \r |
2277 | //\r | |
2278 | // Poll the socket for activity\r | |
2279 | //\r | |
2280 | do {\r | |
2281 | SocketPoll ( pTftpServer );\r | |
7dc13291 | 2282 | \r |
f6e5cdd5 | 2283 | //\r |
2284 | // Normal TFTP lets the client request the retransmit by\r | |
2285 | // sending another ACK for the previous packet\r | |
2286 | //\r | |
2287 | if ( PcdGetBool ( Tftp_HighSpeed )) {\r | |
2288 | UINT64 CurrentTime;\r | |
2289 | UINT64 ElapsedTime;\r | |
2290 | TSDT_CONNECTION_CONTEXT * pContext;\r | |
2291 | TFTP_PACKET * pPacket;\r | |
2292 | \r | |
2293 | //\r | |
2294 | // High speed TFTP uses an agressive retransmit to\r | |
2295 | // get the TFTP client moving again when the ACK or\r | |
2296 | // previous data packet was lost.\r | |
2297 | //\r | |
2298 | // Get the current time\r | |
2299 | //\r | |
2300 | CurrentTime = GetPerformanceCounter ( );\r | |
2301 | \r | |
2302 | //\r | |
2303 | // Walk the list of contexts\r | |
2304 | //\r | |
2305 | pContext = pTftpServer->pContextList;\r | |
2306 | while ( NULL != pContext )\r | |
2307 | {\r | |
2308 | //\r | |
2309 | // Check for a transmit timeout\r | |
2310 | //\r | |
2311 | pPacket = pContext->pTxHead;\r | |
2312 | if ( NULL != pPacket ) {\r | |
2313 | //\r | |
2314 | // Compute the elapsed time\r | |
2315 | //\r | |
2316 | if ( pTftpServer->Time2 > pTftpServer->Time1 ) {\r | |
2317 | ElapsedTime = CurrentTime - pPacket->TxTime;\r | |
2318 | }\r | |
2319 | else {\r | |
2320 | ElapsedTime = pPacket->TxTime - CurrentTime;\r | |
2321 | }\r | |
2322 | ElapsedTime = GetTimeInNanoSecond ( ElapsedTime );\r | |
2323 | \r | |
2324 | //\r | |
2325 | // Determine if a retransmission is necessary\r | |
2326 | //\r | |
2327 | if ( ElapsedTime >= pContext->Rtt2x ) {\r | |
2328 | DEBUG (( DEBUG_WINDOW,\r | |
2329 | "0x%08x: Context TX timeout for packet 0x%08x, Window: %d\r\n",\r | |
2330 | pContext,\r | |
2331 | pPacket,\r | |
2332 | pContext->WindowSize ));\r | |
2333 | WindowTimeout ( pContext );\r | |
2334 | }\r | |
2335 | }\r | |
2336 | \r | |
2337 | //\r | |
2338 | // Set the next context\r | |
2339 | //\r | |
2340 | pContext = pContext->pNext;\r | |
2341 | }\r | |
2342 | }\r | |
2343 | } while ( DIM ( pTftpServer->TftpPort ) == pTftpServer->Entries );\r | |
2344 | } while ( !mbTftpServerExit );\r | |
7dc13291 | 2345 | \r |
2346 | //\r | |
2347 | // Done with the timer event\r | |
2348 | //\r | |
f6e5cdd5 | 2349 | gBS->SetTimer ( pTftpServer->TimerEvent,\r |
2350 | TimerCancel,\r | |
2351 | 0 );\r | |
7dc13291 | 2352 | }\r |
f6e5cdd5 | 2353 | gBS->CloseEvent ( pTftpServer->TimerEvent );\r |
7dc13291 | 2354 | }\r |
2355 | \r | |
2356 | //\r | |
2357 | // Return the final status\r | |
2358 | //\r | |
2359 | DBG_EXIT_STATUS ( Status );\r | |
2360 | return Status;\r | |
2361 | }\r |