]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - StdLib/EfiSocketLib/Socket.c
Update secure boot UI driver to handle “reset to default” hot key.
[mirror_edk2.git] / StdLib / EfiSocketLib / Socket.c
... / ...
CommitLineData
1/** @file\r
2 Implement the socket support for the socket layer.\r
3\r
4 Socket States:\r
5 * Bound - pSocket->PortList is not NULL\r
6 * Listen - AcceptWait event is not NULL\r
7\r
8 Copyright (c) 2011, Intel Corporation\r
9 All rights reserved. This program and the accompanying materials\r
10 are licensed and made available under the terms and conditions of the BSD License\r
11 which accompanies this distribution. The full text of the license may be found at\r
12 http://opensource.org/licenses/bsd-license.php\r
13\r
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17\r
18 \section DataStructures Data Structures\r
19\r
20 <code><pre>\r
21\r
22 +-------------+ +-------------+ +-------------+ \r
23 Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)\r
24 +-------------+ +-------------+ +-------------+ \r
25 ^ | (pPortList) |\r
26 pUdp4List ^ | pTcp4List | |\r
27 | | | |\r
28 ^ | | | |\r
29 pIp4List | | | | |\r
30 +---------------+ | |\r
31 | ::ESL_LAYER | ::mEslLayer | |\r
32 +---------------+ | |\r
33 | (pSocketList) | |\r
34 Socket List V V V\r
35 +-------------+ +-------------+ +-------------+ \r
36 | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)\r
37 +-------------+ +-------------+ +-------------+ \r
38 | | |\r
39 | | V\r
40 V V NULL\r
41 +-------------+ +-------------+ \r
42 | ESL_SOCKET |-->| ESL_PORT |--> NULL\r
43 +-------------+ +-------------+\r
44 | | | | | |\r
45 V | | | | V\r
46 NULL | | | | NULL\r
47 (pNext) | | | | (pLinkService)\r
48 | | | | pRxPacketListHead\r
49 | | | `-----------------------------------------------.\r
50 | | | pRxOobPacketListHead |\r
51 | | `--------------------------------. |\r
52 | | pTxPacketListHead | |\r
53 | `---------------. | |\r
54 pTxOobPacketListHead | | | |\r
55 V V V V\r
56 +------------+ +------------+ +------------+ +------------+\r
57 | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |\r
58 +------------+ +------------+ +------------+ +------------+\r
59 | | | |\r
60 V V V V\r
61 +------------+ +------------+ +------------+ +------------+\r
62 | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |\r
63 +------------+ +------------+ +------------+ +------------+\r
64 | | | |\r
65 V V V V\r
66 NULL NULL NULL NULL\r
67 (pNext)\r
68\r
69 </pre></code>\r
70\r
71 ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or\r
72 indirectly to the other data structures. The ESL_LAYER structure has a unique\r
73 service list for each of the network protocol interfaces.\r
74\r
75 ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)\r
76\r
77 ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains\r
78 the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object\r
79 reference and the API into the EFI socket library.\r
80\r
81 ::ESL_PORT manages the connection with a single instance of the lower layer network.\r
82 This structure is the socket equivalent of an IP connection or a TCP or UDP port.\r
83\r
84 ::ESL_PACKET buffers data for transmit and receive. There are four queues connected\r
85 to the ::ESL_SOCKET that manage the data:\r
86 <ul>\r
87 <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>\r
88 <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>\r
89 <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>\r
90 <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>\r
91 </ul>\r
92 The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit\r
93 request as well as the socket option SO_OOBINLINE. The receive queue is selected by\r
94 the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.\r
95\r
96 Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying\r
97 critical elements within the data structures must be done at this TPL. TPL is then\r
98 restored to the previous level. Note that the code verifies that all callbacks are\r
99 entering at TPL_SOCKETS for proper data structure synchronization.\r
100\r
101 \section PortCloseStateMachine Port Close State Machine\r
102\r
103 The port close state machine walks the port through the necessary\r
104 states to stop activity on the port and get it into a state where\r
105 the resources may be released. The state machine consists of the\r
106 following arcs and states:\r
107\r
108 <code><pre>\r
109\r
110 +--------------------------+\r
111 | Open |\r
112 +--------------------------+\r
113 |\r
114 | ::EslSocketPortCloseStart\r
115 V\r
116 +--------------------------+\r
117 | PORT_STATE_CLOSE_STARTED |\r
118 +--------------------------+\r
119 |\r
120 | ::EslSocketPortCloseTxDone\r
121 V\r
122 +--------------------------+\r
123 | PORT_STATE_CLOSE_TX_DONE |\r
124 +--------------------------+\r
125 |\r
126 | ::EslSocketPortCloseComplete\r
127 V\r
128 +--------------------------+\r
129 | PORT_STATE_CLOSE_DONE |\r
130 +--------------------------+\r
131 |\r
132 | ::EslSocketPortCloseRxDone\r
133 V\r
134 +--------------------------+\r
135 | PORT_STATE_CLOSE_RX_DONE |\r
136 +--------------------------+\r
137 |\r
138 | ::EslSocketPortClose\r
139 V\r
140 +--------------------------+\r
141 | Closed |\r
142 +--------------------------+\r
143\r
144 </pre></code>\r
145\r
146 <ul>\r
147 <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and\r
148 initiates the port close operation</li>\r
149 <li>State: PORT_STATE_CLOSE_STARTED</li>\r
150 <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit\r
151 operations to complete. After all of the transmits are complete,\r
152 this routine initiates the network specific close operation by calling\r
153 through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is\r
154 ::EslTcp4PortCloseOp.\r
155 </li>\r
156 <li>State: PORT_STATE_CLOSE_TX_DONE</li>\r
157 <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is \r
158 complete. After the transition to PORT_STATE_CLOSE_DONE,\r
159 this routine calls ::EslSocketRxCancel to abort the pending receive operations.\r
160 </li>\r
161 <li>State: PORT_STATE_CLOSE_DONE</li>\r
162 <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive\r
163 operation have been cancelled. After the transition to\r
164 PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.\r
165 </li>\r
166 <li>State: PORT_STATE_CLOSE_RX_DONE</li>\r
167 <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers\r
168 using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.\r
169 This routine then releases the port resources allocated by ::EslSocketPortAllocate\r
170 and calls the network specific port close routine (e.g. ::EslTcp4PortClose)\r
171 via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.\r
172 </li>\r
173 </ul>\r
174\r
175\r
176 \section ReceiveEngine Receive Engine\r
177\r
178 The receive path accepts data from the network and queues (buffers) it for the\r
179 application. Flow control is applied once a maximum amount of buffering is reached\r
180 and is released when the buffer usage drops below that limit. Eventually the\r
181 application requests data from the socket which removes entries from the queue and\r
182 returns the data.\r
183\r
184 The receive engine is the state machine which reads data from the network and\r
185 fills the queue with received packets. The receive engine uses two data structures\r
186 to manage the network receive opeations and the buffers.\r
187\r
188 At a high level, the ::ESL_IO_MGMT structures are managing the tokens and\r
189 events for the interface to the UEFI network stack. The ::ESL_PACKET\r
190 structures are managing the receive data buffers. The receive engine\r
191 connects these two structures in the network specific receive completion\r
192 routines.\r
193\r
194<code><pre>\r
195\r
196 +------------------+\r
197 | ::ESL_PORT |\r
198 | |\r
199 +------------------+\r
200 | ::ESL_IO_MGMT |\r
201 +------------------+\r
202 | ESL_IO_MGMT |\r
203 +------------------+\r
204 . .\r
205 . ESL_IO_MGMT .\r
206 . .\r
207 +------------------+\r
208\r
209</pre></code>\r
210\r
211 The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in\r
212 ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on\r
213 the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains\r
214 the network layer specific receive completion token and event. The receive engine\r
215 is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these\r
216 structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.\r
217\r
218<code><pre>\r
219\r
220 pPort->pRxActive\r
221 |\r
222 V\r
223 +-------------+ +-------------+ +-------------+ \r
224 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
225 +-------------+ +-------------+ +-------------+ \r
226\r
227 +-------------+ +-------------+ +-------------+ \r
228 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
229 +-------------+ +-------------+ +-------------+ \r
230 ^\r
231 |\r
232 pPort->pRxFree\r
233</pre></code>\r
234\r
235 The receive engine is started by calling ::EslSocketRxStart. Flow control pauses\r
236 the receive engine by stopping the calls to EslSocketRxStart when the amount of\r
237 receive data waiting for the application meets or exceeds MAX_RX_DATA. After\r
238 the application reads enough data that the amount of buffering drops below this\r
239 limit, the calls to EslSockeRxStart continue which releases the flow control.\r
240\r
241 Receive flow control is applied when the port is created, since no receive\r
242 operation are pending to the low layer network driver. The flow control gets\r
243 released when the low layer network port is configured or the first receive\r
244 operation is posted. Flow control remains in the released state until the\r
245 maximum buffer space is consumed. During this time, ::EslSocketRxComplete\r
246 calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete\r
247 by skipping the call to EslSocketRxStart. Flow control is eventually\r
248 released in ::EslSocketReceive when the buffer space drops below the\r
249 maximum amount causing EslSocketReceive to call EslSocketRxStart.\r
250\r
251<code><pre>\r
252\r
253 +------------+ +------------+ \r
254 High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)\r
255 Priority | +------------+ +------------+\r
256 |\r
257 | pRxOobPacketListHead\r
258 +------------+\r
259 | ::ESL_SOCKET |\r
260 +------------+\r
261 | pRxPacketListHead\r
262 Low |\r
263 Priority | +------------+ +------------+ +------------+ \r
264 `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
265 +------------+ +------------+ +------------+ \r
266\r
267</pre></code>\r
268\r
269 ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure\r
270 and then calls the network layer to start the receive operation. Upon \r
271 receive completion, ::EslSocketRxComplete breaks the connection between these\r
272 structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to\r
273 make token and event available for another receive operation. EslSocketRxComplete\r
274 then queues the ESL_PACKET structure (data packet) to either the\r
275 ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on\r
276 whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts\r
277 to start another receive operation.\r
278\r
279<code><pre>\r
280\r
281 Setup for IP4 and UDP4\r
282\r
283 +--------------------+\r
284 | ESL_IO_MGMT |\r
285 | |\r
286 | +---------------+\r
287 | | Token |\r
288 | | RxData --> NULL\r
289 +----+---------------+\r
290 |\r
291 V\r
292 +--------------------+\r
293 | ESL_PACKET |\r
294 | |\r
295 | +---------------+\r
296 | | pRxData --> NULL\r
297 +----+---------------+\r
298\r
299 Completion for IP4 and UDP4\r
300\r
301 +--------------------+ +----------------------+\r
302 | ESL_IO_MGMT | | Data Buffer |\r
303 | | | (Driver owned) |\r
304 | +---------------+ +----------------------+\r
305 | | Token | ^\r
306 | | Rx Event | |\r
307 | | | +----------------------+\r
308 | | RxData --> | EFI_IP4_RECEIVE_DATA |\r
309 +----+---------------+ | (Driver owned) |\r
310 | +----------------------+\r
311 V ^\r
312 +--------------------+ .\r
313 | ESL_PACKET | .\r
314 | | .\r
315 | +---------------+ .\r
316 | | pRxData --> NULL .......\r
317 +----+---------------+\r
318\r
319\r
320 Setup and completion for TCP4\r
321\r
322 +--------------------+ +--------------------------+\r
323 | ESL_IO_MGMT |-->| ESL_PACKET |\r
324 | | | |\r
325 | +---------------+ +----------------------+ |\r
326 | | Token | | EFI_IP4_RECEIVE_DATA | |\r
327 | | RxData --> | | |\r
328 | | | +----------------------+---+\r
329 | | Event | | Data Buffer |\r
330 +----+---------------+ | |\r
331 | |\r
332 +--------------------------+\r
333\r
334</pre></code>\r
335\r
336 To minimize the number of buffer copies, the data is not copied until the\r
337 application makes a receive call. At this point socket performs a single copy\r
338 in the receive path to move the data from the buffer filled by the network layer\r
339 into the application's buffer.\r
340\r
341 The IP4 and UDP4 drivers go one step further to reduce buffer copies. They\r
342 allow the socket layer to hold on to the actual receive buffer until the\r
343 application has performed a receive operation or closes the socket. Both\r
344 of theses operations return the buffer to the lower layer network driver\r
345 by calling ESL_PROTOCOL_API::pfnPacketFree.\r
346\r
347 When a socket application wants to receive data it indirectly calls\r
348 ::EslSocketReceive to remove data from one of the receive data queues. This routine\r
349 removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or\r
350 ESL_SOCKET::pRxPacketListHead and copies the data from the packet\r
351 into the application's buffer. For SOCK_STREAM sockets, if the packet\r
352 contains more data then the ESL_PACKET structures remains at the head of the\r
353 receive queue for the next application receive\r
354 operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET\r
355 structure is removed from the head of the receive queue and any remaining data is\r
356 discarded as the packet is placed on the free queue.\r
357\r
358 During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to\r
359 cancel any pending receive operations. EslSocketRxCancel calls the network specific\r
360 cancel routine using ESL_PORT::pfnRxCancel.\r
361\r
362\r
363 \section TransmitEngine Transmit Engine\r
364\r
365 Application calls to ::EslSocketTransmit cause data to be copied into a buffer.\r
366 The buffer exists as an extension to an ESL_PACKET structure and the structure\r
367 is placed at the end of the transmit queue.\r
368\r
369<code><pre>\r
370\r
371 *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead\r
372 |\r
373 V\r
374 +------------+ +------------+ +------------+ \r
375 Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
376 +------------+ +------------+ +------------+ \r
377 ^\r
378 |\r
379 *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail\r
380\r
381</pre></code>\r
382\r
383 There are actually two transmit queues the normal or low priority queue which is\r
384 the default and the urgent or high priority queue which is addressed by specifying\r
385 the MSG_OOB flag during the transmit request. Associated with each queue is a\r
386 transmit engine which is responsible for sending the data in that queue.\r
387\r
388 The transmit engine is the state machine which removes entries from the head\r
389 of the transmit queue and causes the data to be sent over the network.\r
390\r
391<code><pre>\r
392\r
393 +--------------------+ +--------------------+\r
394 | ESL_IO_MGMT | | ESL_PACKET |\r
395 | | | |\r
396 | +---------------+ +----------------+ |\r
397 | | Token | | Buffer Length | |\r
398 | | TxData --> | Buffer Address | |\r
399 | | | +----------------+---+\r
400 | | Event | | Data Buffer |\r
401 +----+---------------+ | |\r
402 +--------------------+\r
403</pre></code>\r
404\r
405 At a high level, the transmit engine uses a couple of data structures\r
406 to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and\r
407 events for the interface to the UEFI network stack. The ::ESL_PACKET\r
408 structures manage the data buffers that get sent. The transmit\r
409 engine connects these two structures prior to transmission and disconnects\r
410 them upon completion.\r
411\r
412<code><pre>\r
413\r
414 pPort->pTxActive or pTxOobActive\r
415 |\r
416 V\r
417 +-------------+ +-------------+ +-------------+ \r
418 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
419 +-------------+ +-------------+ +-------------+ \r
420\r
421 +-------------+ +-------------+ +-------------+ \r
422 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
423 +-------------+ +-------------+ +-------------+ \r
424 ^\r
425 |\r
426 pPort->pTxFree or pTxOobFree\r
427\r
428</pre></code>\r
429\r
430 The transmit engine manages multiple transmit operations using the\r
431 active and free lists shown above. ::EslSocketPortAllocate allocates the\r
432 ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.\r
433 This routine places the ESL_IO_MGMT structures on the free list by calling\r
434 ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures\r
435 will move from the free list to the active list and back again. The\r
436 active list contains the packets that are actively being processed by\r
437 the UEFI network stack. Eventually the ESL_IO_MGMT structures will be\r
438 removed from the free list and be deallocated by the EslSocketPortClose\r
439 routine.\r
440\r
441 The network specific code calls the ::EslSocketTxStart routine\r
442 to hand a packet to the network stack. EslSocketTxStart connects\r
443 the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure\r
444 and then queues the result to one of the active lists:\r
445 ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then\r
446 hands the packet to the network stack.\r
447\r
448 Upon completion, the network specific TxComplete routine calls\r
449 ::EslSocketTxComplete to disconnect the transmit packet from the\r
450 ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling\r
451 ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure\r
452 into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.\r
453 EslSocketTxComplete then starts the next transmit operation while\r
454 the socket is active or calls the ::EslSocketPortCloseTxDone routine\r
455 when the socket is shutting down.\r
456\r
457**/\r
458\r
459#include "Socket.h"\r
460\r
461\r
462/**\r
463 Socket driver connection points\r
464\r
465 List the network stack connection points for the socket driver.\r
466**/\r
467CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {\r
468 { L"Ip4",\r
469 &gEfiIp4ServiceBindingProtocolGuid,\r
470 &gEfiIp4ProtocolGuid,\r
471 &mEslIp4ServiceGuid,\r
472 OFFSET_OF ( ESL_LAYER, pIp4List ),\r
473 4, // RX buffers\r
474 4, // TX buffers\r
475 0 }, // TX Oob buffers\r
476 { L"Tcp4",\r
477 &gEfiTcp4ServiceBindingProtocolGuid,\r
478 &gEfiTcp4ProtocolGuid,\r
479 &mEslTcp4ServiceGuid,\r
480 OFFSET_OF ( ESL_LAYER, pTcp4List ),\r
481 4, // RX buffers\r
482 4, // TX buffers\r
483 4 }, // TX Oob buffers\r
484 { L"Tcp6",\r
485 &gEfiTcp6ServiceBindingProtocolGuid,\r
486 &gEfiTcp6ProtocolGuid,\r
487 &mEslTcp6ServiceGuid,\r
488 OFFSET_OF ( ESL_LAYER, pTcp6List ),\r
489 4, // RX buffers\r
490 4, // TX buffers\r
491 4 }, // TX Oob buffers\r
492 { L"Udp4",\r
493 &gEfiUdp4ServiceBindingProtocolGuid,\r
494 &gEfiUdp4ProtocolGuid,\r
495 &mEslUdp4ServiceGuid,\r
496 OFFSET_OF ( ESL_LAYER, pUdp4List ),\r
497 4, // RX buffers\r
498 4, // TX buffers\r
499 0 }, // TX Oob buffers\r
500 { L"Udp6",\r
501 &gEfiUdp6ServiceBindingProtocolGuid,\r
502 &gEfiUdp6ProtocolGuid,\r
503 &mEslUdp6ServiceGuid,\r
504 OFFSET_OF ( ESL_LAYER, pUdp6List ),\r
505 4, // RX buffers\r
506 4, // TX buffers\r
507 0 } // TX Oob buffers\r
508};\r
509\r
510CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );\r
511\r
512/**\r
513 APIs to support the various socket types for the v4 network stack.\r
514**/\r
515CONST ESL_PROTOCOL_API * cEslAfInetApi[] = {\r
516 NULL, // 0\r
517 &cEslTcp4Api, // SOCK_STREAM\r
518 &cEslUdp4Api, // SOCK_DGRAM\r
519 &cEslIp4Api, // SOCK_RAW\r
520 NULL, // SOCK_RDM\r
521 &cEslTcp4Api // SOCK_SEQPACKET\r
522};\r
523\r
524/**\r
525 Number of entries in the v4 API array ::cEslAfInetApi.\r
526**/\r
527CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );\r
528\r
529\r
530/**\r
531 APIs to support the various socket types for the v6 network stack.\r
532**/\r
533CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {\r
534 NULL, // 0\r
535 &cEslTcp6Api, // SOCK_STREAM\r
536 &cEslUdp6Api, // SOCK_DGRAM\r
537 NULL, // SOCK_RAW\r
538 NULL, // SOCK_RDM\r
539 &cEslTcp6Api // SOCK_SEQPACKET\r
540};\r
541\r
542/**\r
543 Number of entries in the v6 API array ::cEslAfInet6Api.\r
544**/\r
545CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );\r
546\r
547\r
548/**\r
549 Global management structure for the socket layer.\r
550**/\r
551ESL_LAYER mEslLayer;\r
552\r
553\r
554/**\r
555 Initialize an endpoint for network communication.\r
556\r
557 This routine initializes the communication endpoint.\r
558\r
559 The ::socket routine calls this routine indirectly to create\r
560 the communication endpoint.\r
561\r
562 @param [in] pSocketProtocol Address of the socket protocol structure.\r
563 @param [in] domain Select the family of protocols for the client or server\r
564 application. See the ::socket documentation for values.\r
565 @param [in] type Specifies how to make the network connection.\r
566 See the ::socket documentation for values.\r
567 @param [in] protocol Specifies the lower layer protocol to use.\r
568 See the ::socket documentation for values.\r
569 @param [out] pErrno Address to receive the errno value upon completion.\r
570\r
571 @retval EFI_SUCCESS - Socket successfully created\r
572 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT\r
573 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL\r
574 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL\r
575\r
576 **/\r
577EFI_STATUS\r
578EslSocket (\r
579 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
580 IN int domain,\r
581 IN int type,\r
582 IN int protocol,\r
583 IN int * pErrno\r
584 )\r
585{\r
586 CONST ESL_PROTOCOL_API * pApi;\r
587 CONST ESL_PROTOCOL_API ** ppApiArray;\r
588 CONST ESL_PROTOCOL_API ** ppApiArrayEnd;\r
589 int ApiArraySize;\r
590 ESL_SOCKET * pSocket;\r
591 EFI_STATUS Status;\r
592 int errno;\r
593\r
594 DBG_ENTER ( );\r
595\r
596 //\r
597 // Locate the socket\r
598 //\r
599 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
600\r
601 //\r
602 // Set the default domain if necessary\r
603 //\r
604 if ( AF_UNSPEC == domain ) {\r
605 domain = AF_INET;\r
606 }\r
607\r
608 //\r
609 // Assume success\r
610 //\r
611 errno = 0;\r
612 Status = EFI_SUCCESS;\r
613\r
614 //\r
615 // Use break instead of goto\r
616 //\r
617 for ( ; ; ) {\r
618 //\r
619 // Validate the domain value\r
620 //\r
621 if (( AF_INET != domain )\r
622 && ( AF_INET6 != domain )\r
623 && ( AF_LOCAL != domain )) {\r
624 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
625 "ERROR - Invalid domain value\r\n" ));\r
626 Status = EFI_INVALID_PARAMETER;\r
627 errno = EAFNOSUPPORT;\r
628 break;\r
629 }\r
630\r
631 //\r
632 // Determine the protocol APIs\r
633 //\r
634 ppApiArray = NULL;\r
635 ApiArraySize = 0;\r
636 if (( AF_INET == domain )\r
637 || ( AF_LOCAL == domain )) {\r
638 ppApiArray = &cEslAfInetApi[0];\r
639 ApiArraySize = cEslAfInetApiSize;\r
640 }\r
641 else {\r
642 ppApiArray = &cEslAfInet6Api[0];\r
643 ApiArraySize = cEslAfInet6ApiSize;\r
644 }\r
645\r
646 //\r
647 // Set the default type if necessary\r
648 //\r
649 if ( 0 == type ) {\r
650 type = SOCK_STREAM;\r
651 }\r
652\r
653 //\r
654 // Validate the type value\r
655 //\r
656 if (( type >= ApiArraySize )\r
657 || ( NULL == ppApiArray )\r
658 || ( NULL == ppApiArray[ type ])) {\r
659 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
660 "ERROR - Invalid type value\r\n" ));\r
661 //\r
662 // The socket type is not supported\r
663 //\r
664 Status = EFI_INVALID_PARAMETER;\r
665 errno = EPROTOTYPE;\r
666 break;\r
667 }\r
668\r
669 //\r
670 // Set the default protocol if necessary\r
671 //\r
672 pApi = ppApiArray[ type ];\r
673 if ( 0 == protocol ) {\r
674 protocol = pApi->DefaultProtocol;\r
675 }\r
676\r
677 //\r
678 // Validate the protocol value\r
679 //\r
680 if (( pApi->DefaultProtocol != protocol )\r
681 && ( SOCK_RAW != type )) {\r
682 Status = EFI_INVALID_PARAMETER;\r
683\r
684 //\r
685 // Assume that the driver supports this protocol\r
686 //\r
687 ppApiArray = &cEslAfInetApi[0];\r
688 ppApiArrayEnd = &ppApiArray [ cEslAfInetApiSize ];\r
689 while ( ppApiArrayEnd > ppApiArray ) {\r
690 pApi = *ppApiArray;\r
691 if ( protocol == pApi->DefaultProtocol ) {\r
692 break;\r
693 }\r
694 ppApiArray += 1;\r
695 }\r
696 if ( ppApiArrayEnd <= ppApiArray ) {\r
697 //\r
698 // Verify against the IPv6 table\r
699 //\r
700 ppApiArray = &cEslAfInet6Api[0];\r
701 ppApiArrayEnd = &ppApiArray [ cEslAfInet6ApiSize ];\r
702 while ( ppApiArrayEnd > ppApiArray ) {\r
703 pApi = *ppApiArray;\r
704 if ( protocol == pApi->DefaultProtocol ) {\r
705 break;\r
706 }\r
707 ppApiArray += 1;\r
708 }\r
709 }\r
710 if ( ppApiArrayEnd <= ppApiArray ) {\r
711 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
712 "ERROR - The protocol is not supported!\r\n" ));\r
713 errno = EPROTONOSUPPORT;\r
714 break;\r
715 }\r
716\r
717 //\r
718 // The driver does not support this protocol\r
719 //\r
720 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
721 "ERROR - The protocol does not support this socket type!\r\n" ));\r
722 errno = EPROTONOSUPPORT;\r
723 errno = EPROTOTYPE;\r
724 break;\r
725 }\r
726\r
727 //\r
728 // Save the socket attributes\r
729 //\r
730 pSocket->pApi = pApi;\r
731 pSocket->Domain = domain;\r
732 pSocket->Type = type;\r
733 pSocket->Protocol = protocol;\r
734\r
735 //\r
736 // Done\r
737 //\r
738 break;\r
739 }\r
740\r
741 //\r
742 // Return the operation status\r
743 //\r
744 if ( NULL != pErrno ) {\r
745 *pErrno = errno;\r
746 }\r
747 DBG_EXIT_STATUS ( Status );\r
748 return Status;\r
749}\r
750\r
751\r
752/**\r
753 Accept a network connection.\r
754\r
755 This routine calls the network specific layer to remove the next\r
756 connection from the FIFO.\r
757\r
758 The ::accept calls this routine to poll for a network\r
759 connection to the socket. When a connection is available\r
760 this routine returns the ::EFI_SOCKET_PROTOCOL structure address\r
761 associated with the new socket and the remote network address\r
762 if requested.\r
763\r
764 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
765\r
766 @param [in] pSockAddr Address of a buffer to receive the remote\r
767 network address.\r
768\r
769 @param [in, out] pSockAddrLength Length in bytes of the address buffer.\r
770 On output specifies the length of the\r
771 remote network address.\r
772\r
773 @param [out] ppSocketProtocol Address of a buffer to receive the\r
774 ::EFI_SOCKET_PROTOCOL instance\r
775 associated with the new socket.\r
776\r
777 @param [out] pErrno Address to receive the errno value upon completion.\r
778\r
779 @retval EFI_SUCCESS New connection successfully created\r
780 @retval EFI_NOT_READY No connection is available\r
781\r
782 **/\r
783EFI_STATUS\r
784EslSocketAccept (\r
785 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
786 IN struct sockaddr * pSockAddr,\r
787 IN OUT socklen_t * pSockAddrLength,\r
788 IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,\r
789 IN int * pErrno\r
790 )\r
791{\r
792 ESL_SOCKET * pNewSocket;\r
793 ESL_SOCKET * pSocket;\r
794 EFI_STATUS Status;\r
795 EFI_TPL TplPrevious;\r
796\r
797 DBG_ENTER ( );\r
798\r
799 //\r
800 // Assume success\r
801 //\r
802 Status = EFI_SUCCESS;\r
803\r
804 //\r
805 // Validate the socket\r
806 //\r
807 pSocket = NULL;\r
808 pNewSocket = NULL;\r
809 if ( NULL != pSocketProtocol ) {\r
810 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
811\r
812 //\r
813 // Verify the API\r
814 //\r
815 if ( NULL == pSocket->pApi->pfnAccept ) {\r
816 Status = EFI_UNSUPPORTED;\r
817 pSocket->errno = ENOTSUP;\r
818 }\r
819 else {\r
820 //\r
821 // Validate the sockaddr\r
822 //\r
823 if (( NULL != pSockAddr )\r
824 && ( NULL == pSockAddrLength )) {\r
825 DEBUG (( DEBUG_ACCEPT,\r
826 "ERROR - pSockAddr is NULL!\r\n" ));\r
827 Status = EFI_INVALID_PARAMETER;\r
828 pSocket->errno = EFAULT;\r
829 }\r
830 else {\r
831 //\r
832 // Synchronize with the socket layer\r
833 //\r
834 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
835\r
836 //\r
837 // Verify that the socket is in the listen state\r
838 //\r
839 if ( SOCKET_STATE_LISTENING != pSocket->State ) {\r
840 DEBUG (( DEBUG_ACCEPT,\r
841 "ERROR - Socket is not listening!\r\n" ));\r
842 if ( NULL == pSocket->pApi->pfnAccept ) {\r
843 //\r
844 // Socket does not support listen\r
845 //\r
846 pSocket->errno = EOPNOTSUPP;\r
847 Status = EFI_UNSUPPORTED;\r
848 }\r
849 else {\r
850 //\r
851 // Socket supports listen, but not in listen state\r
852 //\r
853 pSocket->errno = EINVAL;\r
854 Status = EFI_NOT_STARTED;\r
855 }\r
856 }\r
857 else {\r
858 //\r
859 // Determine if a socket is available\r
860 //\r
861 if ( 0 == pSocket->FifoDepth ) {\r
862 //\r
863 // No connections available\r
864 // Determine if any ports are available\r
865 //\r
866 if ( NULL == pSocket->pPortList ) {\r
867 //\r
868 // No ports available\r
869 //\r
870 Status = EFI_DEVICE_ERROR;\r
871 pSocket->errno = EINVAL;\r
872\r
873 //\r
874 // Update the socket state\r
875 //\r
876 pSocket->State = SOCKET_STATE_NO_PORTS;\r
877 }\r
878 else {\r
879 //\r
880 // Ports are available\r
881 // No connection requests at this time\r
882 //\r
883 Status = EFI_NOT_READY;\r
884 pSocket->errno = EAGAIN;\r
885 }\r
886 }\r
887 else {\r
888\r
889 //\r
890 // Attempt to accept the connection and\r
891 // get the remote network address\r
892 //\r
893 pNewSocket = pSocket->pFifoHead;\r
894 ASSERT ( NULL != pNewSocket );\r
895 Status = pSocket->pApi->pfnAccept ( pNewSocket,\r
896 pSockAddr,\r
897 pSockAddrLength );\r
898 if ( !EFI_ERROR ( Status )) {\r
899 //\r
900 // Remove the new socket from the list\r
901 //\r
902 pSocket->pFifoHead = pNewSocket->pNextConnection;\r
903 if ( NULL == pSocket->pFifoHead ) {\r
904 pSocket->pFifoTail = NULL;\r
905 }\r
906\r
907 //\r
908 // Account for this socket\r
909 //\r
910 pSocket->FifoDepth -= 1;\r
911\r
912 //\r
913 // Update the new socket's state\r
914 //\r
915 pNewSocket->State = SOCKET_STATE_CONNECTED;\r
916 pNewSocket->bConfigured = TRUE;\r
917 DEBUG (( DEBUG_ACCEPT,\r
918 "0x%08x: Socket connected\r\n",\r
919 pNewSocket ));\r
920 }\r
921 }\r
922 }\r
923\r
924 //\r
925 // Release the socket layer synchronization\r
926 //\r
927 RESTORE_TPL ( TplPrevious );\r
928 }\r
929 }\r
930 }\r
931\r
932 //\r
933 // Return the new socket\r
934 //\r
935 if (( NULL != ppSocketProtocol )\r
936 && ( NULL != pNewSocket )) {\r
937 *ppSocketProtocol = &pNewSocket->SocketProtocol;\r
938 }\r
939\r
940 //\r
941 // Return the operation status\r
942 //\r
943 if ( NULL != pErrno ) {\r
944 if ( NULL != pSocket ) {\r
945 *pErrno = pSocket->errno;\r
946 }\r
947 else {\r
948 Status = EFI_INVALID_PARAMETER;\r
949 *pErrno = ENOTSOCK;\r
950 }\r
951 }\r
952 DBG_EXIT_STATUS ( Status );\r
953 return Status;\r
954}\r
955\r
956\r
957/**\r
958 Allocate and initialize a ESL_SOCKET structure.\r
959 \r
960 This support function allocates an ::ESL_SOCKET structure\r
961 and installs a protocol on ChildHandle. If pChildHandle is a\r
962 pointer to NULL, then a new handle is created and returned in\r
963 pChildHandle. If pChildHandle is not a pointer to NULL, then\r
964 the protocol installs on the existing pChildHandle.\r
965\r
966 @param [in, out] pChildHandle Pointer to the handle of the child to create.\r
967 If it is NULL, then a new handle is created.\r
968 If it is a pointer to an existing UEFI handle, \r
969 then the protocol is added to the existing UEFI\r
970 handle.\r
971 @param [in] DebugFlags Flags for debug messages\r
972 @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.\r
973\r
974 @retval EFI_SUCCESS The protocol was added to ChildHandle.\r
975 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
976 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create\r
977 the child\r
978 @retval other The child handle was not created\r
979 \r
980**/\r
981EFI_STATUS\r
982EFIAPI\r
983EslSocketAllocate (\r
984 IN OUT EFI_HANDLE * pChildHandle,\r
985 IN UINTN DebugFlags,\r
986 IN OUT ESL_SOCKET ** ppSocket\r
987 )\r
988{\r
989 UINTN LengthInBytes;\r
990 ESL_LAYER * pLayer;\r
991 ESL_SOCKET * pSocket;\r
992 EFI_STATUS Status;\r
993 EFI_TPL TplPrevious;\r
994\r
995 DBG_ENTER ( );\r
996\r
997 //\r
998 // Create a socket structure\r
999 //\r
1000 LengthInBytes = sizeof ( *pSocket );\r
1001 pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );\r
1002 if ( NULL != pSocket ) {\r
1003 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
1004 "0x%08x: Allocate pSocket, %d bytes\r\n",\r
1005 pSocket,\r
1006 LengthInBytes ));\r
1007\r
1008 //\r
1009 // Initialize the socket protocol\r
1010 //\r
1011 pSocket->Signature = SOCKET_SIGNATURE;\r
1012 pSocket->SocketProtocol.pfnAccept = EslSocketAccept;\r
1013 pSocket->SocketProtocol.pfnBind = EslSocketBind;\r
1014 pSocket->SocketProtocol.pfnClosePoll = EslSocketClosePoll;\r
1015 pSocket->SocketProtocol.pfnCloseStart = EslSocketCloseStart;\r
1016 pSocket->SocketProtocol.pfnConnect = EslSocketConnect;\r
1017 pSocket->SocketProtocol.pfnGetLocal = EslSocketGetLocalAddress;\r
1018 pSocket->SocketProtocol.pfnGetPeer = EslSocketGetPeerAddress;\r
1019 pSocket->SocketProtocol.pfnListen = EslSocketListen;\r
1020 pSocket->SocketProtocol.pfnOptionGet = EslSocketOptionGet;\r
1021 pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;\r
1022 pSocket->SocketProtocol.pfnPoll = EslSocketPoll;\r
1023 pSocket->SocketProtocol.pfnReceive = EslSocketReceive;\r
1024 pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;\r
1025 pSocket->SocketProtocol.pfnSocket = EslSocket;\r
1026 pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;\r
1027\r
1028 pSocket->MaxRxBuf = MAX_RX_DATA;\r
1029 pSocket->MaxTxBuf = MAX_TX_DATA;\r
1030\r
1031 //\r
1032 // Install the socket protocol on the specified handle\r
1033 //\r
1034 Status = gBS->InstallMultipleProtocolInterfaces (\r
1035 pChildHandle,\r
1036 &gEfiSocketProtocolGuid,\r
1037 &pSocket->SocketProtocol,\r
1038 NULL\r
1039 );\r
1040 if ( !EFI_ERROR ( Status )) {\r
1041 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
1042 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",\r
1043 *pChildHandle ));\r
1044 pSocket->SocketProtocol.SocketHandle = *pChildHandle;\r
1045\r
1046 //\r
1047 // Synchronize with the socket layer\r
1048 //\r
1049 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1050\r
1051 //\r
1052 // Add this socket to the list\r
1053 //\r
1054 pLayer = &mEslLayer;\r
1055 pSocket->pNext = pLayer->pSocketList;\r
1056 pLayer->pSocketList = pSocket;\r
1057\r
1058 //\r
1059 // Release the socket layer synchronization\r
1060 //\r
1061 RESTORE_TPL ( TplPrevious );\r
1062\r
1063 //\r
1064 // Return the socket structure address\r
1065 //\r
1066 *ppSocket = pSocket;\r
1067 }\r
1068 else {\r
1069 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
1070 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",\r
1071 *pChildHandle,\r
1072 Status ));\r
1073 }\r
1074\r
1075 //\r
1076 // Release the socket if necessary\r
1077 //\r
1078 if ( EFI_ERROR ( Status )) {\r
1079 gBS->FreePool ( pSocket );\r
1080 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
1081 "0x%08x: Free pSocket, %d bytes\r\n",\r
1082 pSocket,\r
1083 sizeof ( *pSocket )));\r
1084 pSocket = NULL;\r
1085 }\r
1086 }\r
1087 else {\r
1088 Status = EFI_OUT_OF_RESOURCES;\r
1089 }\r
1090\r
1091 //\r
1092 // Return the operation status\r
1093 //\r
1094 DBG_EXIT_STATUS ( Status );\r
1095 return Status;\r
1096}\r
1097\r
1098\r
1099/**\r
1100 Bind a name to a socket.\r
1101\r
1102 This routine calls the network specific layer to save the network\r
1103 address of the local connection point.\r
1104\r
1105 The ::bind routine calls this routine to connect a name\r
1106 (network address and port) to a socket on the local machine.\r
1107\r
1108 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
1109\r
1110 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
1111 connection point on the local machine. An IPv4 address\r
1112 of INADDR_ANY specifies that the connection is made to\r
1113 all of the network stacks on the platform. Specifying a\r
1114 specific IPv4 address restricts the connection to the\r
1115 network stack supporting that address. Specifying zero\r
1116 for the port causes the network layer to assign a port\r
1117 number from the dynamic range. Specifying a specific\r
1118 port number causes the network layer to use that port.\r
1119\r
1120 @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.\r
1121\r
1122 @param [out] pErrno Address to receive the errno value upon completion.\r
1123\r
1124 @retval EFI_SUCCESS - Socket successfully created\r
1125\r
1126 **/\r
1127EFI_STATUS\r
1128EslSocketBind (\r
1129 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1130 IN CONST struct sockaddr * pSockAddr,\r
1131 IN socklen_t SockAddrLength,\r
1132 OUT int * pErrno\r
1133 )\r
1134{\r
1135 EFI_HANDLE ChildHandle;\r
1136 UINT8 * pBuffer;\r
1137 ESL_PORT * pPort;\r
1138 ESL_SERVICE ** ppServiceListHead;\r
1139 ESL_SOCKET * pSocket;\r
1140 ESL_SERVICE * pService;\r
1141 EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
1142 EFI_STATUS Status;\r
1143 EFI_TPL TplPrevious;\r
1144\r
1145 DBG_ENTER ( );\r
1146\r
1147 //\r
1148 // Assume success\r
1149 //\r
1150 Status = EFI_SUCCESS;\r
1151\r
1152 //\r
1153 // Validate the socket\r
1154 //\r
1155 pSocket = NULL;\r
1156 if ( NULL != pSocketProtocol ) {\r
1157 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1158\r
1159 //\r
1160 // Validate the structure pointer\r
1161 //\r
1162 pSocket->errno = 0;\r
1163 if ( NULL == pSockAddr ) {\r
1164 DEBUG (( DEBUG_BIND,\r
1165 "ERROR - pSockAddr is NULL!\r\n" ));\r
1166 Status = EFI_INVALID_PARAMETER;\r
1167 pSocket->errno = EFAULT;\r
1168 }\r
1169\r
1170 //\r
1171 // Validate the local address length\r
1172 //\r
1173 else if ( SockAddrLength < pSocket->pApi->MinimumAddressLength ) {\r
1174 DEBUG (( DEBUG_BIND,\r
1175 "ERROR - Invalid bind name length: %d\r\n",\r
1176 SockAddrLength ));\r
1177 Status = EFI_INVALID_PARAMETER;\r
1178 pSocket->errno = EINVAL;\r
1179 }\r
1180\r
1181 //\r
1182 // Validate the shutdown state\r
1183 //\r
1184 else if ( pSocket->bRxDisable || pSocket->bTxDisable ) {\r
1185 DEBUG (( DEBUG_BIND,\r
1186 "ERROR - Shutdown has been called on socket 0x%08x\r\n",\r
1187 pSocket ));\r
1188 pSocket->errno = EINVAL;\r
1189 Status = EFI_INVALID_PARAMETER;\r
1190 }\r
1191\r
1192 //\r
1193 // Verify the socket state\r
1194 //\r
1195 else if ( SOCKET_STATE_NOT_CONFIGURED != pSocket->State ) {\r
1196 DEBUG (( DEBUG_BIND,\r
1197 "ERROR - The socket 0x%08x is already configured!\r\n",\r
1198 pSocket ));\r
1199 pSocket->errno = EINVAL;\r
1200 Status = EFI_ALREADY_STARTED;\r
1201 }\r
1202 else {\r
1203 //\r
1204 // Synchronize with the socket layer\r
1205 //\r
1206 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1207\r
1208 //\r
1209 // Assume no ports are available\r
1210 //\r
1211 pSocket->errno = EADDRNOTAVAIL;\r
1212 Status = EFI_INVALID_PARAMETER;\r
1213\r
1214 //\r
1215 // Walk the list of services\r
1216 //\r
1217 pBuffer = (UINT8 *)&mEslLayer;\r
1218 pBuffer = &pBuffer[ pSocket->pApi->ServiceListOffset ];\r
1219 ppServiceListHead = (ESL_SERVICE **)pBuffer;\r
1220 pService = *ppServiceListHead;\r
1221 while ( NULL != pService ) {\r
1222 //\r
1223 // Create the port\r
1224 //\r
1225 pServiceBinding = pService->pServiceBinding;\r
1226 ChildHandle = NULL;\r
1227 Status = pServiceBinding->CreateChild ( pServiceBinding,\r
1228 &ChildHandle );\r
1229 if ( !EFI_ERROR ( Status )) {\r
1230 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
1231 "0x%08x: %s port handle created\r\n",\r
1232 ChildHandle,\r
1233 pService->pSocketBinding->pName ));\r
1234\r
1235 //\r
1236 // Open the port\r
1237 //\r
1238 Status = EslSocketPortAllocate ( pSocket,\r
1239 pService,\r
1240 ChildHandle,\r
1241 pSockAddr,\r
1242 TRUE,\r
1243 DEBUG_BIND,\r
1244 &pPort );\r
1245 }\r
1246 else {\r
1247 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
1248 "ERROR - Failed to open %s port handle, Status: %r\r\n",\r
1249 pService->pSocketBinding->pName,\r
1250 Status ));\r
1251 }\r
1252\r
1253 //\r
1254 // Set the next service\r
1255 //\r
1256 pService = pService->pNext;\r
1257 }\r
1258\r
1259 //\r
1260 // Verify that at least one network connection was found\r
1261 //\r
1262 if ( NULL != pSocket->pPortList ) {\r
1263 Status = EFI_SUCCESS;\r
1264 }\r
1265 else {\r
1266 if ( EADDRNOTAVAIL == pSocket->errno ) {\r
1267 DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
1268 "ERROR - Socket address is not available!\r\n" ));\r
1269 }\r
1270 if ( EADDRINUSE == pSocket->errno ) {\r
1271 DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
1272 "ERROR - Socket address is in use!\r\n" ));\r
1273 }\r
1274 Status = EFI_INVALID_PARAMETER;\r
1275 }\r
1276\r
1277 //\r
1278 // Mark this socket as bound if successful\r
1279 //\r
1280 if ( !EFI_ERROR ( Status )) {\r
1281 pSocket->State = SOCKET_STATE_BOUND;\r
1282 pSocket->errno = 0;\r
1283 }\r
1284\r
1285 //\r
1286 // Release the socket layer synchronization\r
1287 //\r
1288 RESTORE_TPL ( TplPrevious );\r
1289 }\r
1290 }\r
1291\r
1292 //\r
1293 // Return the operation status\r
1294 //\r
1295 if ( NULL != pErrno ) {\r
1296 if ( NULL != pSocket ) {\r
1297 *pErrno = pSocket->errno;\r
1298 }\r
1299 else {\r
1300 Status = EFI_INVALID_PARAMETER;\r
1301 *pErrno = ENOTSOCK;\r
1302 }\r
1303 }\r
1304 DBG_EXIT_STATUS ( Status );\r
1305 return Status;\r
1306}\r
1307\r
1308\r
1309/**\r
1310 Test the bind configuration.\r
1311\r
1312 @param [in] pPort Address of the ::ESL_PORT structure.\r
1313 @param [in] ErrnoValue errno value if test fails\r
1314\r
1315 @retval EFI_SUCCESS The connection was successfully established.\r
1316 @retval Others The connection attempt failed.\r
1317\r
1318 **/\r
1319EFI_STATUS\r
1320EslSocketBindTest (\r
1321 IN ESL_PORT * pPort,\r
1322 IN int ErrnoValue\r
1323 )\r
1324{\r
1325 UINT8 * pBuffer;\r
1326 VOID * pConfigData;\r
1327 EFI_STATUS Status;\r
1328\r
1329 DBG_ENTER ( );\r
1330\r
1331 //\r
1332 // Locate the configuration data\r
1333 //\r
1334 pBuffer = (UINT8 *)pPort;\r
1335 pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];\r
1336 pConfigData = (VOID *)pBuffer;\r
1337\r
1338 //\r
1339 // Attempt to use this configuration\r
1340 //\r
1341 Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );\r
1342 if ( EFI_ERROR ( Status )) {\r
1343 DEBUG (( DEBUG_WARN | DEBUG_BIND,\r
1344 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",\r
1345 pPort,\r
1346 Status ));\r
1347 pPort->pSocket->errno = ErrnoValue;\r
1348 }\r
1349 else {\r
1350 //\r
1351 // Reset the port\r
1352 //\r
1353 Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );\r
1354 if ( EFI_ERROR ( Status )) {\r
1355 DEBUG (( DEBUG_ERROR | DEBUG_BIND,\r
1356 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",\r
1357 pPort,\r
1358 Status ));\r
1359 ASSERT ( EFI_SUCCESS == Status );\r
1360 }\r
1361 }\r
1362\r
1363 //\r
1364 // Return the operation status\r
1365 //\r
1366 DBG_EXIT_STATUS ( Status );\r
1367 return Status;\r
1368}\r
1369\r
1370\r
1371/**\r
1372 Determine if the socket is closed\r
1373\r
1374 This routine checks the state of the socket to determine if\r
1375 the network specific layer has completed the close operation.\r
1376\r
1377 The ::close routine polls this routine to determine when the\r
1378 close operation is complete. The close operation needs to\r
1379 reverse the operations of the ::EslSocketAllocate routine.\r
1380\r
1381 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
1382 @param [out] pErrno Address to receive the errno value upon completion.\r
1383\r
1384 @retval EFI_SUCCESS Socket successfully closed\r
1385 @retval EFI_NOT_READY Close still in progress\r
1386 @retval EFI_ALREADY Close operation already in progress\r
1387 @retval Other Failed to close the socket\r
1388\r
1389**/\r
1390EFI_STATUS\r
1391EslSocketClosePoll (\r
1392 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1393 IN int * pErrno\r
1394 )\r
1395{\r
1396 int errno;\r
1397 ESL_LAYER * pLayer;\r
1398 ESL_SOCKET * pNextSocket;\r
1399 ESL_SOCKET * pSocket;\r
1400 EFI_STATUS Status;\r
1401 EFI_TPL TplPrevious;\r
1402\r
1403 DBG_ENTER ( );\r
1404\r
1405 //\r
1406 // Assume success\r
1407 //\r
1408 errno = 0;\r
1409 Status = EFI_SUCCESS;\r
1410\r
1411 //\r
1412 // Synchronize with the socket layer\r
1413 //\r
1414 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1415\r
1416 //\r
1417 // Locate the socket\r
1418 //\r
1419 pLayer = &mEslLayer;\r
1420 pNextSocket = pLayer->pSocketList;\r
1421 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1422 while ( NULL != pNextSocket ) {\r
1423 if ( pNextSocket == pSocket ) {\r
1424 //\r
1425 // Determine if the socket is in the closing state\r
1426 //\r
1427 if ( SOCKET_STATE_CLOSED == pSocket->State ) {\r
1428 //\r
1429 // Walk the list of ports\r
1430 //\r
1431 if ( NULL == pSocket->pPortList ) {\r
1432 //\r
1433 // All the ports are closed\r
1434 // Close the WaitAccept event if necessary\r
1435 //\r
1436 if ( NULL != pSocket->WaitAccept ) {\r
1437 Status = gBS->CloseEvent ( pSocket->WaitAccept );\r
1438 if ( !EFI_ERROR ( Status )) {\r
1439 DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
1440 "0x%08x: Closed WaitAccept event\r\n",\r
1441 pSocket->WaitAccept ));\r
1442 //\r
1443 // Return the transmit status\r
1444 //\r
1445 Status = pSocket->TxError;\r
1446 if ( EFI_ERROR ( Status )) {\r
1447 pSocket->errno = EIO;\r
1448 }\r
1449 }\r
1450 else {\r
1451 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
1452 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",\r
1453 Status ));\r
1454 ASSERT ( EFI_SUCCESS == Status );\r
1455 }\r
1456 }\r
1457 }\r
1458 else {\r
1459 //\r
1460 // At least one port is still open\r
1461 //\r
1462 Status = EFI_NOT_READY;\r
1463 errno = EAGAIN;\r
1464 }\r
1465 }\r
1466 else {\r
1467 //\r
1468 // SocketCloseStart was not called\r
1469 //\r
1470 Status = EFI_NOT_STARTED;\r
1471 errno = EPERM;\r
1472 }\r
1473 break;\r
1474 }\r
1475\r
1476 //\r
1477 // Set the next socket\r
1478 //\r
1479 pNextSocket = pNextSocket->pNext;\r
1480 }\r
1481\r
1482 //\r
1483 // Handle the error case where the socket was already closed\r
1484 //\r
1485 if ( NULL == pSocket ) {\r
1486 //\r
1487 // Socket not found\r
1488 //\r
1489 Status = EFI_NOT_FOUND;\r
1490 errno = ENOTSOCK;\r
1491 }\r
1492\r
1493 //\r
1494 // Release the socket layer synchronization\r
1495 //\r
1496 RESTORE_TPL ( TplPrevious );\r
1497\r
1498 //\r
1499 // Return the operation status\r
1500 //\r
1501 if ( NULL != pErrno ) {\r
1502 *pErrno = errno;\r
1503 }\r
1504 DBG_EXIT_STATUS ( Status );\r
1505 return Status;\r
1506}\r
1507\r
1508\r
1509/**\r
1510 Start the close operation on the socket\r
1511\r
1512 This routine calls the network specific layer to initiate the\r
1513 close state machine. This routine then calls the network\r
1514 specific layer to determine if the close state machine has gone\r
1515 to completion. The result from this poll is returned to the\r
1516 caller.\r
1517\r
1518 The ::close routine calls this routine to start the close\r
1519 operation which reverses the operations of the\r
1520 ::EslSocketAllocate routine. The close routine then polls\r
1521 the ::EslSocketClosePoll routine to determine when the\r
1522 socket is closed.\r
1523\r
1524 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
1525 @param [in] bCloseNow Boolean to control close behavior\r
1526 @param [out] pErrno Address to receive the errno value upon completion.\r
1527\r
1528 @retval EFI_SUCCESS Socket successfully closed\r
1529 @retval EFI_NOT_READY Close still in progress\r
1530 @retval EFI_ALREADY Close operation already in progress\r
1531 @retval Other Failed to close the socket\r
1532\r
1533**/\r
1534EFI_STATUS\r
1535EslSocketCloseStart (\r
1536 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1537 IN BOOLEAN bCloseNow,\r
1538 IN int * pErrno\r
1539 )\r
1540{\r
1541 int errno;\r
1542 ESL_PORT * pNextPort;\r
1543 ESL_PORT * pPort;\r
1544 ESL_SOCKET * pSocket;\r
1545 EFI_STATUS Status;\r
1546 EFI_TPL TplPrevious;\r
1547\r
1548 DBG_ENTER ( );\r
1549\r
1550 //\r
1551 // Assume success\r
1552 //\r
1553 Status = EFI_SUCCESS;\r
1554 errno = 0;\r
1555\r
1556 //\r
1557 // Synchronize with the socket layer\r
1558 //\r
1559 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1560\r
1561 //\r
1562 // Determine if the socket is already closed\r
1563 //\r
1564 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1565 if ( SOCKET_STATE_CLOSED > pSocket->State ) {\r
1566 //\r
1567 // Update the socket state\r
1568 //\r
1569 pSocket->State = SOCKET_STATE_CLOSED;\r
1570\r
1571 //\r
1572 // Walk the list of ports\r
1573 //\r
1574 pPort = pSocket->pPortList;\r
1575 while ( NULL != pPort ) {\r
1576 //\r
1577 // Start closing the ports\r
1578 //\r
1579 pNextPort = pPort->pLinkSocket;\r
1580 Status = EslSocketPortCloseStart ( pPort,\r
1581 bCloseNow,\r
1582 DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );\r
1583 if (( EFI_SUCCESS != Status )\r
1584 && ( EFI_NOT_READY != Status )) {\r
1585 errno = EIO;\r
1586 break;\r
1587 }\r
1588\r
1589 //\r
1590 // Set the next port\r
1591 //\r
1592 pPort = pNextPort;\r
1593 }\r
1594\r
1595 //\r
1596 // Attempt to finish closing the socket\r
1597 //\r
1598 if ( NULL == pPort ) {\r
1599 Status = EslSocketClosePoll ( pSocketProtocol, &errno );\r
1600 }\r
1601 }\r
1602 else {\r
1603 Status = EFI_NOT_READY;\r
1604 errno = EAGAIN;\r
1605 }\r
1606\r
1607 //\r
1608 // Release the socket layer synchronization\r
1609 //\r
1610 RESTORE_TPL ( TplPrevious );\r
1611\r
1612 //\r
1613 // Return the operation status\r
1614 //\r
1615 if ( NULL != pErrno ) {\r
1616 *pErrno = errno;\r
1617 }\r
1618 DBG_EXIT_STATUS ( Status );\r
1619 return Status;\r
1620}\r
1621\r
1622\r
1623/**\r
1624 Connect to a remote system via the network.\r
1625\r
1626 This routine calls the network specific layer to establish\r
1627 the remote system address and establish the connection to\r
1628 the remote system.\r
1629\r
1630 The ::connect routine calls this routine to establish a\r
1631 connection with the specified remote system. This routine\r
1632 is designed to be polled by the connect routine for completion\r
1633 of the network connection.\r
1634 \r
1635 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
1636\r
1637 @param [in] pSockAddr Network address of the remote system.\r
1638 \r
1639 @param [in] SockAddrLength Length in bytes of the network address.\r
1640 \r
1641 @param [out] pErrno Address to receive the errno value upon completion.\r
1642 \r
1643 @retval EFI_SUCCESS The connection was successfully established.\r
1644 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
1645 @retval Others The connection attempt failed.\r
1646\r
1647 **/\r
1648EFI_STATUS\r
1649EslSocketConnect (\r
1650 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1651 IN const struct sockaddr * pSockAddr,\r
1652 IN socklen_t SockAddrLength,\r
1653 IN int * pErrno\r
1654 )\r
1655{\r
1656 struct sockaddr_in6 LocalAddress;\r
1657 ESL_PORT * pPort;\r
1658 ESL_SOCKET * pSocket;\r
1659 EFI_STATUS Status;\r
1660 EFI_TPL TplPrevious;\r
1661 \r
1662 DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));\r
1663\r
1664 //\r
1665 // Assume success\r
1666 //\r
1667 Status = EFI_SUCCESS;\r
1668\r
1669 //\r
1670 // Validate the socket\r
1671 //\r
1672 pSocket = NULL;\r
1673 if ( NULL != pSocketProtocol ) {\r
1674 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1675\r
1676 //\r
1677 // Validate the name length\r
1678 //\r
1679 if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {\r
1680 DEBUG (( DEBUG_CONNECT,\r
1681 "ERROR - Invalid bind name length: %d\r\n",\r
1682 SockAddrLength ));\r
1683 Status = EFI_INVALID_PARAMETER;\r
1684 pSocket->errno = EINVAL;\r
1685 }\r
1686 else {\r
1687 //\r
1688 // Assume success\r
1689 //\r
1690 pSocket->errno = 0;\r
1691\r
1692 //\r
1693 // Synchronize with the socket layer\r
1694 //\r
1695 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1696\r
1697 //\r
1698 // Validate the socket state\r
1699 //\r
1700 switch ( pSocket->State ) {\r
1701 default:\r
1702 //\r
1703 // Wrong socket state\r
1704 //\r
1705 pSocket->errno = EIO;\r
1706 Status = EFI_DEVICE_ERROR;\r
1707 break;\r
1708\r
1709 case SOCKET_STATE_NOT_CONFIGURED:\r
1710 case SOCKET_STATE_BOUND:\r
1711 //\r
1712 // Validate the address length\r
1713 //\r
1714 if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {\r
1715 //\r
1716 // Verify the API\r
1717 //\r
1718 if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {\r
1719 //\r
1720 // Already connected\r
1721 //\r
1722 pSocket->errno = ENOTSUP;\r
1723 Status = EFI_UNSUPPORTED;\r
1724 }\r
1725 else {\r
1726 //\r
1727 // Determine if BIND was already called\r
1728 //\r
1729 if ( NULL == pSocket->pPortList ) {\r
1730 //\r
1731 // Allow any local port\r
1732 //\r
1733 ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
1734 LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;\r
1735 LocalAddress.sin6_family = pSocket->pApi->AddressFamily;\r
1736 Status = EslSocketBind ( &pSocket->SocketProtocol,\r
1737 (struct sockaddr *)&LocalAddress,\r
1738 LocalAddress.sin6_len,\r
1739 &pSocket->errno );\r
1740 }\r
1741 if ( NULL != pSocket->pPortList ) {\r
1742 //\r
1743 // Walk the list of ports\r
1744 //\r
1745 pPort = pSocket->pPortList;\r
1746 while ( NULL != pPort ) {\r
1747 //\r
1748 // Set the remote address\r
1749 //\r
1750 Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,\r
1751 pSockAddr,\r
1752 SockAddrLength );\r
1753 if ( EFI_ERROR ( Status )) {\r
1754 break;\r
1755 }\r
1756\r
1757 //\r
1758 // Set the next port\r
1759 //\r
1760 pPort = pPort->pLinkSocket;\r
1761 }\r
1762\r
1763 //\r
1764 // Verify the API\r
1765 //\r
1766 if (( !EFI_ERROR ( Status ))\r
1767 && ( NULL != pSocket->pApi->pfnConnectStart )) {\r
1768 //\r
1769 // Initiate the connection with the remote system\r
1770 //\r
1771 Status = pSocket->pApi->pfnConnectStart ( pSocket );\r
1772\r
1773 //\r
1774 // Set the next state if connecting\r
1775 //\r
1776 if ( EFI_NOT_READY == Status ) {\r
1777 pSocket->State = SOCKET_STATE_CONNECTING;\r
1778 }\r
1779 }\r
1780 }\r
1781 }\r
1782 }\r
1783 else {\r
1784 DEBUG (( DEBUG_CONNECT,\r
1785 "ERROR - Invalid address length: %d\r\n",\r
1786 SockAddrLength ));\r
1787 Status = EFI_INVALID_PARAMETER;\r
1788 pSocket->errno = EINVAL;\r
1789 }\r
1790 break;\r
1791\r
1792 case SOCKET_STATE_CONNECTING:\r
1793 //\r
1794 // Poll the network adapter\r
1795 //\r
1796 EslSocketRxPoll ( pSocket );\r
1797\r
1798 //\r
1799 // Poll for connection completion\r
1800 //\r
1801 if ( NULL == pSocket->pApi->pfnConnectPoll ) {\r
1802 //\r
1803 // Already connected\r
1804 //\r
1805 pSocket->errno = EISCONN;\r
1806 Status = EFI_ALREADY_STARTED;\r
1807 }\r
1808 else {\r
1809 Status = pSocket->pApi->pfnConnectPoll ( pSocket );\r
1810\r
1811 //\r
1812 // Set the next state if connected\r
1813 //\r
1814 if ( EFI_NOT_READY != Status ) {\r
1815 if ( !EFI_ERROR ( Status )) {\r
1816 pSocket->State = SOCKET_STATE_CONNECTED;\r
1817\r
1818 //\r
1819 // Start the receive operations\r
1820 //\r
1821 EslSocketRxStart ( pSocket->pPortList );\r
1822 }\r
1823 else {\r
1824 pSocket->State = SOCKET_STATE_BOUND;\r
1825 }\r
1826 }\r
1827 }\r
1828 break;\r
1829\r
1830 case SOCKET_STATE_CONNECTED:\r
1831 //\r
1832 // Already connected\r
1833 //\r
1834 pSocket->errno = EISCONN;\r
1835 Status = EFI_ALREADY_STARTED;\r
1836 break;\r
1837 }\r
1838\r
1839 //\r
1840 // Release the socket layer synchronization\r
1841 //\r
1842 RESTORE_TPL ( TplPrevious );\r
1843 }\r
1844 }\r
1845\r
1846 //\r
1847 // Return the operation status\r
1848 //\r
1849 if ( NULL != pErrno ) {\r
1850 if ( NULL != pSocket ) {\r
1851 *pErrno = pSocket->errno;\r
1852 }\r
1853 else {\r
1854 //\r
1855 // Bad socket protocol\r
1856 //\r
1857 DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,\r
1858 "ERROR - pSocketProtocol invalid!\r\n" ));\r
1859 Status = EFI_INVALID_PARAMETER;\r
1860 *pErrno = ENOTSOCK;\r
1861 }\r
1862 }\r
1863\r
1864 //\r
1865 // Return the operation status\r
1866 //\r
1867 DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));\r
1868 return Status;\r
1869}\r
1870\r
1871\r
1872/**\r
1873 Copy a fragmented buffer into a destination buffer.\r
1874\r
1875 This support routine copies a fragmented buffer to the caller specified buffer.\r
1876\r
1877 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.\r
1878\r
1879 @param [in] FragmentCount Number of fragments in the table\r
1880\r
1881 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure\r
1882\r
1883 @param [in] BufferLength Length of the the buffer\r
1884\r
1885 @param [in] pBuffer Address of a buffer to receive the data.\r
1886\r
1887 @param [in] pDataLength Number of received data bytes in the buffer.\r
1888\r
1889 @return Returns the address of the next free byte in the buffer.\r
1890\r
1891**/\r
1892UINT8 *\r
1893EslSocketCopyFragmentedBuffer (\r
1894 IN UINT32 FragmentCount,\r
1895 IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,\r
1896 IN size_t BufferLength,\r
1897 IN UINT8 * pBuffer,\r
1898 OUT size_t * pDataLength\r
1899 )\r
1900{\r
1901 size_t BytesToCopy;\r
1902 UINT32 Fragment;\r
1903 UINT8 * pBufferEnd;\r
1904 UINT8 * pData;\r
1905\r
1906 DBG_ENTER ( );\r
1907\r
1908 //\r
1909 // Validate the IP and UDP structures are identical\r
1910 //\r
1911 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )\r
1912 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));\r
1913 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )\r
1914 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));\r
1915\r
1916 //\r
1917 // Copy the received data\r
1918 //\r
1919 Fragment = 0;\r
1920 pBufferEnd = &pBuffer [ BufferLength ];\r
1921 while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {\r
1922 //\r
1923 // Determine the amount of received data\r
1924 //\r
1925 pData = pFragmentTable[Fragment].FragmentBuffer;\r
1926 BytesToCopy = pFragmentTable[Fragment].FragmentLength;\r
1927 if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {\r
1928 BytesToCopy = pBufferEnd - pBuffer;\r
1929 }\r
1930\r
1931 //\r
1932 // Move the data into the buffer\r
1933 //\r
1934 DEBUG (( DEBUG_RX,\r
1935 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",\r
1936 pData,\r
1937 pBuffer,\r
1938 BytesToCopy ));\r
1939 CopyMem ( pBuffer, pData, BytesToCopy );\r
1940 pBuffer += BytesToCopy;\r
1941 Fragment += 1;\r
1942 }\r
1943\r
1944 //\r
1945 // Return the data length and the buffer address\r
1946 //\r
1947 *pDataLength = BufferLength - ( pBufferEnd - pBuffer );\r
1948 DBG_EXIT_HEX ( pBuffer );\r
1949 return pBuffer;\r
1950}\r
1951\r
1952\r
1953/**\r
1954 Free the socket.\r
1955\r
1956 This routine frees the socket structure and handle resources.\r
1957\r
1958 The ::close routine calls EslServiceFreeProtocol which then calls\r
1959 this routine to free the socket context structure and close the\r
1960 handle.\r
1961\r
1962 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
1963 \r
1964 @param [out] pErrno Address to receive the errno value upon completion.\r
1965\r
1966 @retval EFI_SUCCESS The socket resources were returned successfully.\r
1967\r
1968 **/\r
1969EFI_STATUS\r
1970EslSocketFree (\r
1971 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1972 IN int * pErrno\r
1973 )\r
1974{\r
1975 EFI_HANDLE ChildHandle;\r
1976 int errno;\r
1977 ESL_LAYER * pLayer;\r
1978 ESL_SOCKET * pSocket;\r
1979 ESL_SOCKET * pSocketPrevious;\r
1980 EFI_STATUS Status;\r
1981 EFI_TPL TplPrevious;\r
1982\r
1983 DBG_ENTER ( );\r
1984\r
1985 //\r
1986 // Assume failure\r
1987 //\r
1988 errno = EIO;\r
1989 pSocket = NULL;\r
1990 Status = EFI_INVALID_PARAMETER;\r
1991\r
1992 //\r
1993 // Validate the socket\r
1994 //\r
1995 pLayer = &mEslLayer;\r
1996 if ( NULL != pSocketProtocol ) {\r
1997 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1998\r
1999 //\r
2000 // Synchronize with the socket layer\r
2001 //\r
2002 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2003\r
2004 //\r
2005 // Walk the socket list\r
2006 //\r
2007 pSocketPrevious = pLayer->pSocketList;\r
2008 if ( NULL != pSocketPrevious ) {\r
2009 if ( pSocket == pSocketPrevious ) {\r
2010 //\r
2011 // Remove the socket from the head of the list\r
2012 //\r
2013 pLayer->pSocketList = pSocket->pNext;\r
2014 }\r
2015 else {\r
2016 //\r
2017 // Find the socket in the middle of the list\r
2018 //\r
2019 while (( NULL != pSocketPrevious )\r
2020 && ( pSocket != pSocketPrevious->pNext )) {\r
2021 //\r
2022 // Set the next socket\r
2023 //\r
2024 pSocketPrevious = pSocketPrevious->pNext;\r
2025 }\r
2026 if ( NULL != pSocketPrevious ) {\r
2027 //\r
2028 // Remove the socket from the middle of the list\r
2029 //\r
2030 pSocketPrevious = pSocket->pNext;\r
2031 }\r
2032 }\r
2033 }\r
2034 else {\r
2035 DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
2036 "ERROR - Socket list is empty!\r\n" ));\r
2037 }\r
2038\r
2039 //\r
2040 // Release the socket layer synchronization\r
2041 //\r
2042 RESTORE_TPL ( TplPrevious );\r
2043\r
2044 //\r
2045 // Determine if the socket was found\r
2046 //\r
2047 if ( NULL != pSocketPrevious ) {\r
2048 pSocket->pNext = NULL;\r
2049\r
2050 //\r
2051 // Remove the socket protocol\r
2052 //\r
2053 ChildHandle = pSocket->SocketProtocol.SocketHandle;\r
2054 Status = gBS->UninstallMultipleProtocolInterfaces (\r
2055 ChildHandle,\r
2056 &gEfiSocketProtocolGuid,\r
2057 &pSocket->SocketProtocol,\r
2058 NULL );\r
2059 if ( !EFI_ERROR ( Status )) {\r
2060 DEBUG (( DEBUG_POOL | DEBUG_INFO,\r
2061 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",\r
2062 ChildHandle ));\r
2063\r
2064 //\r
2065 // Free the socket structure\r
2066 //\r
2067 Status = gBS->FreePool ( pSocket );\r
2068 if ( !EFI_ERROR ( Status )) {\r
2069 DEBUG (( DEBUG_POOL,\r
2070 "0x%08x: Free pSocket, %d bytes\r\n",\r
2071 pSocket,\r
2072 sizeof ( *pSocket )));\r
2073 errno = 0;\r
2074 }\r
2075 else {\r
2076 DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
2077 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",\r
2078 pSocket,\r
2079 Status ));\r
2080 }\r
2081 }\r
2082 else {\r
2083 DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,\r
2084 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",\r
2085 ChildHandle,\r
2086 Status ));\r
2087 }\r
2088 }\r
2089 else {\r
2090 DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
2091 "ERROR - The socket was not in the socket list!\r\n" ));\r
2092 Status = EFI_NOT_FOUND;\r
2093 }\r
2094 }\r
2095 else {\r
2096 DEBUG (( DEBUG_ERROR,\r
2097 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));\r
2098 }\r
2099\r
2100 //\r
2101 // Return the errno value if possible\r
2102 //\r
2103 if ( NULL != pErrno ) {\r
2104 *pErrno = errno;\r
2105 }\r
2106\r
2107 //\r
2108 // Return the operation status\r
2109 //\r
2110 DBG_EXIT_STATUS ( Status );\r
2111 return Status;\r
2112}\r
2113\r
2114\r
2115/**\r
2116 Get the local address.\r
2117\r
2118 This routine calls the network specific layer to get the network\r
2119 address of the local host connection point.\r
2120\r
2121 The ::getsockname routine calls this routine to obtain the network\r
2122 address associated with the local host connection point.\r
2123\r
2124 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
2125 \r
2126 @param [out] pAddress Network address to receive the local system address\r
2127\r
2128 @param [in,out] pAddressLength Length of the local network address structure\r
2129\r
2130 @param [out] pErrno Address to receive the errno value upon completion.\r
2131\r
2132 @retval EFI_SUCCESS - Local address successfully returned\r
2133\r
2134 **/\r
2135EFI_STATUS\r
2136EslSocketGetLocalAddress (\r
2137 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2138 OUT struct sockaddr * pAddress,\r
2139 IN OUT socklen_t * pAddressLength,\r
2140 IN int * pErrno\r
2141 )\r
2142{\r
2143 socklen_t LengthInBytes;\r
2144 ESL_PORT * pPort;\r
2145 ESL_SOCKET * pSocket;\r
2146 EFI_STATUS Status;\r
2147 EFI_TPL TplPrevious;\r
2148 \r
2149 DBG_ENTER ( );\r
2150 \r
2151 //\r
2152 // Assume success\r
2153 //\r
2154 Status = EFI_SUCCESS;\r
2155 \r
2156 //\r
2157 // Validate the socket\r
2158 //\r
2159 pSocket = NULL;\r
2160 if ( NULL != pSocketProtocol ) {\r
2161 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2162\r
2163 //\r
2164 // Verify the socket state\r
2165 //\r
2166 EslSocketIsConfigured ( pSocket );\r
2167 if ( pSocket->bAddressSet ) {\r
2168 //\r
2169 // Verify the address buffer and length address\r
2170 //\r
2171 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
2172 //\r
2173 // Verify the API\r
2174 //\r
2175 if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {\r
2176 Status = EFI_UNSUPPORTED;\r
2177 pSocket->errno = ENOTSUP;\r
2178 }\r
2179 else {\r
2180 //\r
2181 // Synchronize with the socket layer\r
2182 //\r
2183 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2184\r
2185 //\r
2186 // Verify that there is just a single connection\r
2187 //\r
2188 pPort = pSocket->pPortList;\r
2189 if ( NULL != pPort ) {\r
2190 //\r
2191 // Verify the address length\r
2192 //\r
2193 LengthInBytes = pSocket->pApi->AddressLength;\r
2194 if (( LengthInBytes <= *pAddressLength ) \r
2195 && ( 255 >= LengthInBytes )) {\r
2196 //\r
2197 // Return the local address and address length\r
2198 //\r
2199 ZeroMem ( pAddress, LengthInBytes );\r
2200 pAddress->sa_len = (uint8_t)LengthInBytes;\r
2201 *pAddressLength = pAddress->sa_len;\r
2202 pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );\r
2203 pSocket->errno = 0;\r
2204 Status = EFI_SUCCESS;\r
2205 }\r
2206 else {\r
2207 pSocket->errno = EINVAL;\r
2208 Status = EFI_INVALID_PARAMETER;\r
2209 }\r
2210 }\r
2211 else {\r
2212 pSocket->errno = ENOTCONN;\r
2213 Status = EFI_NOT_STARTED;\r
2214 }\r
2215 \r
2216 //\r
2217 // Release the socket layer synchronization\r
2218 //\r
2219 RESTORE_TPL ( TplPrevious );\r
2220 }\r
2221 }\r
2222 else {\r
2223 pSocket->errno = EINVAL;\r
2224 Status = EFI_INVALID_PARAMETER;\r
2225 }\r
2226 }\r
2227 else {\r
2228 //\r
2229 // Address not set\r
2230 //\r
2231 Status = EFI_NOT_STARTED;\r
2232 pSocket->errno = EADDRNOTAVAIL;\r
2233 }\r
2234 }\r
2235 \r
2236 //\r
2237 // Return the operation status\r
2238 //\r
2239 if ( NULL != pErrno ) {\r
2240 if ( NULL != pSocket ) {\r
2241 *pErrno = pSocket->errno;\r
2242 }\r
2243 else {\r
2244 Status = EFI_INVALID_PARAMETER;\r
2245 *pErrno = ENOTSOCK;\r
2246 }\r
2247 }\r
2248 DBG_EXIT_STATUS ( Status );\r
2249 return Status;\r
2250}\r
2251\r
2252\r
2253/**\r
2254 Get the peer address.\r
2255\r
2256 This routine calls the network specific layer to get the remote\r
2257 system connection point.\r
2258\r
2259 The ::getpeername routine calls this routine to obtain the network\r
2260 address of the remote connection point.\r
2261\r
2262 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
2263 \r
2264 @param [out] pAddress Network address to receive the remote system address\r
2265\r
2266 @param [in,out] pAddressLength Length of the remote network address structure\r
2267\r
2268 @param [out] pErrno Address to receive the errno value upon completion.\r
2269\r
2270 @retval EFI_SUCCESS - Remote address successfully returned\r
2271\r
2272 **/\r
2273EFI_STATUS\r
2274EslSocketGetPeerAddress (\r
2275 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2276 OUT struct sockaddr * pAddress,\r
2277 IN OUT socklen_t * pAddressLength,\r
2278 IN int * pErrno\r
2279 )\r
2280{\r
2281 socklen_t LengthInBytes;\r
2282 ESL_PORT * pPort;\r
2283 ESL_SOCKET * pSocket;\r
2284 EFI_STATUS Status;\r
2285 EFI_TPL TplPrevious;\r
2286 \r
2287 DBG_ENTER ( );\r
2288 \r
2289 //\r
2290 // Assume success\r
2291 //\r
2292 Status = EFI_SUCCESS;\r
2293 \r
2294 //\r
2295 // Validate the socket\r
2296 //\r
2297 pSocket = NULL;\r
2298 if ( NULL != pSocketProtocol ) {\r
2299 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2300\r
2301 //\r
2302 // Verify the socket state\r
2303 //\r
2304 Status = EslSocketIsConfigured ( pSocket );\r
2305 if ( !EFI_ERROR ( Status )) {\r
2306 //\r
2307 // Verify the API\r
2308 //\r
2309 if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {\r
2310 Status = EFI_UNSUPPORTED;\r
2311 pSocket->errno = ENOTSUP;\r
2312 }\r
2313 else {\r
2314 //\r
2315 // Verify the address buffer and length address\r
2316 //\r
2317 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
2318 //\r
2319 // Verify the socket state\r
2320 //\r
2321 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
2322 //\r
2323 // Synchronize with the socket layer\r
2324 //\r
2325 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2326\r
2327 //\r
2328 // Verify that there is just a single connection\r
2329 //\r
2330 pPort = pSocket->pPortList;\r
2331 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
2332 //\r
2333 // Verify the address length\r
2334 //\r
2335 LengthInBytes = pSocket->pApi->AddressLength;\r
2336 if ( LengthInBytes <= *pAddressLength ) {\r
2337 //\r
2338 // Return the local address\r
2339 //\r
2340 ZeroMem ( pAddress, LengthInBytes );\r
2341 pAddress->sa_len = (uint8_t)LengthInBytes;\r
2342 *pAddressLength = pAddress->sa_len;\r
2343 pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );\r
2344 pSocket->errno = 0;\r
2345 Status = EFI_SUCCESS;\r
2346 }\r
2347 else {\r
2348 pSocket->errno = EINVAL;\r
2349 Status = EFI_INVALID_PARAMETER;\r
2350 }\r
2351 }\r
2352 else {\r
2353 pSocket->errno = ENOTCONN;\r
2354 Status = EFI_NOT_STARTED;\r
2355 }\r
2356\r
2357 //\r
2358 // Release the socket layer synchronization\r
2359 //\r
2360 RESTORE_TPL ( TplPrevious );\r
2361 }\r
2362 else {\r
2363 pSocket->errno = ENOTCONN;\r
2364 Status = EFI_NOT_STARTED;\r
2365 }\r
2366 }\r
2367 else {\r
2368 pSocket->errno = EINVAL;\r
2369 Status = EFI_INVALID_PARAMETER;\r
2370 }\r
2371 }\r
2372 }\r
2373 }\r
2374\r
2375 //\r
2376 // Return the operation status\r
2377 //\r
2378 if ( NULL != pErrno ) {\r
2379 if ( NULL != pSocket ) {\r
2380 *pErrno = pSocket->errno;\r
2381 }\r
2382 else {\r
2383 Status = EFI_INVALID_PARAMETER;\r
2384 *pErrno = ENOTSOCK;\r
2385 }\r
2386 }\r
2387 DBG_EXIT_STATUS ( Status );\r
2388 return Status;\r
2389}\r
2390\r
2391\r
2392/**\r
2393 Free the ESL_IO_MGMT event and structure\r
2394\r
2395 This support routine walks the free list to close the event in\r
2396 the ESL_IO_MGMT structure and remove the structure from the free\r
2397 list.\r
2398\r
2399 See the \ref TransmitEngine section.\r
2400\r
2401 @param [in] pPort Address of an ::ESL_PORT structure\r
2402 @param [in] ppFreeQueue Address of the free queue head\r
2403 @param [in] DebugFlags Flags for debug messages\r
2404 @param [in] pEventName Zero terminated string containing the event name\r
2405\r
2406 @retval EFI_SUCCESS - The structures were properly initialized\r
2407\r
2408**/\r
2409EFI_STATUS\r
2410EslSocketIoFree (\r
2411 IN ESL_PORT * pPort,\r
2412 IN ESL_IO_MGMT ** ppFreeQueue,\r
2413 IN UINTN DebugFlags,\r
2414 IN CHAR8 * pEventName\r
2415 )\r
2416{\r
2417 UINT8 * pBuffer;\r
2418 EFI_EVENT * pEvent;\r
2419 ESL_IO_MGMT * pIo;\r
2420 ESL_SOCKET * pSocket;\r
2421 EFI_STATUS Status;\r
2422\r
2423 DBG_ENTER ( );\r
2424\r
2425 //\r
2426 // Assume success\r
2427 //\r
2428 Status = EFI_SUCCESS;\r
2429\r
2430 //\r
2431 // Walk the list of IO structures\r
2432 //\r
2433 pSocket = pPort->pSocket;\r
2434 while ( *ppFreeQueue ) {\r
2435 //\r
2436 // Free the event for this structure\r
2437 //\r
2438 pIo = *ppFreeQueue;\r
2439 pBuffer = (UINT8 *)pIo;\r
2440 pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];\r
2441 pEvent = (EFI_EVENT *)pBuffer;\r
2442 Status = gBS->CloseEvent ( *pEvent );\r
2443 if ( EFI_ERROR ( Status )) {\r
2444 DEBUG (( DEBUG_ERROR | DebugFlags,\r
2445 "ERROR - Failed to close the %a event, Status: %r\r\n",\r
2446 pEventName,\r
2447 Status ));\r
2448 pSocket->errno = ENOMEM;\r
2449 break;\r
2450 }\r
2451 DEBUG (( DebugFlags,\r
2452 "0x%08x: Closed %a event 0x%08x\r\n",\r
2453 pIo,\r
2454 pEventName,\r
2455 *pEvent ));\r
2456\r
2457 //\r
2458 // Remove this structure from the queue\r
2459 //\r
2460 *ppFreeQueue = pIo->pNext;\r
2461 }\r
2462\r
2463 //\r
2464 // Return the operation status\r
2465 //\r
2466 DBG_EXIT_STATUS ( Status );\r
2467 return Status;\r
2468}\r
2469\r
2470\r
2471/**\r
2472 Initialize the ESL_IO_MGMT structures\r
2473\r
2474 This support routine initializes the ESL_IO_MGMT structure and\r
2475 places them on to a free list.\r
2476\r
2477 This routine is called by ::EslSocketPortAllocate routines to prepare\r
2478 the transmit engines. See the \ref TransmitEngine section.\r
2479\r
2480 @param [in] pPort Address of an ::ESL_PORT structure\r
2481 @param [in, out] ppIo Address containing the first structure address. Upon\r
2482 return this buffer contains the next structure address.\r
2483 @param [in] TokenCount Number of structures to initialize\r
2484 @param [in] ppFreeQueue Address of the free queue head\r
2485 @param [in] DebugFlags Flags for debug messages\r
2486 @param [in] pEventName Zero terminated string containing the event name\r
2487 @param [in] pfnCompletion Completion routine address\r
2488\r
2489 @retval EFI_SUCCESS - The structures were properly initialized\r
2490\r
2491**/\r
2492EFI_STATUS\r
2493EslSocketIoInit (\r
2494 IN ESL_PORT * pPort,\r
2495 IN ESL_IO_MGMT ** ppIo,\r
2496 IN UINTN TokenCount,\r
2497 IN ESL_IO_MGMT ** ppFreeQueue,\r
2498 IN UINTN DebugFlags,\r
2499 IN CHAR8 * pEventName,\r
2500 IN PFN_API_IO_COMPLETE pfnCompletion\r
2501 )\r
2502{\r
2503 ESL_IO_MGMT * pEnd;\r
2504 EFI_EVENT * pEvent;\r
2505 ESL_IO_MGMT * pIo;\r
2506 ESL_SOCKET * pSocket;\r
2507 EFI_STATUS Status;\r
2508\r
2509 DBG_ENTER ( );\r
2510\r
2511 //\r
2512 // Assume success\r
2513 //\r
2514 Status = EFI_SUCCESS;\r
2515\r
2516 //\r
2517 // Walk the list of IO structures\r
2518 //\r
2519 pSocket = pPort->pSocket;\r
2520 pIo = *ppIo;\r
2521 pEnd = &pIo [ TokenCount ];\r
2522 while ( pEnd > pIo ) {\r
2523 //\r
2524 // Initialize the IO structure\r
2525 //\r
2526 pIo->pPort = pPort;\r
2527 pIo->pPacket = NULL;\r
2528\r
2529 //\r
2530 // Allocate the event for this structure\r
2531 //\r
2532 pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);\r
2533 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
2534 TPL_SOCKETS,\r
2535 (EFI_EVENT_NOTIFY)pfnCompletion,\r
2536 pIo,\r
2537 pEvent );\r
2538 if ( EFI_ERROR ( Status )) {\r
2539 DEBUG (( DEBUG_ERROR | DebugFlags,\r
2540 "ERROR - Failed to create the %a event, Status: %r\r\n",\r
2541 pEventName,\r
2542 Status ));\r
2543 pSocket->errno = ENOMEM;\r
2544 break;\r
2545 }\r
2546 DEBUG (( DebugFlags,\r
2547 "0x%08x: Created %a event 0x%08x\r\n",\r
2548 pIo,\r
2549 pEventName,\r
2550 *pEvent ));\r
2551\r
2552 //\r
2553 // Add this structure to the queue\r
2554 //\r
2555 pIo->pNext = *ppFreeQueue;\r
2556 *ppFreeQueue = pIo;\r
2557\r
2558 //\r
2559 // Set the next structure\r
2560 //\r
2561 pIo += 1;\r
2562 }\r
2563\r
2564 //\r
2565 // Save the next structure\r
2566 //\r
2567 *ppIo = pIo;\r
2568\r
2569 //\r
2570 // Return the operation status\r
2571 //\r
2572 DBG_EXIT_STATUS ( Status );\r
2573 return Status;\r
2574}\r
2575\r
2576\r
2577/**\r
2578 Determine if the socket is configured\r
2579\r
2580 This support routine is called to determine if the socket if the\r
2581 configuration call was made to the network layer. The following\r
2582 routines call this routine to verify that they may be successful\r
2583 in their operations:\r
2584 <ul>\r
2585 <li>::EslSocketGetLocalAddress</li>\r
2586 <li>::EslSocketGetPeerAddress</li>\r
2587 <li>::EslSocketPoll</li>\r
2588 <li>::EslSocketReceive</li>\r
2589 <li>::EslSocketTransmit</li>\r
2590 </ul>\r
2591\r
2592 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
2593\r
2594 @retval EFI_SUCCESS - The socket is configured\r
2595\r
2596**/\r
2597EFI_STATUS\r
2598EslSocketIsConfigured (\r
2599 IN ESL_SOCKET * pSocket\r
2600 )\r
2601{\r
2602 EFI_STATUS Status;\r
2603 EFI_TPL TplPrevious;\r
2604\r
2605 //\r
2606 // Assume success\r
2607 //\r
2608 Status = EFI_SUCCESS;\r
2609\r
2610 //\r
2611 // Verify the socket state\r
2612 //\r
2613 if ( !pSocket->bConfigured ) {\r
2614 DBG_ENTER ( );\r
2615\r
2616 //\r
2617 // Verify the API\r
2618 //\r
2619 if ( NULL == pSocket->pApi->pfnIsConfigured ) {\r
2620 Status = EFI_UNSUPPORTED;\r
2621 pSocket->errno = ENOTSUP;\r
2622 }\r
2623 else {\r
2624 //\r
2625 // Synchronize with the socket layer\r
2626 //\r
2627 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2628\r
2629 //\r
2630 // Determine if the socket is configured\r
2631 //\r
2632 Status = pSocket->pApi->pfnIsConfigured ( pSocket );\r
2633\r
2634 //\r
2635 // Release the socket layer synchronization\r
2636 //\r
2637 RESTORE_TPL ( TplPrevious );\r
2638\r
2639 //\r
2640 // Set errno if a failure occurs\r
2641 //\r
2642 if ( EFI_ERROR ( Status )) {\r
2643 pSocket->errno = EADDRNOTAVAIL;\r
2644 }\r
2645 }\r
2646\r
2647 DBG_EXIT_STATUS ( Status );\r
2648 }\r
2649\r
2650 //\r
2651 // Return the configuration status\r
2652 //\r
2653 return Status;\r
2654}\r
2655\r
2656\r
2657/**\r
2658 Establish the known port to listen for network connections.\r
2659\r
2660 This routine calls into the network protocol layer to establish\r
2661 a handler that is called upon connection completion. The handler\r
2662 is responsible for inserting the connection into the FIFO.\r
2663\r
2664 The ::listen routine indirectly calls this routine to place the\r
2665 socket into a state that enables connection attempts. Connections\r
2666 are placed in a FIFO that is serviced by the application. The\r
2667 application calls the ::accept (::EslSocketAccept) routine to\r
2668 remove the next connection from the FIFO and get the associated\r
2669 socket and address.\r
2670\r
2671 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
2672\r
2673 @param [in] Backlog Backlog specifies the maximum FIFO depth for\r
2674 the connections waiting for the application\r
2675 to call accept. Connection attempts received\r
2676 while the queue is full are refused.\r
2677\r
2678 @param [out] pErrno Address to receive the errno value upon completion.\r
2679\r
2680 @retval EFI_SUCCESS - Socket successfully created\r
2681 @retval Other - Failed to enable the socket for listen\r
2682\r
2683**/\r
2684EFI_STATUS\r
2685EslSocketListen (\r
2686 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2687 IN INT32 Backlog,\r
2688 OUT int * pErrno\r
2689 )\r
2690{\r
2691 ESL_SOCKET * pSocket;\r
2692 EFI_STATUS Status;\r
2693 EFI_STATUS TempStatus;\r
2694 EFI_TPL TplPrevious;\r
2695\r
2696 DBG_ENTER ( );\r
2697\r
2698 //\r
2699 // Assume success\r
2700 //\r
2701 Status = EFI_SUCCESS;\r
2702\r
2703 //\r
2704 // Validate the socket\r
2705 //\r
2706 pSocket = NULL;\r
2707 if ( NULL != pSocketProtocol ) {\r
2708 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2709\r
2710 //\r
2711 // Verify the API\r
2712 //\r
2713 if ( NULL == pSocket->pApi->pfnListen ) {\r
2714 Status = EFI_UNSUPPORTED;\r
2715 pSocket->errno = ENOTSUP;\r
2716 }\r
2717 else {\r
2718 //\r
2719 // Assume success\r
2720 //\r
2721 pSocket->Status = EFI_SUCCESS;\r
2722 pSocket->errno = 0;\r
2723\r
2724 //\r
2725 // Verify that the bind operation was successful\r
2726 //\r
2727 if ( SOCKET_STATE_BOUND == pSocket->State ) {\r
2728 //\r
2729 // Synchronize with the socket layer\r
2730 //\r
2731 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2732\r
2733 //\r
2734 // Create the event for SocketAccept completion\r
2735 //\r
2736 Status = gBS->CreateEvent ( 0,\r
2737 TPL_SOCKETS,\r
2738 NULL,\r
2739 NULL,\r
2740 &pSocket->WaitAccept );\r
2741 if ( !EFI_ERROR ( Status )) {\r
2742 DEBUG (( DEBUG_POOL,\r
2743 "0x%08x: Created WaitAccept event\r\n",\r
2744 pSocket->WaitAccept ));\r
2745 //\r
2746 // Set the maximum FIFO depth\r
2747 //\r
2748 if ( 0 >= Backlog ) {\r
2749 Backlog = MAX_PENDING_CONNECTIONS;\r
2750 }\r
2751 else {\r
2752 if ( SOMAXCONN < Backlog ) {\r
2753 Backlog = SOMAXCONN;\r
2754 }\r
2755 else {\r
2756 pSocket->MaxFifoDepth = Backlog;\r
2757 }\r
2758 }\r
2759\r
2760 //\r
2761 // Initiate the connection attempt listen\r
2762 //\r
2763 Status = pSocket->pApi->pfnListen ( pSocket );\r
2764\r
2765 //\r
2766 // Place the socket in the listen state if successful\r
2767 //\r
2768 if ( !EFI_ERROR ( Status )) {\r
2769 pSocket->State = SOCKET_STATE_LISTENING;\r
2770 pSocket->bListenCalled = TRUE;\r
2771 }\r
2772 else {\r
2773 //\r
2774 // Not waiting for SocketAccept to complete\r
2775 //\r
2776 TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );\r
2777 if ( !EFI_ERROR ( TempStatus )) {\r
2778 DEBUG (( DEBUG_POOL,\r
2779 "0x%08x: Closed WaitAccept event\r\n",\r
2780 pSocket->WaitAccept ));\r
2781 pSocket->WaitAccept = NULL;\r
2782 }\r
2783 else {\r
2784 DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
2785 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",\r
2786 TempStatus ));\r
2787 ASSERT ( EFI_SUCCESS == TempStatus );\r
2788 }\r
2789 }\r
2790 }\r
2791 else {\r
2792 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
2793 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",\r
2794 Status ));\r
2795 pSocket->errno = ENOMEM;\r
2796 }\r
2797\r
2798 //\r
2799 // Release the socket layer synchronization\r
2800 //\r
2801 RESTORE_TPL ( TplPrevious );\r
2802 }\r
2803 else {\r
2804 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
2805 "ERROR - Bind operation must be performed first!\r\n" ));\r
2806 pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ\r
2807 : EINVAL;\r
2808 Status = EFI_NO_MAPPING;\r
2809 }\r
2810 }\r
2811 }\r
2812\r
2813 //\r
2814 // Return the operation status\r
2815 //\r
2816 if ( NULL != pErrno ) {\r
2817 if ( NULL != pSocket ) {\r
2818 *pErrno = pSocket->errno;\r
2819 }\r
2820 else {\r
2821 Status = EFI_INVALID_PARAMETER;\r
2822 *pErrno = ENOTSOCK;\r
2823 }\r
2824 }\r
2825 DBG_EXIT_STATUS ( Status );\r
2826 return Status;\r
2827}\r
2828\r
2829\r
2830/**\r
2831 Get the socket options\r
2832\r
2833 This routine handles the socket level options and passes the\r
2834 others to the network specific layer.\r
2835\r
2836 The ::getsockopt routine calls this routine to retrieve the\r
2837 socket options one at a time by name.\r
2838\r
2839 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
2840 @param [in] level Option protocol level\r
2841 @param [in] OptionName Name of the option\r
2842 @param [out] pOptionValue Buffer to receive the option value\r
2843 @param [in,out] pOptionLength Length of the buffer in bytes,\r
2844 upon return length of the option value in bytes\r
2845 @param [out] pErrno Address to receive the errno value upon completion.\r
2846\r
2847 @retval EFI_SUCCESS - Socket data successfully received\r
2848\r
2849 **/\r
2850EFI_STATUS\r
2851EslSocketOptionGet (\r
2852 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2853 IN int level,\r
2854 IN int OptionName,\r
2855 OUT void * __restrict pOptionValue,\r
2856 IN OUT socklen_t * __restrict pOptionLength,\r
2857 IN int * pErrno\r
2858 )\r
2859{\r
2860 int errno;\r
2861 socklen_t LengthInBytes;\r
2862 socklen_t MaxBytes;\r
2863 CONST UINT8 * pOptionData;\r
2864 ESL_SOCKET * pSocket;\r
2865 EFI_STATUS Status;\r
2866\r
2867 DBG_ENTER ( );\r
2868\r
2869 //\r
2870 // Assume failure\r
2871 //\r
2872 errno = EINVAL;\r
2873 Status = EFI_INVALID_PARAMETER;\r
2874\r
2875 //\r
2876 // Validate the socket\r
2877 //\r
2878 pSocket = NULL;\r
2879 if ( NULL == pSocketProtocol ) {\r
2880 DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));\r
2881 }\r
2882 else if ( NULL == pOptionValue ) {\r
2883 DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));\r
2884 }\r
2885 else if ( NULL == pOptionLength ) {\r
2886 DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));\r
2887 }\r
2888 else {\r
2889 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2890 LengthInBytes = 0;\r
2891 MaxBytes = *pOptionLength;\r
2892 pOptionData = NULL;\r
2893 switch ( level ) {\r
2894 default:\r
2895 //\r
2896 // See if the protocol will handle the option\r
2897 //\r
2898 if ( NULL != pSocket->pApi->pfnOptionGet ) {\r
2899 if ( pSocket->pApi->DefaultProtocol == level ) {\r
2900 Status = pSocket->pApi->pfnOptionGet ( pSocket,\r
2901 OptionName,\r
2902 (CONST void ** __restrict)&pOptionData,\r
2903 &LengthInBytes );\r
2904 errno = pSocket->errno;\r
2905 break;\r
2906 }\r
2907 else {\r
2908 //\r
2909 // Protocol not supported\r
2910 //\r
2911 DEBUG (( DEBUG_OPTION,\r
2912 "ERROR - The socket does not support this protocol!\r\n" ));\r
2913 }\r
2914 }\r
2915 else {\r
2916 //\r
2917 // Protocol level not supported\r
2918 //\r
2919 DEBUG (( DEBUG_OPTION,\r
2920 "ERROR - %a does not support any options!\r\n",\r
2921 pSocket->pApi->pName ));\r
2922 }\r
2923 errno = ENOPROTOOPT;\r
2924 Status = EFI_INVALID_PARAMETER;\r
2925 break;\r
2926\r
2927 case SOL_SOCKET:\r
2928 switch ( OptionName ) {\r
2929 default:\r
2930 //\r
2931 // Socket option not supported\r
2932 //\r
2933 DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));\r
2934 errno = EINVAL;\r
2935 Status = EFI_INVALID_PARAMETER;\r
2936 break;\r
2937\r
2938 case SO_ACCEPTCONN:\r
2939 //\r
2940 // Return the listen flag\r
2941 //\r
2942 pOptionData = (CONST UINT8 *)&pSocket->bListenCalled;\r
2943 LengthInBytes = sizeof ( pSocket->bListenCalled );\r
2944 break;\r
2945\r
2946 case SO_DEBUG:\r
2947 //\r
2948 // Return the debug flags\r
2949 //\r
2950 pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;\r
2951 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
2952 break;\r
2953\r
2954 case SO_OOBINLINE:\r
2955 //\r
2956 // Return the out-of-band inline flag\r
2957 //\r
2958 pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;\r
2959 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
2960 break;\r
2961\r
2962 case SO_RCVTIMEO:\r
2963 //\r
2964 // Return the receive timeout\r
2965 //\r
2966 pOptionData = (CONST UINT8 *)&pSocket->RxTimeout;\r
2967 LengthInBytes = sizeof ( pSocket->RxTimeout );\r
2968 break;\r
2969 \r
2970 case SO_RCVBUF:\r
2971 //\r
2972 // Return the maximum receive buffer size\r
2973 //\r
2974 pOptionData = (CONST UINT8 *)&pSocket->MaxRxBuf;\r
2975 LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
2976 break;\r
2977\r
2978 case SO_REUSEADDR:\r
2979 //\r
2980 // Return the address reuse flag\r
2981 //\r
2982 pOptionData = (UINT8 *)&pSocket->bReUseAddr;\r
2983 LengthInBytes = sizeof ( pSocket->bReUseAddr );\r
2984 break;\r
2985 \r
2986 case SO_SNDBUF:\r
2987 //\r
2988 // Return the maximum transmit buffer size\r
2989 //\r
2990 pOptionData = (CONST UINT8 *)&pSocket->MaxTxBuf;\r
2991 LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
2992 break;\r
2993\r
2994 case SO_TYPE:\r
2995 //\r
2996 // Return the socket type\r
2997 //\r
2998 pOptionData = (CONST UINT8 *)&pSocket->Type;\r
2999 LengthInBytes = sizeof ( pSocket->Type );\r
3000 break;\r
3001 }\r
3002 break;\r
3003 }\r
3004\r
3005 //\r
3006 // Return the option length\r
3007 //\r
3008 *pOptionLength = LengthInBytes;\r
3009\r
3010 //\r
3011 // Determine if the option is present\r
3012 //\r
3013 if ( 0 != LengthInBytes ) {\r
3014 //\r
3015 // Silently truncate the value length\r
3016 //\r
3017 if ( LengthInBytes > MaxBytes ) {\r
3018 DEBUG (( DEBUG_OPTION,\r
3019 "INFO - Truncating option from %d to %d bytes\r\n",\r
3020 LengthInBytes,\r
3021 MaxBytes ));\r
3022 LengthInBytes = MaxBytes;\r
3023 }\r
3024\r
3025 //\r
3026 // Return the value\r
3027 //\r
3028 CopyMem ( pOptionValue, pOptionData, LengthInBytes );\r
3029\r
3030 //\r
3031 // Zero fill any remaining space\r
3032 //\r
3033 if ( LengthInBytes < MaxBytes ) {\r
3034 ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );\r
3035 }\r
3036 errno = 0;\r
3037 Status = EFI_SUCCESS;\r
3038 }\r
3039 }\r
3040\r
3041 //\r
3042 // Return the operation status\r
3043 //\r
3044 if ( NULL != pErrno ) {\r
3045 *pErrno = errno;\r
3046 }\r
3047 DBG_EXIT_STATUS ( Status );\r
3048 return Status;\r
3049}\r
3050\r
3051\r
3052/**\r
3053 Set the socket options\r
3054\r
3055 This routine handles the socket level options and passes the\r
3056 others to the network specific layer.\r
3057\r
3058 The ::setsockopt routine calls this routine to adjust the socket\r
3059 options one at a time by name.\r
3060\r
3061 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
3062 @param [in] level Option protocol level\r
3063 @param [in] OptionName Name of the option\r
3064 @param [in] pOptionValue Buffer containing the option value\r
3065 @param [in] OptionLength Length of the buffer in bytes\r
3066 @param [out] pErrno Address to receive the errno value upon completion.\r
3067\r
3068 @retval EFI_SUCCESS - Option successfully set\r
3069\r
3070 **/\r
3071EFI_STATUS\r
3072EslSocketOptionSet (\r
3073 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
3074 IN int level,\r
3075 IN int OptionName,\r
3076 IN CONST void * pOptionValue,\r
3077 IN socklen_t OptionLength,\r
3078 IN int * pErrno\r
3079 )\r
3080{\r
3081 BOOLEAN bTrueFalse;\r
3082 int errno;\r
3083 socklen_t LengthInBytes;\r
3084 UINT8 * pOptionData;\r
3085 ESL_SOCKET * pSocket;\r
3086 EFI_STATUS Status;\r
3087 \r
3088 DBG_ENTER ( );\r
3089 \r
3090 //\r
3091 // Assume failure\r
3092 //\r
3093 errno = EINVAL;\r
3094 Status = EFI_INVALID_PARAMETER;\r
3095\r
3096 //\r
3097 // Validate the socket\r
3098 //\r
3099 pSocket = NULL;\r
3100 if ( NULL == pSocketProtocol ) {\r
3101 DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));\r
3102 }\r
3103 else if ( NULL == pOptionValue ) {\r
3104 DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));\r
3105 }\r
3106 else\r
3107 {\r
3108 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
3109 if ( pSocket->bRxDisable || pSocket->bTxDisable ) {\r
3110 DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));\r
3111 }\r
3112 else {\r
3113 LengthInBytes = 0;\r
3114 pOptionData = NULL;\r
3115 switch ( level ) {\r
3116 default:\r
3117 //\r
3118 // See if the protocol will handle the option\r
3119 //\r
3120 if ( NULL != pSocket->pApi->pfnOptionSet ) {\r
3121 if ( pSocket->pApi->DefaultProtocol == level ) {\r
3122 Status = pSocket->pApi->pfnOptionSet ( pSocket,\r
3123 OptionName,\r
3124 pOptionValue,\r
3125 OptionLength );\r
3126 errno = pSocket->errno;\r
3127 break;\r
3128 }\r
3129 else {\r
3130 //\r
3131 // Protocol not supported\r
3132 //\r
3133 DEBUG (( DEBUG_OPTION,\r
3134 "ERROR - The socket does not support this protocol!\r\n" ));\r
3135 }\r
3136 }\r
3137 else {\r
3138 //\r
3139 // Protocol level not supported\r
3140 //\r
3141 DEBUG (( DEBUG_OPTION,\r
3142 "ERROR - %a does not support any options!\r\n",\r
3143 pSocket->pApi->pName ));\r
3144 }\r
3145 errno = ENOPROTOOPT;\r
3146 Status = EFI_INVALID_PARAMETER;\r
3147 break;\r
3148 \r
3149 case SOL_SOCKET:\r
3150 switch ( OptionName ) {\r
3151 default:\r
3152 //\r
3153 // Option not supported\r
3154 //\r
3155 DEBUG (( DEBUG_OPTION,\r
3156 "ERROR - Sockets does not support this option!\r\n" ));\r
3157 errno = EINVAL;\r
3158 Status = EFI_INVALID_PARAMETER;\r
3159 break;\r
3160\r
3161 case SO_DEBUG:\r
3162 //\r
3163 // Set the debug flags\r
3164 //\r
3165 pOptionData = (UINT8 *)&pSocket->bOobInLine;\r
3166 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
3167 break;\r
3168\r
3169 case SO_OOBINLINE:\r
3170 pOptionData = (UINT8 *)&pSocket->bOobInLine;\r
3171 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
3172\r
3173 //\r
3174 // Validate the option length\r
3175 //\r
3176 if ( sizeof ( UINT32 ) == OptionLength ) {\r
3177 //\r
3178 // Restrict the input to TRUE or FALSE\r
3179 //\r
3180 bTrueFalse = TRUE;\r
3181 if ( 0 == *(UINT32 *)pOptionValue ) {\r
3182 bTrueFalse = FALSE;\r
3183 }\r
3184 pOptionValue = &bTrueFalse;\r
3185 }\r
3186 else {\r
3187 //\r
3188 // Force an invalid option length error\r
3189 //\r
3190 OptionLength = LengthInBytes - 1;\r
3191 }\r
3192 break;\r
3193\r
3194 case SO_RCVTIMEO:\r
3195 //\r
3196 // Return the receive timeout\r
3197 //\r
3198 pOptionData = (UINT8 *)&pSocket->RxTimeout;\r
3199 LengthInBytes = sizeof ( pSocket->RxTimeout );\r
3200 break;\r
3201\r
3202 case SO_RCVBUF:\r
3203 //\r
3204 // Return the maximum receive buffer size\r
3205 //\r
3206 pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
3207 LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
3208 break;\r
3209\r
3210 case SO_REUSEADDR:\r
3211 //\r
3212 // Return the address reuse flag\r
3213 //\r
3214 pOptionData = (UINT8 *)&pSocket->bReUseAddr;\r
3215 LengthInBytes = sizeof ( pSocket->bReUseAddr );\r
3216 break;\r
3217\r
3218 case SO_SNDBUF:\r
3219 //\r
3220 // Send buffer size\r
3221 //\r
3222 //\r
3223 // Return the maximum transmit buffer size\r
3224 //\r
3225 pOptionData = (UINT8 *)&pSocket->MaxTxBuf;\r
3226 LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
3227 break;\r
3228 }\r
3229 break;\r
3230 }\r
3231\r
3232 //\r
3233 // Determine if an option was found\r
3234 //\r
3235 if ( 0 != LengthInBytes ) {\r
3236 //\r
3237 // Validate the option length\r
3238 //\r
3239 if ( LengthInBytes <= OptionLength ) {\r
3240 //\r
3241 // Set the option value\r
3242 //\r
3243 CopyMem ( pOptionData, pOptionValue, LengthInBytes );\r
3244 errno = 0;\r
3245 Status = EFI_SUCCESS;\r
3246 }\r
3247 else {\r
3248 DEBUG (( DEBUG_OPTION,\r
3249 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",\r
3250 OptionLength,\r
3251 LengthInBytes ));\r
3252 }\r
3253 }\r
3254 }\r
3255 }\r
3256\r
3257 //\r
3258 // Return the operation status\r
3259 //\r
3260 if ( NULL != pErrno ) {\r
3261 *pErrno = errno;\r
3262 }\r
3263 DBG_EXIT_STATUS ( Status );\r
3264 return Status;\r
3265}\r
3266\r
3267\r
3268/**\r
3269 Allocate a packet for a receive or transmit operation\r
3270\r
3271 This support routine is called by ::EslSocketRxStart and the\r
3272 network specific TxBuffer routines to get buffer space for the\r
3273 next operation.\r
3274\r
3275 @param [in] ppPacket Address to receive the ::ESL_PACKET structure\r
3276 @param [in] LengthInBytes Length of the packet structure\r
3277 @param [in] ZeroBytes Length of packet to zero\r
3278 @param [in] DebugFlags Flags for debug messages\r
3279\r
3280 @retval EFI_SUCCESS - The packet was allocated successfully\r
3281\r
3282 **/\r
3283EFI_STATUS\r
3284EslSocketPacketAllocate (\r
3285 IN ESL_PACKET ** ppPacket,\r
3286 IN size_t LengthInBytes,\r
3287 IN size_t ZeroBytes,\r
3288 IN UINTN DebugFlags\r
3289 )\r
3290{\r
3291 ESL_PACKET * pPacket;\r
3292 EFI_STATUS Status;\r
3293\r
3294 DBG_ENTER ( );\r
3295\r
3296 //\r
3297 // Allocate a packet structure\r
3298 //\r
3299 LengthInBytes += sizeof ( *pPacket )\r
3300 - sizeof ( pPacket->Op );\r
3301 Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
3302 LengthInBytes,\r
3303 (VOID **)&pPacket );\r
3304 if ( !EFI_ERROR ( Status )) {\r
3305 DEBUG (( DebugFlags | DEBUG_POOL,\r
3306 "0x%08x: Allocate pPacket, %d bytes\r\n",\r
3307 pPacket,\r
3308 LengthInBytes ));\r
3309 if ( 0 != ZeroBytes ) {\r
3310 ZeroMem ( &pPacket->Op, ZeroBytes );\r
3311 }\r
3312 pPacket->PacketSize = LengthInBytes;\r
3313 }\r
3314 else {\r
3315 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
3316 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",\r
3317 LengthInBytes,\r
3318 Status ));\r
3319 pPacket = NULL;\r
3320 }\r
3321\r
3322 //\r
3323 // Return the packet\r
3324 //\r
3325 *ppPacket = pPacket;\r
3326\r
3327 //\r
3328 // Return the operation status\r
3329 //\r
3330 DBG_EXIT_STATUS ( Status );\r
3331 return Status;\r
3332}\r
3333\r
3334\r
3335/**\r
3336 Free a packet used for receive or transmit operation\r
3337\r
3338 This support routine is called by the network specific Close\r
3339 and TxComplete routines and during error cases in RxComplete\r
3340 and TxBuffer. Note that the network layers typically place\r
3341 receive packets on the ESL_SOCKET::pRxFree list for reuse.\r
3342\r
3343 @param [in] pPacket Address of an ::ESL_PACKET structure\r
3344 @param [in] DebugFlags Flags for debug messages\r
3345\r
3346 @retval EFI_SUCCESS - The packet was allocated successfully\r
3347\r
3348 **/\r
3349EFI_STATUS\r
3350EslSocketPacketFree (\r
3351 IN ESL_PACKET * pPacket,\r
3352 IN UINTN DebugFlags\r
3353 )\r
3354{\r
3355 UINTN LengthInBytes;\r
3356 EFI_STATUS Status;\r
3357\r
3358 DBG_ENTER ( );\r
3359\r
3360 //\r
3361 // Free a packet structure\r
3362 //\r
3363 LengthInBytes = pPacket->PacketSize;\r
3364 Status = gBS->FreePool ( pPacket );\r
3365 if ( !EFI_ERROR ( Status )) {\r
3366 DEBUG (( DebugFlags | DEBUG_POOL,\r
3367 "0x%08x: Free pPacket, %d bytes\r\n",\r
3368 pPacket,\r
3369 LengthInBytes ));\r
3370 }\r
3371 else {\r
3372 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
3373 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",\r
3374 pPacket,\r
3375 Status ));\r
3376 }\r
3377\r
3378 //\r
3379 // Return the operation status\r
3380 //\r
3381 DBG_EXIT_STATUS ( Status );\r
3382 return Status;\r
3383}\r
3384\r
3385\r
3386/**\r
3387 Poll a socket for pending activity.\r
3388\r
3389 This routine builds a detected event mask which is returned to\r
3390 the caller in the buffer provided.\r
3391\r
3392 The ::poll routine calls this routine to determine if the socket\r
3393 needs to be serviced as a result of connection, error, receive or\r
3394 transmit activity.\r
3395\r
3396 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
3397\r
3398 @param [in] Events Events of interest for this socket\r
3399\r
3400 @param [in] pEvents Address to receive the detected events\r
3401\r
3402 @param [out] pErrno Address to receive the errno value upon completion.\r
3403\r
3404 @retval EFI_SUCCESS - Socket successfully polled\r
3405 @retval EFI_INVALID_PARAMETER - When pEvents is NULL\r
3406\r
3407 **/\r
3408EFI_STATUS\r
3409EslSocketPoll (\r
3410 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
3411 IN short Events,\r
3412 IN short * pEvents,\r
3413 IN int * pErrno\r
3414 )\r
3415{\r
3416 short DetectedEvents;\r
3417 ESL_SOCKET * pSocket;\r
3418 EFI_STATUS Status;\r
3419 EFI_TPL TplPrevious;\r
3420 short ValidEvents;\r
3421\r
3422 DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));\r
3423\r
3424 //\r
3425 // Assume success\r
3426 //\r
3427 Status = EFI_SUCCESS;\r
3428 DetectedEvents = 0;\r
3429 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
3430 pSocket->errno = 0;\r
3431\r
3432 //\r
3433 // Verify the socket state\r
3434 //\r
3435 Status = EslSocketIsConfigured ( pSocket );\r
3436 if ( !EFI_ERROR ( Status )) {\r
3437 //\r
3438 // Check for invalid events\r
3439 //\r
3440 ValidEvents = POLLIN\r
3441 | POLLPRI\r
3442 | POLLOUT | POLLWRNORM\r
3443 | POLLERR\r
3444 | POLLHUP\r
3445 | POLLNVAL\r
3446 | POLLRDNORM\r
3447 | POLLRDBAND\r
3448 | POLLWRBAND ;\r
3449 if ( 0 != ( Events & ( ~ValidEvents ))) {\r
3450 DetectedEvents |= POLLNVAL;\r
3451 DEBUG (( DEBUG_INFO | DEBUG_POLL,\r
3452 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",\r
3453 Events & ValidEvents,\r
3454 Events & ( ~ValidEvents )));\r
3455 }\r
3456 else {\r
3457 //\r
3458 // Synchronize with the socket layer\r
3459 //\r
3460 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
3461 \r
3462 //\r
3463 // Increase the network performance by extending the\r
3464 // polling (idle) loop down into the LAN driver\r
3465 //\r
3466 EslSocketRxPoll ( pSocket );\r
3467 \r
3468 //\r
3469 // Release the socket layer synchronization\r
3470 //\r
3471 RESTORE_TPL ( TplPrevious );\r
3472\r
3473 //\r
3474 // Check for pending connections\r
3475 //\r
3476 if ( 0 != pSocket->FifoDepth ) {\r
3477 //\r
3478 // A connection is waiting for an accept call\r
3479 // See posix connect documentation at\r
3480 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm\r
3481 //\r
3482 DetectedEvents |= POLLIN | POLLRDNORM;\r
3483 }\r
3484 if ( pSocket->bConnected ) {\r
3485 //\r
3486 // A connection is present\r
3487 // See posix connect documentation at\r
3488 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm\r
3489 //\r
3490 DetectedEvents |= POLLOUT | POLLWRNORM;\r
3491 }\r
3492\r
3493 //\r
3494 // The following bits are set based upon the POSIX poll documentation at\r
3495 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html\r
3496 //\r
3497\r
3498 //\r
3499 // Check for urgent receive data\r
3500 //\r
3501 if ( 0 < pSocket->RxOobBytes ) {\r
3502 DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;\r
3503 }\r
3504\r
3505 //\r
3506 // Check for normal receive data\r
3507 //\r
3508 if (( 0 < pSocket->RxBytes )\r
3509 || ( EFI_SUCCESS != pSocket->RxError )) {\r
3510 DetectedEvents |= POLLRDNORM | POLLIN;\r
3511 }\r
3512\r
3513 //\r
3514 // Handle the receive errors\r
3515 //\r
3516 if (( EFI_SUCCESS != pSocket->RxError )\r
3517 && ( 0 == ( DetectedEvents & POLLIN ))) {\r
3518 DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;\r
3519 }\r
3520\r
3521 //\r
3522 // Check for urgent transmit data buffer space\r
3523 //\r
3524 if (( MAX_TX_DATA > pSocket->TxOobBytes )\r
3525 || ( EFI_SUCCESS != pSocket->TxError )) {\r
3526 DetectedEvents |= POLLWRBAND;\r
3527 }\r
3528\r
3529 //\r
3530 // Check for normal transmit data buffer space\r
3531 //\r
3532 if (( MAX_TX_DATA > pSocket->TxBytes )\r
3533 || ( EFI_SUCCESS != pSocket->TxError )) {\r
3534 DetectedEvents |= POLLWRNORM;\r
3535 }\r
3536\r
3537 //\r
3538 // Handle the transmit error\r
3539 //\r
3540 if ( EFI_ERROR ( pSocket->TxError )) {\r
3541 DetectedEvents |= POLLERR;\r
3542 }\r
3543 }\r
3544 }\r
3545\r
3546 //\r
3547 // Return the detected events\r
3548 //\r
3549 *pEvents = DetectedEvents & ( Events\r
3550 | POLLERR\r
3551 | POLLHUP\r
3552 | POLLNVAL );\r
3553\r
3554 //\r
3555 // Return the operation status\r
3556 //\r
3557 DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));\r
3558 return Status;\r
3559}\r
3560\r
3561\r
3562/**\r
3563 Allocate and initialize a ESL_PORT structure.\r
3564\r
3565 This routine initializes an ::ESL_PORT structure for use by\r
3566 the socket. This routine calls a routine via\r
3567 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network\r
3568 specific resources. The resources are released later by the\r
3569 \ref PortCloseStateMachine.\r
3570\r
3571 This support routine is called by:\r
3572 <ul>\r
3573 <li>::EslSocketBind</li>\r
3574 <li>::EslTcp4ListenComplete</li>\r
3575 </ul>\r
3576 to connect the socket with the underlying network adapter\r
3577 to the socket.\r
3578\r
3579 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
3580 @param [in] pService Address of an ::ESL_SERVICE structure.\r
3581 @param [in] ChildHandle Network protocol child handle\r
3582 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
3583 connection point on the local machine. An IPv4 address\r
3584 of INADDR_ANY specifies that the connection is made to\r
3585 all of the network stacks on the platform. Specifying a\r
3586 specific IPv4 address restricts the connection to the\r
3587 network stack supporting that address. Specifying zero\r
3588 for the port causes the network layer to assign a port\r
3589 number from the dynamic range. Specifying a specific\r
3590 port number causes the network layer to use that port.\r
3591 @param [in] bBindTest TRUE if EslSocketBindTest should be called\r
3592 @param [in] DebugFlags Flags for debug messages\r
3593 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address\r
3594\r
3595 @retval EFI_SUCCESS - Socket successfully created\r
3596\r
3597 **/\r
3598EFI_STATUS\r
3599EslSocketPortAllocate (\r
3600 IN ESL_SOCKET * pSocket,\r
3601 IN ESL_SERVICE * pService,\r
3602 IN EFI_HANDLE ChildHandle,\r
3603 IN CONST struct sockaddr * pSockAddr,\r
3604 IN BOOLEAN bBindTest,\r
3605 IN UINTN DebugFlags,\r
3606 OUT ESL_PORT ** ppPort\r
3607 )\r
3608{\r
3609 UINTN LengthInBytes;\r
3610 UINT8 * pBuffer;\r
3611 ESL_IO_MGMT * pIo;\r
3612 ESL_LAYER * pLayer;\r
3613 ESL_PORT * pPort;\r
3614 EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
3615 CONST ESL_SOCKET_BINDING * pSocketBinding;\r
3616 EFI_STATUS Status;\r
3617 EFI_STATUS TempStatus;\r
3618\r
3619 DBG_ENTER ( );\r
3620\r
3621 //\r
3622 // Verify the socket layer synchronization\r
3623 //\r
3624 VERIFY_TPL ( TPL_SOCKETS );\r
3625\r
3626 //\r
3627 // Use for/break instead of goto\r
3628 pSocketBinding = pService->pSocketBinding;\r
3629 for ( ; ; ) {\r
3630 //\r
3631 // Allocate a port structure\r
3632 //\r
3633 pLayer = &mEslLayer;\r
3634 LengthInBytes = sizeof ( *pPort )\r
3635 + ESL_STRUCTURE_ALIGNMENT_BYTES\r
3636 + (( pSocketBinding->RxIo\r
3637 + pSocketBinding->TxIoNormal\r
3638 + pSocketBinding->TxIoUrgent )\r
3639 * sizeof ( ESL_IO_MGMT ));\r
3640 pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );\r
3641 if ( NULL == pPort ) {\r
3642 Status = EFI_OUT_OF_RESOURCES;\r
3643 pSocket->errno = ENOMEM;\r
3644 break;\r
3645 }\r
3646 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
3647 "0x%08x: Allocate pPort, %d bytes\r\n",\r
3648 pPort,\r
3649 LengthInBytes ));\r
3650\r
3651 //\r
3652 // Initialize the port\r
3653 //\r
3654 pPort->DebugFlags = DebugFlags;\r
3655 pPort->Handle = ChildHandle;\r
3656 pPort->pService = pService;\r
3657 pPort->pServiceBinding = pService->pServiceBinding;\r
3658 pPort->pSocket = pSocket;\r
3659 pPort->pSocketBinding = pService->pSocketBinding;\r
3660 pPort->Signature = PORT_SIGNATURE;\r
3661\r
3662 //\r
3663 // Open the port protocol\r
3664 //\r
3665 Status = gBS->OpenProtocol ( pPort->Handle,\r
3666 pSocketBinding->pNetworkProtocolGuid,\r
3667 &pPort->pProtocol.v,\r
3668 pLayer->ImageHandle,\r
3669 NULL,\r
3670 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );\r
3671 if ( EFI_ERROR ( Status )) {\r
3672 DEBUG (( DEBUG_ERROR | DebugFlags,\r
3673 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",\r
3674 pPort->Handle ));\r
3675 pSocket->errno = EEXIST;\r
3676 break;\r
3677 }\r
3678 DEBUG (( DebugFlags,\r
3679 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",\r
3680 pPort->pProtocol.v,\r
3681 pPort->Handle ));\r
3682\r
3683 //\r
3684 // Initialize the port specific resources\r
3685 //\r
3686 Status = pSocket->pApi->pfnPortAllocate ( pPort,\r
3687 DebugFlags );\r
3688 if ( EFI_ERROR ( Status )) {\r
3689 break;\r
3690 }\r
3691\r
3692 //\r
3693 // Set the local address\r
3694 //\r
3695 Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );\r
3696 if ( EFI_ERROR ( Status )) {\r
3697 break;\r
3698 }\r
3699\r
3700 //\r
3701 // Test the address/port configuration\r
3702 //\r
3703 if ( bBindTest ) {\r
3704 Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );\r
3705 if ( EFI_ERROR ( Status )) {\r
3706 break;\r
3707 }\r
3708 }\r
3709\r
3710 //\r
3711 // Initialize the receive structures\r
3712 //\r
3713 pBuffer = (UINT8 *)&pPort[ 1 ];\r
3714 pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];\r
3715 pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );\r
3716 pIo = (ESL_IO_MGMT *)pBuffer;\r
3717 if (( 0 != pSocketBinding->RxIo )\r
3718 && ( NULL != pSocket->pApi->pfnRxComplete )) {\r
3719 Status = EslSocketIoInit ( pPort,\r
3720 &pIo,\r
3721 pSocketBinding->RxIo,\r
3722 &pPort->pRxFree,\r
3723 DebugFlags | DEBUG_POOL,\r
3724 "receive",\r
3725 pSocket->pApi->pfnRxComplete );\r
3726 if ( EFI_ERROR ( Status )) {\r
3727 break;\r
3728 }\r
3729 }\r
3730\r
3731 //\r
3732 // Initialize the urgent transmit structures\r
3733 //\r
3734 if (( 0 != pSocketBinding->TxIoUrgent )\r
3735 && ( NULL != pSocket->pApi->pfnTxOobComplete )) {\r
3736 Status = EslSocketIoInit ( pPort,\r
3737 &pIo,\r
3738 pSocketBinding->TxIoUrgent,\r
3739 &pPort->pTxOobFree,\r
3740 DebugFlags | DEBUG_POOL,\r
3741 "urgent transmit",\r
3742 pSocket->pApi->pfnTxOobComplete );\r
3743 if ( EFI_ERROR ( Status )) {\r
3744 break;\r
3745 }\r
3746 }\r
3747\r
3748 //\r
3749 // Initialize the normal transmit structures\r
3750 //\r
3751 if (( 0 != pSocketBinding->TxIoNormal )\r
3752 && ( NULL != pSocket->pApi->pfnTxComplete )) {\r
3753 Status = EslSocketIoInit ( pPort,\r
3754 &pIo,\r
3755 pSocketBinding->TxIoNormal,\r
3756 &pPort->pTxFree,\r
3757 DebugFlags | DEBUG_POOL,\r
3758 "normal transmit",\r
3759 pSocket->pApi->pfnTxComplete );\r
3760 if ( EFI_ERROR ( Status )) {\r
3761 break;\r
3762 }\r
3763 }\r
3764\r
3765 //\r
3766 // Add this port to the socket\r
3767 //\r
3768 pPort->pLinkSocket = pSocket->pPortList;\r
3769 pSocket->pPortList = pPort;\r
3770 DEBUG (( DebugFlags,\r
3771 "0x%08x: Socket adding port: 0x%08x\r\n",\r
3772 pSocket,\r
3773 pPort ));\r
3774\r
3775 //\r
3776 // Add this port to the service\r
3777 //\r
3778 pPort->pLinkService = pService->pPortList;\r
3779 pService->pPortList = pPort;\r
3780\r
3781 //\r
3782 // Return the port\r
3783 //\r
3784 *ppPort = pPort;\r
3785 break;\r
3786 }\r
3787\r
3788 //\r
3789 // Clean up after the error if necessary\r
3790 //\r
3791 if ( EFI_ERROR ( Status )) {\r
3792 if ( NULL != pPort ) {\r
3793 //\r
3794 // Close the port\r
3795 //\r
3796 EslSocketPortClose ( pPort );\r
3797 }\r
3798 else {\r
3799 //\r
3800 // Close the port if necessary\r
3801 //\r
3802 pServiceBinding = pService->pServiceBinding;\r
3803 TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,\r
3804 ChildHandle );\r
3805 if ( !EFI_ERROR ( TempStatus )) {\r
3806 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
3807 "0x%08x: %s port handle destroyed\r\n",\r
3808 ChildHandle,\r
3809 pSocketBinding->pName ));\r
3810 }\r
3811 else {\r
3812 DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,\r
3813 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",\r
3814 pSocketBinding->pName,\r
3815 ChildHandle,\r
3816 TempStatus ));\r
3817 ASSERT ( EFI_SUCCESS == TempStatus );\r
3818 }\r
3819 }\r
3820 }\r
3821 //\r
3822 // Return the operation status\r
3823 //\r
3824 DBG_EXIT_STATUS ( Status );\r
3825 return Status;\r
3826}\r
3827\r
3828\r
3829/**\r
3830 Close a port.\r
3831\r
3832 This routine releases the resources allocated by ::EslSocketPortAllocate.\r
3833 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network\r
3834 specific resources.\r
3835\r
3836 This routine is called by:\r
3837 <ul>\r
3838 <li>::EslSocketPortAllocate - Port initialization failure</li>\r
3839 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>\r
3840 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>\r
3841 </ul>\r
3842 See the \ref PortCloseStateMachine section.\r
3843 \r
3844 @param [in] pPort Address of an ::ESL_PORT structure.\r
3845\r
3846 @retval EFI_SUCCESS The port is closed\r
3847 @retval other Port close error\r
3848\r
3849**/\r
3850EFI_STATUS\r
3851EslSocketPortClose (\r
3852 IN ESL_PORT * pPort\r
3853 )\r
3854{\r
3855 UINTN DebugFlags;\r
3856 ESL_LAYER * pLayer;\r
3857 ESL_PACKET * pPacket;\r
3858 ESL_PORT * pPreviousPort;\r
3859 ESL_SERVICE * pService;\r
3860 EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
3861 CONST ESL_SOCKET_BINDING * pSocketBinding;\r
3862 ESL_SOCKET * pSocket;\r
3863 EFI_STATUS Status;\r
3864 \r
3865 DBG_ENTER ( );\r
3866\r
3867 //\r
3868 // Verify the socket layer synchronization\r
3869 //\r
3870 VERIFY_TPL ( TPL_SOCKETS );\r
3871\r
3872 //\r
3873 // Locate the port in the socket list\r
3874 //\r
3875 Status = EFI_SUCCESS;\r
3876 pLayer = &mEslLayer;\r
3877 DebugFlags = pPort->DebugFlags;\r
3878 pSocket = pPort->pSocket;\r
3879 pPreviousPort = pSocket->pPortList;\r
3880 if ( pPreviousPort == pPort ) {\r
3881 //\r
3882 // Remove this port from the head of the socket list\r
3883 //\r
3884 pSocket->pPortList = pPort->pLinkSocket;\r
3885 }\r
3886 else {\r
3887 //\r
3888 // Locate the port in the middle of the socket list\r
3889 //\r
3890 while (( NULL != pPreviousPort )\r
3891 && ( pPreviousPort->pLinkSocket != pPort )) {\r
3892 pPreviousPort = pPreviousPort->pLinkSocket;\r
3893 }\r
3894 if ( NULL != pPreviousPort ) {\r
3895 //\r
3896 // Remove the port from the middle of the socket list\r
3897 //\r
3898 pPreviousPort->pLinkSocket = pPort->pLinkSocket;\r
3899 }\r
3900 }\r
3901\r
3902 //\r
3903 // Locate the port in the service list\r
3904 // Note that the port may not be in the service list\r
3905 // if the service has been shutdown.\r
3906 //\r
3907 pService = pPort->pService;\r
3908 if ( NULL != pService ) {\r
3909 pPreviousPort = pService->pPortList;\r
3910 if ( pPreviousPort == pPort ) {\r
3911 //\r
3912 // Remove this port from the head of the service list\r
3913 //\r
3914 pService->pPortList = pPort->pLinkService;\r
3915 }\r
3916 else {\r
3917 //\r
3918 // Locate the port in the middle of the service list\r
3919 //\r
3920 while (( NULL != pPreviousPort )\r
3921 && ( pPreviousPort->pLinkService != pPort )) {\r
3922 pPreviousPort = pPreviousPort->pLinkService;\r
3923 }\r
3924 if ( NULL != pPreviousPort ) {\r
3925 //\r
3926 // Remove the port from the middle of the service list\r
3927 //\r
3928 pPreviousPort->pLinkService = pPort->pLinkService;\r
3929 }\r
3930 }\r
3931 }\r
3932\r
3933 //\r
3934 // Empty the urgent receive queue\r
3935 //\r
3936 while ( NULL != pSocket->pRxOobPacketListHead ) {\r
3937 pPacket = pSocket->pRxOobPacketListHead;\r
3938 pSocket->pRxOobPacketListHead = pPacket->pNext;\r
3939 pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );\r
3940 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
3941 }\r
3942 pSocket->pRxOobPacketListTail = NULL;\r
3943 ASSERT ( 0 == pSocket->RxOobBytes );\r
3944\r
3945 //\r
3946 // Empty the receive queue\r
3947 //\r
3948 while ( NULL != pSocket->pRxPacketListHead ) {\r
3949 pPacket = pSocket->pRxPacketListHead;\r
3950 pSocket->pRxPacketListHead = pPacket->pNext;\r
3951 pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );\r
3952 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
3953 }\r
3954 pSocket->pRxPacketListTail = NULL;\r
3955 ASSERT ( 0 == pSocket->RxBytes );\r
3956\r
3957 //\r
3958 // Empty the receive free queue\r
3959 //\r
3960 while ( NULL != pSocket->pRxFree ) {\r
3961 pPacket = pSocket->pRxFree;\r
3962 pSocket->pRxFree = pPacket->pNext;\r
3963 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
3964 }\r
3965\r
3966 //\r
3967 // Release the network specific resources\r
3968 //\r
3969 if ( NULL != pSocket->pApi->pfnPortClose ) {\r
3970 Status = pSocket->pApi->pfnPortClose ( pPort );\r
3971 }\r
3972\r
3973 //\r
3974 // Done with the normal transmit events\r
3975 //\r
3976 Status = EslSocketIoFree ( pPort,\r
3977 &pPort->pTxFree,\r
3978 DebugFlags | DEBUG_POOL,\r
3979 "normal transmit" );\r
3980\r
3981 //\r
3982 // Done with the urgent transmit events\r
3983 //\r
3984 Status = EslSocketIoFree ( pPort,\r
3985 &pPort->pTxOobFree,\r
3986 DebugFlags | DEBUG_POOL,\r
3987 "urgent transmit" );\r
3988\r
3989 //\r
3990 // Done with the receive events\r
3991 //\r
3992 Status = EslSocketIoFree ( pPort,\r
3993 &pPort->pRxFree,\r
3994 DebugFlags | DEBUG_POOL,\r
3995 "receive" );\r
3996\r
3997 //\r
3998 // Done with the lower layer network protocol\r
3999 //\r
4000 pSocketBinding = pPort->pSocketBinding;\r
4001 if ( NULL != pPort->pProtocol.v ) {\r
4002 Status = gBS->CloseProtocol ( pPort->Handle,\r
4003 pSocketBinding->pNetworkProtocolGuid,\r
4004 pLayer->ImageHandle,\r
4005 NULL );\r
4006 if ( !EFI_ERROR ( Status )) {\r
4007 DEBUG (( DebugFlags,\r
4008 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",\r
4009 pPort->pProtocol.v,\r
4010 pPort->Handle ));\r
4011 }\r
4012 else {\r
4013 DEBUG (( DEBUG_ERROR | DebugFlags,\r
4014 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",\r
4015 pPort->Handle,\r
4016 Status ));\r
4017 ASSERT ( EFI_SUCCESS == Status );\r
4018 }\r
4019 }\r
4020\r
4021 //\r
4022 // Done with the network port\r
4023 //\r
4024 pServiceBinding = pPort->pServiceBinding;\r
4025 if ( NULL != pPort->Handle ) {\r
4026 Status = pServiceBinding->DestroyChild ( pServiceBinding,\r
4027 pPort->Handle );\r
4028 if ( !EFI_ERROR ( Status )) {\r
4029 DEBUG (( DebugFlags | DEBUG_POOL,\r
4030 "0x%08x: %s port handle destroyed\r\n",\r
4031 pPort->Handle,\r
4032 pSocketBinding->pName ));\r
4033 }\r
4034 else {\r
4035 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
4036 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",\r
4037 pSocketBinding->pName,\r
4038 Status ));\r
4039 ASSERT ( EFI_SUCCESS == Status );\r
4040 }\r
4041 }\r
4042\r
4043 //\r
4044 // Release the port structure\r
4045 //\r
4046 Status = gBS->FreePool ( pPort );\r
4047 if ( !EFI_ERROR ( Status )) {\r
4048 DEBUG (( DebugFlags | DEBUG_POOL,\r
4049 "0x%08x: Free pPort, %d bytes\r\n",\r
4050 pPort,\r
4051 sizeof ( *pPort )));\r
4052 }\r
4053 else {\r
4054 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
4055 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",\r
4056 pPort,\r
4057 Status ));\r
4058 ASSERT ( EFI_SUCCESS == Status );\r
4059 }\r
4060\r
4061 //\r
4062 // Mark the socket as closed if necessary\r
4063 //\r
4064 if ( NULL == pSocket->pPortList ) {\r
4065 pSocket->State = SOCKET_STATE_CLOSED;\r
4066 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4067 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",\r
4068 pSocket ));\r
4069 }\r
4070\r
4071 //\r
4072 // Return the operation status\r
4073 //\r
4074 DBG_EXIT_STATUS ( Status );\r
4075 return Status;\r
4076}\r
4077\r
4078\r
4079/**\r
4080 Port close state 3\r
4081\r
4082 This routine attempts to complete the port close operation.\r
4083\r
4084 This routine is called by the TCP layer upon completion of\r
4085 the close operation and by ::EslSocketPortCloseTxDone.\r
4086 See the \ref PortCloseStateMachine section.\r
4087\r
4088 @param [in] Event The close completion event\r
4089\r
4090 @param [in] pPort Address of an ::ESL_PORT structure.\r
4091\r
4092**/\r
4093VOID\r
4094EslSocketPortCloseComplete (\r
4095 IN EFI_EVENT Event,\r
4096 IN ESL_PORT * pPort\r
4097 )\r
4098{\r
4099 ESL_IO_MGMT * pIo;\r
4100 EFI_STATUS Status;\r
4101\r
4102 DBG_ENTER ( );\r
4103 VERIFY_AT_TPL ( TPL_SOCKETS );\r
4104\r
4105 //\r
4106 // Update the port state\r
4107 //\r
4108 pPort->State = PORT_STATE_CLOSE_DONE;\r
4109 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4110 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",\r
4111 pPort ));\r
4112\r
4113 //\r
4114 // Shutdown the receive operation on the port\r
4115 //\r
4116 if ( NULL != pPort->pfnRxCancel ) {\r
4117 pIo = pPort->pRxActive;\r
4118 while ( NULL != pIo ) {\r
4119 EslSocketRxCancel ( pPort, pIo );\r
4120 pIo = pIo->pNext;\r
4121 }\r
4122 }\r
4123\r
4124 //\r
4125 // Determine if the receive operation is pending\r
4126 //\r
4127 Status = EslSocketPortCloseRxDone ( pPort );\r
4128 DBG_EXIT_STATUS ( Status );\r
4129}\r
4130\r
4131\r
4132/**\r
4133 Port close state 4\r
4134\r
4135 This routine determines the state of the receive operations and\r
4136 continues the close operation after the pending receive operations\r
4137 are cancelled.\r
4138\r
4139 This routine is called by\r
4140 <ul>\r
4141 <li>::EslSocketPortCloseComplete</li>\r
4142 <li>::EslSocketPortCloseTxDone</li>\r
4143 <li>::EslSocketRxComplete</li>\r
4144 </ul>\r
4145 to determine the state of the receive operations.\r
4146 See the \ref PortCloseStateMachine section.\r
4147\r
4148 @param [in] pPort Address of an ::ESL_PORT structure.\r
4149\r
4150 @retval EFI_SUCCESS The port is closed\r
4151 @retval EFI_NOT_READY The port is still closing\r
4152 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
4153 most likely the routine was called already.\r
4154\r
4155**/\r
4156EFI_STATUS\r
4157EslSocketPortCloseRxDone (\r
4158 IN ESL_PORT * pPort\r
4159 )\r
4160{\r
4161 EFI_STATUS Status;\r
4162\r
4163 DBG_ENTER ( );\r
4164\r
4165 //\r
4166 // Verify the socket layer synchronization\r
4167 //\r
4168 VERIFY_TPL ( TPL_SOCKETS );\r
4169\r
4170 //\r
4171 // Verify that the port is closing\r
4172 //\r
4173 Status = EFI_ALREADY_STARTED;\r
4174 if ( PORT_STATE_CLOSE_DONE == pPort->State ) {\r
4175 //\r
4176 // Determine if the receive operation is pending\r
4177 //\r
4178 Status = EFI_NOT_READY;\r
4179 if ( NULL == pPort->pRxActive ) {\r
4180 //\r
4181 // The receive operation is complete\r
4182 // Update the port state\r
4183 //\r
4184 pPort->State = PORT_STATE_CLOSE_RX_DONE;\r
4185 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4186 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",\r
4187 pPort ));\r
4188\r
4189 //\r
4190 // Complete the port close operation\r
4191 //\r
4192 Status = EslSocketPortClose ( pPort );\r
4193 }\r
4194 else {\r
4195 DEBUG_CODE_BEGIN ();\r
4196 {\r
4197 ESL_IO_MGMT * pIo;\r
4198 //\r
4199 // Display the outstanding receive operations\r
4200 //\r
4201 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4202 "0x%08x: Port Close: Receive still pending!\r\n",\r
4203 pPort ));\r
4204 pIo = pPort->pRxActive;\r
4205 while ( NULL != pIo ) {\r
4206 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4207 "0x%08x: Packet pending on network adapter\r\n",\r
4208 pIo->pPacket ));\r
4209 pIo = pIo->pNext;\r
4210 }\r
4211 }\r
4212 DEBUG_CODE_END ( );\r
4213 }\r
4214 }\r
4215\r
4216 //\r
4217 // Return the operation status\r
4218 //\r
4219 DBG_EXIT_STATUS ( Status );\r
4220 return Status;\r
4221}\r
4222\r
4223\r
4224/**\r
4225 Start the close operation on a port, state 1.\r
4226\r
4227 This routine marks the port as closed and initiates the \ref\r
4228 PortCloseStateMachine. The first step is to allow the \ref\r
4229 TransmitEngine to run down.\r
4230\r
4231 This routine is called by ::EslSocketCloseStart to initiate the socket\r
4232 network specific close operation on the socket.\r
4233\r
4234 @param [in] pPort Address of an ::ESL_PORT structure.\r
4235 @param [in] bCloseNow Set TRUE to abort active transfers\r
4236 @param [in] DebugFlags Flags for debug messages\r
4237\r
4238 @retval EFI_SUCCESS The port is closed, not normally returned\r
4239 @retval EFI_NOT_READY The port has started the closing process\r
4240 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
4241 most likely the routine was called already.\r
4242\r
4243**/\r
4244EFI_STATUS\r
4245EslSocketPortCloseStart (\r
4246 IN ESL_PORT * pPort,\r
4247 IN BOOLEAN bCloseNow,\r
4248 IN UINTN DebugFlags\r
4249 )\r
4250{\r
4251 ESL_SOCKET * pSocket;\r
4252 EFI_STATUS Status;\r
4253\r
4254 DBG_ENTER ( );\r
4255\r
4256 //\r
4257 // Verify the socket layer synchronization\r
4258 //\r
4259 VERIFY_TPL ( TPL_SOCKETS );\r
4260\r
4261 //\r
4262 // Mark the port as closing\r
4263 //\r
4264 Status = EFI_ALREADY_STARTED;\r
4265 pSocket = pPort->pSocket;\r
4266 pSocket->errno = EALREADY;\r
4267 if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {\r
4268\r
4269 //\r
4270 // Update the port state\r
4271 //\r
4272 pPort->State = PORT_STATE_CLOSE_STARTED;\r
4273 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4274 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",\r
4275 pPort ));\r
4276 pPort->bCloseNow = bCloseNow;\r
4277 pPort->DebugFlags = DebugFlags;\r
4278\r
4279 //\r
4280 // Determine if transmits are complete\r
4281 //\r
4282 Status = EslSocketPortCloseTxDone ( pPort );\r
4283 }\r
4284\r
4285 //\r
4286 // Return the operation status\r
4287 //\r
4288 DBG_EXIT_STATUS ( Status );\r
4289 return Status;\r
4290}\r
4291\r
4292\r
4293/**\r
4294 Port close state 2\r
4295\r
4296 This routine determines the state of the transmit engine and\r
4297 continue the close operation after the transmission is complete.\r
4298 The next step is to stop the \ref ReceiveEngine.\r
4299 See the \ref PortCloseStateMachine section.\r
4300\r
4301 This routine is called by ::EslSocketPortCloseStart to determine\r
4302 if the transmission is complete.\r
4303\r
4304 @param [in] pPort Address of an ::ESL_PORT structure.\r
4305\r
4306 @retval EFI_SUCCESS The port is closed, not normally returned\r
4307 @retval EFI_NOT_READY The port is still closing\r
4308 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
4309 most likely the routine was called already.\r
4310\r
4311**/\r
4312EFI_STATUS\r
4313EslSocketPortCloseTxDone (\r
4314 IN ESL_PORT * pPort\r
4315 )\r
4316{\r
4317 ESL_IO_MGMT * pIo;\r
4318 ESL_SOCKET * pSocket;\r
4319 EFI_STATUS Status;\r
4320\r
4321 DBG_ENTER ( );\r
4322\r
4323 //\r
4324 // Verify the socket layer synchronization\r
4325 //\r
4326 VERIFY_TPL ( TPL_SOCKETS );\r
4327\r
4328 //\r
4329 // All transmissions are complete or must be stopped\r
4330 // Mark the port as TX complete\r
4331 //\r
4332 Status = EFI_ALREADY_STARTED;\r
4333 if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {\r
4334 //\r
4335 // Verify that the transmissions are complete\r
4336 //\r
4337 pSocket = pPort->pSocket;\r
4338 if ( pPort->bCloseNow\r
4339 || ( EFI_SUCCESS != pSocket->TxError )\r
4340 || (( NULL == pPort->pTxActive )\r
4341 && ( NULL == pPort->pTxOobActive ))) {\r
4342 //\r
4343 // Update the port state\r
4344 //\r
4345 pPort->State = PORT_STATE_CLOSE_TX_DONE;\r
4346 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4347 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",\r
4348 pPort ));\r
4349\r
4350 //\r
4351 // Close the port\r
4352 // Skip the close operation if the port is not configured\r
4353 //\r
4354 Status = EFI_SUCCESS;\r
4355 pSocket = pPort->pSocket;\r
4356 if (( pPort->bConfigured )\r
4357 && ( NULL != pSocket->pApi->pfnPortCloseOp )) {\r
4358 //\r
4359 // Start the close operation\r
4360 //\r
4361 Status = pSocket->pApi->pfnPortCloseOp ( pPort );\r
4362 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4363 "0x%08x: Port Close: Close operation still pending!\r\n",\r
4364 pPort ));\r
4365 ASSERT ( EFI_SUCCESS == Status );\r
4366 }\r
4367 else {\r
4368 //\r
4369 // The receive operation is complete\r
4370 // Update the port state\r
4371 //\r
4372 EslSocketPortCloseComplete ( NULL, pPort );\r
4373 }\r
4374 }\r
4375 else {\r
4376 //\r
4377 // Transmissions are still active, exit\r
4378 //\r
4379 Status = EFI_NOT_READY;\r
4380 pSocket->errno = EAGAIN;\r
4381 DEBUG_CODE_BEGIN ( );\r
4382 {\r
4383 ESL_PACKET * pPacket;\r
4384\r
4385 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4386 "0x%08x: Port Close: Transmits are still pending!\r\n",\r
4387 pPort ));\r
4388\r
4389 //\r
4390 // Display the pending urgent transmit packets\r
4391 //\r
4392 pPacket = pSocket->pTxOobPacketListHead;\r
4393 while ( NULL != pPacket ) {\r
4394 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4395 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",\r
4396 pPacket,\r
4397 pPacket->PacketSize ));\r
4398 pPacket = pPacket->pNext;\r
4399 }\r
4400\r
4401 pIo = pPort->pTxOobActive;\r
4402 while ( NULL != pIo ) {\r
4403 pPacket = pIo->pPacket;\r
4404 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4405 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",\r
4406 pPacket,\r
4407 pPacket->PacketSize,\r
4408 pIo ));\r
4409 pIo = pIo->pNext;\r
4410 }\r
4411\r
4412 //\r
4413 // Display the pending normal transmit packets\r
4414 //\r
4415 pPacket = pSocket->pTxPacketListHead;\r
4416 while ( NULL != pPacket ) {\r
4417 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4418 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",\r
4419 pPacket,\r
4420 pPacket->PacketSize ));\r
4421 pPacket = pPacket->pNext;\r
4422 }\r
4423\r
4424 pIo = pPort->pTxActive;\r
4425 while ( NULL != pIo ) {\r
4426 pPacket = pIo->pPacket;\r
4427 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4428 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",\r
4429 pPacket,\r
4430 pPacket->PacketSize,\r
4431 pIo ));\r
4432 pIo = pIo->pNext;\r
4433 }\r
4434 }\r
4435 DEBUG_CODE_END ();\r
4436 }\r
4437 }\r
4438\r
4439 //\r
4440 // Return the operation status\r
4441 //\r
4442 DBG_EXIT_STATUS ( Status );\r
4443 return Status;\r
4444}\r
4445\r
4446\r
4447/**\r
4448 Receive data from a network connection.\r
4449\r
4450 This routine calls the network specific routine to remove the\r
4451 next portion of data from the receive queue and return it to the\r
4452 caller.\r
4453\r
4454 The ::recvfrom routine calls this routine to determine if any data\r
4455 is received from the remote system. Note that the other routines\r
4456 ::recv and ::read are layered on top of ::recvfrom.\r
4457\r
4458 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
4459 \r
4460 @param [in] Flags Message control flags\r
4461 \r
4462 @param [in] BufferLength Length of the the buffer\r
4463 \r
4464 @param [in] pBuffer Address of a buffer to receive the data.\r
4465 \r
4466 @param [in] pDataLength Number of received data bytes in the buffer.\r
4467\r
4468 @param [out] pAddress Network address to receive the remote system address\r
4469\r
4470 @param [in,out] pAddressLength Length of the remote network address structure\r
4471\r
4472 @param [out] pErrno Address to receive the errno value upon completion.\r
4473\r
4474 @retval EFI_SUCCESS - Socket data successfully received\r
4475\r
4476 **/\r
4477EFI_STATUS\r
4478EslSocketReceive (\r
4479 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
4480 IN INT32 Flags,\r
4481 IN size_t BufferLength,\r
4482 IN UINT8 * pBuffer,\r
4483 OUT size_t * pDataLength,\r
4484 OUT struct sockaddr * pAddress,\r
4485 IN OUT socklen_t * pAddressLength,\r
4486 IN int * pErrno\r
4487 )\r
4488{\r
4489 union {\r
4490 struct sockaddr_in v4;\r
4491 struct sockaddr_in6 v6;\r
4492 } Addr;\r
4493 socklen_t AddressLength;\r
4494 BOOLEAN bConsumePacket;\r
4495 BOOLEAN bUrgentQueue;\r
4496 size_t DataLength;\r
4497 ESL_PACKET * pNextPacket;\r
4498 ESL_PACKET * pPacket;\r
4499 ESL_PORT * pPort;\r
4500 ESL_PACKET ** ppQueueHead;\r
4501 ESL_PACKET ** ppQueueTail;\r
4502 struct sockaddr * pRemoteAddress;\r
4503 size_t * pRxDataBytes;\r
4504 ESL_SOCKET * pSocket;\r
4505 size_t SkipBytes;\r
4506 EFI_STATUS Status;\r
4507 EFI_TPL TplPrevious;\r
4508\r
4509 DBG_ENTER ( );\r
4510\r
4511 //\r
4512 // Assume success\r
4513 //\r
4514 Status = EFI_SUCCESS;\r
4515\r
4516 //\r
4517 // Validate the socket\r
4518 //\r
4519 pSocket = NULL;\r
4520 if ( NULL != pSocketProtocol ) {\r
4521 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
4522\r
4523 //\r
4524 // Validate the return address parameters\r
4525 //\r
4526 if (( NULL == pAddress ) || ( NULL != pAddressLength )) {\r
4527 //\r
4528 // Return the transmit error if necessary\r
4529 //\r
4530 if ( EFI_SUCCESS != pSocket->TxError ) {\r
4531 pSocket->errno = EIO;\r
4532 Status = pSocket->TxError;\r
4533 pSocket->TxError = EFI_SUCCESS;\r
4534 }\r
4535 else {\r
4536 //\r
4537 // Verify the socket state\r
4538 //\r
4539 Status = EslSocketIsConfigured ( pSocket );\r
4540 if ( !EFI_ERROR ( Status )) {\r
4541 //\r
4542 // Validate the buffer length\r
4543 //\r
4544 if (( NULL == pDataLength )\r
4545 || ( NULL == pBuffer )) {\r
4546 if ( NULL == pDataLength ) {\r
4547 DEBUG (( DEBUG_RX,\r
4548 "ERROR - pDataLength is NULL!\r\n" ));\r
4549 }\r
4550 else {\r
4551 DEBUG (( DEBUG_RX,\r
4552 "ERROR - pBuffer is NULL!\r\n" ));\r
4553 }\r
4554 Status = EFI_INVALID_PARAMETER;\r
4555 pSocket->errno = EFAULT;\r
4556 }\r
4557 else {\r
4558 //\r
4559 // Verify the API\r
4560 //\r
4561 if ( NULL == pSocket->pApi->pfnReceive ) {\r
4562 Status = EFI_UNSUPPORTED;\r
4563 pSocket->errno = ENOTSUP;\r
4564 }\r
4565 else {\r
4566 //\r
4567 // Zero the receive address if being returned\r
4568 //\r
4569 pRemoteAddress = NULL;\r
4570 if ( NULL != pAddress ) {\r
4571 pRemoteAddress = (struct sockaddr *)&Addr;\r
4572 ZeroMem ( pRemoteAddress, sizeof ( Addr ));\r
4573 pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;\r
4574 pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;\r
4575 }\r
4576 \r
4577 //\r
4578 // Synchronize with the socket layer\r
4579 //\r
4580 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
4581\r
4582 //\r
4583 // Assume failure\r
4584 //\r
4585 Status = EFI_UNSUPPORTED;\r
4586 pSocket->errno = ENOTCONN;\r
4587\r
4588 //\r
4589 // Verify that the socket is connected\r
4590 //\r
4591 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
4592 //\r
4593 // Poll the network to increase performance\r
4594 //\r
4595 EslSocketRxPoll ( pSocket );\r
4596\r
4597 //\r
4598 // Locate the port\r
4599 //\r
4600 pPort = pSocket->pPortList;\r
4601 if ( NULL != pPort ) {\r
4602 //\r
4603 // Determine the queue head\r
4604 //\r
4605 bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
4606 if ( bUrgentQueue ) {\r
4607 ppQueueHead = &pSocket->pRxOobPacketListHead;\r
4608 ppQueueTail = &pSocket->pRxOobPacketListTail;\r
4609 pRxDataBytes = &pSocket->RxOobBytes;\r
4610 }\r
4611 else {\r
4612 ppQueueHead = &pSocket->pRxPacketListHead;\r
4613 ppQueueTail = &pSocket->pRxPacketListTail;\r
4614 pRxDataBytes = &pSocket->RxBytes;\r
4615 }\r
4616\r
4617 //\r
4618 // Determine if there is any data on the queue\r
4619 //\r
4620 *pDataLength = 0;\r
4621 pPacket = *ppQueueHead;\r
4622 if ( NULL != pPacket ) {\r
4623 //\r
4624 // Copy the received data\r
4625 //\r
4626 do {\r
4627 //\r
4628 // Attempt to receive a packet\r
4629 //\r
4630 SkipBytes = 0;\r
4631 bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));\r
4632 pBuffer = pSocket->pApi->pfnReceive ( pPort,\r
4633 pPacket,\r
4634 &bConsumePacket,\r
4635 BufferLength,\r
4636 pBuffer,\r
4637 &DataLength,\r
4638 (struct sockaddr *)&Addr,\r
4639 &SkipBytes );\r
4640 *pDataLength += DataLength;\r
4641 BufferLength -= DataLength;\r
4642\r
4643 //\r
4644 // Determine if the data is being read\r
4645 //\r
4646 pNextPacket = pPacket->pNext;\r
4647 if ( bConsumePacket ) {\r
4648 //\r
4649 // All done with this packet\r
4650 // Account for any discarded data\r
4651 //\r
4652 pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );\r
4653 if ( 0 != SkipBytes ) {\r
4654 DEBUG (( DEBUG_RX,\r
4655 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",\r
4656 pPort,\r
4657 SkipBytes ));\r
4658 }\r
4659\r
4660 //\r
4661 // Remove this packet from the queue\r
4662 //\r
4663 *ppQueueHead = pPacket->pNext;\r
4664 if ( NULL == *ppQueueHead ) {\r
4665 *ppQueueTail = NULL;\r
4666 }\r
4667\r
4668 //\r
4669 // Move the packet to the free queue\r
4670 //\r
4671 pPacket->pNext = pSocket->pRxFree;\r
4672 pSocket->pRxFree = pPacket;\r
4673 DEBUG (( DEBUG_RX,\r
4674 "0x%08x: Port freeing packet 0x%08x\r\n",\r
4675 pPort,\r
4676 pPacket ));\r
4677\r
4678 //\r
4679 // Restart the receive operation if necessary\r
4680 //\r
4681 if (( NULL != pPort->pRxFree )\r
4682 && ( MAX_RX_DATA > pSocket->RxBytes )) {\r
4683 EslSocketRxStart ( pPort );\r
4684 }\r
4685 }\r
4686\r
4687 //\r
4688 // Get the next packet\r
4689 //\r
4690 pPacket = pNextPacket;\r
4691 } while (( SOCK_STREAM == pSocket->Type )\r
4692 && ( NULL != pPacket )\r
4693 && ( 0 < BufferLength ));\r
4694\r
4695 //\r
4696 // Successful operation\r
4697 //\r
4698 Status = EFI_SUCCESS;\r
4699 pSocket->errno = 0;\r
4700 }\r
4701 else {\r
4702 //\r
4703 // The queue is empty\r
4704 // Determine if it is time to return the receive error\r
4705 //\r
4706 if ( EFI_ERROR ( pSocket->RxError )\r
4707 && ( NULL == pSocket->pRxPacketListHead )\r
4708 && ( NULL == pSocket->pRxOobPacketListHead )) {\r
4709 Status = pSocket->RxError;\r
4710 pSocket->RxError = EFI_SUCCESS;\r
4711 switch ( Status ) {\r
4712 default:\r
4713 pSocket->errno = EIO;\r
4714 break;\r
4715\r
4716 case EFI_CONNECTION_FIN:\r
4717 //\r
4718 // Continue to return zero bytes received when the\r
4719 // peer has successfully closed the connection\r
4720 //\r
4721 pSocket->RxError = EFI_CONNECTION_FIN;\r
4722 *pDataLength = 0;\r
4723 pSocket->errno = 0;\r
4724 Status = EFI_SUCCESS;\r
4725 break;\r
4726\r
4727 case EFI_CONNECTION_REFUSED:\r
4728 pSocket->errno = ECONNREFUSED;\r
4729 break;\r
4730\r
4731 case EFI_CONNECTION_RESET:\r
4732 pSocket->errno = ECONNRESET;\r
4733 break;\r
4734\r
4735 case EFI_HOST_UNREACHABLE:\r
4736 pSocket->errno = EHOSTUNREACH;\r
4737 break;\r
4738\r
4739 case EFI_NETWORK_UNREACHABLE:\r
4740 pSocket->errno = ENETUNREACH;\r
4741 break;\r
4742\r
4743 case EFI_PORT_UNREACHABLE:\r
4744 pSocket->errno = EPROTONOSUPPORT;\r
4745 break;\r
4746\r
4747 case EFI_PROTOCOL_UNREACHABLE:\r
4748 pSocket->errno = ENOPROTOOPT;\r
4749 break;\r
4750 }\r
4751 }\r
4752 else {\r
4753 Status = EFI_NOT_READY;\r
4754 pSocket->errno = EAGAIN;\r
4755 }\r
4756 }\r
4757 }\r
4758 }\r
4759\r
4760 //\r
4761 // Release the socket layer synchronization\r
4762 //\r
4763 RESTORE_TPL ( TplPrevious );\r
4764\r
4765 if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {\r
4766 //\r
4767 // Return the remote address if requested, truncate if necessary\r
4768 //\r
4769 AddressLength = pRemoteAddress->sa_len;\r
4770 if ( AddressLength > *pAddressLength ) {\r
4771 AddressLength = *pAddressLength;\r
4772 }\r
4773 DEBUG (( DEBUG_RX,\r
4774 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));\r
4775 ZeroMem ( pAddress, *pAddressLength );\r
4776 CopyMem ( pAddress, &Addr, AddressLength );\r
4777\r
4778 //\r
4779 // Update the address length\r
4780 //\r
4781 *pAddressLength = pRemoteAddress->sa_len;\r
4782 }\r
4783 }\r
4784 }\r
4785 }\r
4786 }\r
4787\r
4788 \r
4789 }\r
4790 else {\r
4791 //\r
4792 // Bad return address pointer and length\r
4793 //\r
4794 Status = EFI_INVALID_PARAMETER;\r
4795 pSocket->errno = EINVAL;\r
4796 }\r
4797 }\r
4798\r
4799 //\r
4800 // Return the operation status\r
4801 //\r
4802 if ( NULL != pErrno ) {\r
4803 if ( NULL != pSocket ) {\r
4804 *pErrno = pSocket->errno;\r
4805 }\r
4806 else {\r
4807 Status = EFI_INVALID_PARAMETER;\r
4808 *pErrno = ENOTSOCK;\r
4809 }\r
4810 }\r
4811 DBG_EXIT_STATUS ( Status );\r
4812 return Status;\r
4813}\r
4814\r
4815\r
4816/**\r
4817 Cancel the receive operations\r
4818\r
4819 This routine cancels a pending receive operation.\r
4820 See the \ref ReceiveEngine section.\r
4821\r
4822 This routine is called by ::EslSocketShutdown when the socket\r
4823 layer is being shutdown.\r
4824\r
4825 @param [in] pPort Address of an ::ESL_PORT structure\r
4826 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
4827\r
4828 **/\r
4829VOID\r
4830EslSocketRxCancel (\r
4831 IN ESL_PORT * pPort,\r
4832 IN ESL_IO_MGMT * pIo\r
4833 )\r
4834{\r
4835 EFI_STATUS Status;\r
4836\r
4837 DBG_ENTER ( );\r
4838\r
4839 //\r
4840 // Cancel the outstanding receive\r
4841 //\r
4842 Status = pPort->pfnRxCancel ( pPort->pProtocol.v,\r
4843 &pIo->Token );\r
4844 if ( !EFI_ERROR ( Status )) {\r
4845 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
4846 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",\r
4847 pIo->pPacket,\r
4848 pPort ));\r
4849 }\r
4850 else {\r
4851 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
4852 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",\r
4853 pIo->pPacket,\r
4854 pPort,\r
4855 Status ));\r
4856 }\r
4857 DBG_EXIT ( );\r
4858}\r
4859\r
4860\r
4861/**\r
4862 Process the receive completion\r
4863\r
4864 This routine queues the data in FIFO order in either the urgent\r
4865 or normal data queues depending upon the type of data received.\r
4866 See the \ref ReceiveEngine section.\r
4867\r
4868 This routine is called when some data is received by:\r
4869 <ul>\r
4870 <li>::EslIp4RxComplete</li>\r
4871 <li>::EslTcp4RxComplete</li>\r
4872 <li>::EslUdp4RxComplete</li>\r
4873 </ul>\r
4874\r
4875 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
4876 @param [in] Status Receive status\r
4877 @param [in] LengthInBytes Length of the receive data\r
4878 @param [in] bUrgent TRUE if urgent data is received and FALSE\r
4879 for normal data.\r
4880\r
4881**/\r
4882VOID\r
4883EslSocketRxComplete (\r
4884 IN ESL_IO_MGMT * pIo,\r
4885 IN EFI_STATUS Status,\r
4886 IN UINTN LengthInBytes,\r
4887 IN BOOLEAN bUrgent\r
4888 )\r
4889{\r
4890 BOOLEAN bUrgentQueue;\r
4891 ESL_IO_MGMT * pIoNext;\r
4892 ESL_PACKET * pPacket;\r
4893 ESL_PORT * pPort;\r
4894 ESL_PACKET * pPrevious;\r
4895 ESL_PACKET ** ppQueueHead;\r
4896 ESL_PACKET ** ppQueueTail;\r
4897 size_t * pRxBytes;\r
4898 ESL_SOCKET * pSocket;\r
4899\r
4900 DBG_ENTER ( );\r
4901 VERIFY_AT_TPL ( TPL_SOCKETS );\r
4902\r
4903 //\r
4904 // Locate the active receive packet\r
4905 //\r
4906 pPacket = pIo->pPacket;\r
4907 pPort = pIo->pPort;\r
4908 pSocket = pPort->pSocket;\r
4909\r
4910 //\r
4911 // pPort->pRxActive\r
4912 // |\r
4913 // V\r
4914 // +-------------+ +-------------+ +-------------+ \r
4915 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
4916 // +-------------+ +-------------+ +-------------+ \r
4917 //\r
4918 // +-------------+ +-------------+ +-------------+ \r
4919 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
4920 // +-------------+ +-------------+ +-------------+ \r
4921 // ^\r
4922 // |\r
4923 // pPort->pRxFree\r
4924 //\r
4925 //\r
4926 // Remove the IO structure from the active list\r
4927 // The following code searches for the entry in the list and does not\r
4928 // assume that the receive operations complete in the order they were\r
4929 // issued to the UEFI network layer.\r
4930 //\r
4931 pIoNext = pPort->pRxActive;\r
4932 while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))\r
4933 {\r
4934 pIoNext = pIoNext->pNext;\r
4935 }\r
4936 ASSERT ( NULL != pIoNext );\r
4937 if ( pIoNext == pIo ) {\r
4938 pPort->pRxActive = pIo->pNext; // Beginning of list\r
4939 }\r
4940 else {\r
4941 pIoNext->pNext = pIo->pNext; // Middle of list\r
4942 }\r
4943\r
4944 //\r
4945 // Free the IO structure\r
4946 //\r
4947 pIo->pNext = pPort->pRxFree;\r
4948 pPort->pRxFree = pIo;\r
4949\r
4950 //\r
4951 // pRxOobPacketListHead pRxOobPacketListTail\r
4952 // | |\r
4953 // V V\r
4954 // +------------+ +------------+ +------------+ \r
4955 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
4956 // +------------+ +------------+ +------------+ \r
4957 //\r
4958 // +------------+ +------------+ +------------+ \r
4959 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
4960 // +------------+ +------------+ +------------+ \r
4961 // ^ ^\r
4962 // | |\r
4963 // pRxPacketListHead pRxPacketListTail\r
4964 //\r
4965 //\r
4966 // Determine the queue to use\r
4967 //\r
4968 bUrgentQueue = (BOOLEAN)( bUrgent\r
4969 && pSocket->pApi->bOobSupported\r
4970 && ( !pSocket->bOobInLine ));\r
4971 if ( bUrgentQueue ) {\r
4972 ppQueueHead = &pSocket->pRxOobPacketListHead;\r
4973 ppQueueTail = &pSocket->pRxOobPacketListTail;\r
4974 pRxBytes = &pSocket->RxOobBytes;\r
4975 }\r
4976 else {\r
4977 ppQueueHead = &pSocket->pRxPacketListHead;\r
4978 ppQueueTail = &pSocket->pRxPacketListTail;\r
4979 pRxBytes = &pSocket->RxBytes;\r
4980 }\r
4981\r
4982 //\r
4983 // Determine if this receive was successful\r
4984 //\r
4985 if (( !EFI_ERROR ( Status ))\r
4986 && ( PORT_STATE_CLOSE_STARTED > pPort->State )\r
4987 && ( !pSocket->bRxDisable )) {\r
4988 //\r
4989 // Account for the received data\r
4990 //\r
4991 *pRxBytes += LengthInBytes;\r
4992\r
4993 //\r
4994 // Log the received data\r
4995 //\r
4996 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
4997 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",\r
4998 pPacket,\r
4999 bUrgentQueue ? L"urgent" : L"normal",\r
5000 pPort,\r
5001 LengthInBytes,\r
5002 bUrgent ? L"urgent" : L"normal" ));\r
5003\r
5004 //\r
5005 // Add the packet to the list tail.\r
5006 //\r
5007 pPacket->pNext = NULL;\r
5008 pPrevious = *ppQueueTail;\r
5009 if ( NULL == pPrevious ) {\r
5010 *ppQueueHead = pPacket;\r
5011 }\r
5012 else {\r
5013 pPrevious->pNext = pPacket;\r
5014 }\r
5015 *ppQueueTail = pPacket;\r
5016\r
5017 //\r
5018 // Attempt to restart this receive operation\r
5019 //\r
5020 if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {\r
5021 EslSocketRxStart ( pPort );\r
5022 }\r
5023 else {\r
5024 DEBUG (( DEBUG_RX,\r
5025 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",\r
5026 pPort,\r
5027 pSocket->RxBytes ));\r
5028 }\r
5029 }\r
5030 else {\r
5031 if ( EFI_ERROR ( Status )) {\r
5032 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5033 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",\r
5034 pPort,\r
5035 pPacket,\r
5036 Status ));\r
5037 }\r
5038\r
5039 //\r
5040 // Account for the receive bytes and release the driver's buffer\r
5041 //\r
5042 if ( !EFI_ERROR ( Status )) {\r
5043 *pRxBytes += LengthInBytes;\r
5044 pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );\r
5045 }\r
5046\r
5047 //\r
5048 // Receive error, free the packet save the error\r
5049 //\r
5050 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
5051 if ( !EFI_ERROR ( pSocket->RxError )) {\r
5052 pSocket->RxError = Status;\r
5053 }\r
5054\r
5055 //\r
5056 // Update the port state\r
5057 //\r
5058 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
5059 if ( PORT_STATE_CLOSE_DONE == pPort->State ) {\r
5060 EslSocketPortCloseRxDone ( pPort );\r
5061 }\r
5062 }\r
5063 else {\r
5064 if ( EFI_ERROR ( Status )) {\r
5065 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5066 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",\r
5067 pPort,\r
5068 Status ));\r
5069 pPort->State = PORT_STATE_RX_ERROR;\r
5070 }\r
5071 }\r
5072 }\r
5073\r
5074 DBG_EXIT ( );\r
5075}\r
5076\r
5077\r
5078/**\r
5079 Poll a socket for pending receive activity.\r
5080\r
5081 This routine is called at elivated TPL and extends the idle\r
5082 loop which polls a socket down into the LAN driver layer to\r
5083 determine if there is any receive activity.\r
5084\r
5085 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit\r
5086 routines call this routine when there is nothing to do.\r
5087\r
5088 @param [in] pSocket Address of an ::EFI_SOCKET structure.\r
5089\r
5090 **/\r
5091VOID\r
5092EslSocketRxPoll (\r
5093 IN ESL_SOCKET * pSocket\r
5094 )\r
5095{\r
5096 ESL_PORT * pPort;\r
5097\r
5098 DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));\r
5099\r
5100 //\r
5101 // Increase the network performance by extending the\r
5102 // polling (idle) loop down into the LAN driver\r
5103 //\r
5104 pPort = pSocket->pPortList;\r
5105 while ( NULL != pPort ) {\r
5106 //\r
5107 // Poll the LAN adapter\r
5108 //\r
5109 pPort->pfnRxPoll ( pPort->pProtocol.v );\r
5110\r
5111 //\r
5112 // Locate the next LAN adapter\r
5113 //\r
5114 pPort = pPort->pLinkSocket;\r
5115 }\r
5116\r
5117 DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));\r
5118}\r
5119\r
5120\r
5121/**\r
5122 Start a receive operation\r
5123\r
5124 This routine posts a receive buffer to the network adapter.\r
5125 See the \ref ReceiveEngine section.\r
5126\r
5127 This support routine is called by:\r
5128 <ul>\r
5129 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>\r
5130 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
5131 <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>\r
5132 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>\r
5133 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>\r
5134 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
5135 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>\r
5136 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
5137 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>\r
5138 </ul>\r
5139\r
5140 @param [in] pPort Address of an ::ESL_PORT structure.\r
5141\r
5142 **/\r
5143VOID\r
5144EslSocketRxStart (\r
5145 IN ESL_PORT * pPort\r
5146 )\r
5147{\r
5148 UINT8 * pBuffer;\r
5149 ESL_IO_MGMT * pIo;\r
5150 ESL_PACKET * pPacket;\r
5151 ESL_SOCKET * pSocket;\r
5152 EFI_STATUS Status;\r
5153\r
5154 DBG_ENTER ( );\r
5155\r
5156 //\r
5157 // Determine if a receive is already pending\r
5158 //\r
5159 Status = EFI_SUCCESS;\r
5160 pPacket = NULL;\r
5161 pSocket = pPort->pSocket;\r
5162 if ( !EFI_ERROR ( pPort->pSocket->RxError )) {\r
5163 if (( NULL != pPort->pRxFree )\r
5164 && ( !pSocket->bRxDisable )\r
5165 && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {\r
5166 //\r
5167 // Start all of the pending receive operations\r
5168 //\r
5169 while ( NULL != pPort->pRxFree ) {\r
5170 //\r
5171 // Determine if there are any free packets\r
5172 //\r
5173 pPacket = pSocket->pRxFree;\r
5174 if ( NULL != pPacket ) {\r
5175 //\r
5176 // Remove this packet from the free list\r
5177 //\r
5178 pSocket->pRxFree = pPacket->pNext;\r
5179 DEBUG (( DEBUG_RX,\r
5180 "0x%08x: Port removed packet 0x%08x from free list\r\n",\r
5181 pPort,\r
5182 pPacket ));\r
5183 }\r
5184 else {\r
5185 //\r
5186 // Allocate a packet structure\r
5187 //\r
5188 Status = EslSocketPacketAllocate ( &pPacket,\r
5189 pSocket->pApi->RxPacketBytes,\r
5190 pSocket->pApi->RxZeroBytes,\r
5191 DEBUG_RX );\r
5192 if ( EFI_ERROR ( Status )) {\r
5193 pPacket = NULL;\r
5194 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
5195 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",\r
5196 pPort,\r
5197 Status ));\r
5198 break;\r
5199 }\r
5200 }\r
5201\r
5202 //\r
5203 // Connect the IO and packet structures\r
5204 //\r
5205 pIo = pPort->pRxFree;\r
5206 pIo->pPacket = pPacket;\r
5207\r
5208 //\r
5209 // Eliminate the need for IP4 and UDP4 specific routines by\r
5210 // clearing the RX data pointer here.\r
5211 //\r
5212 // No driver buffer for this packet\r
5213 //\r
5214 // +--------------------+\r
5215 // | ESL_IO_MGMT |\r
5216 // | |\r
5217 // | +---------------+\r
5218 // | | Token |\r
5219 // | | RxData --> NULL\r
5220 // +----+---------------+\r
5221 //\r
5222 pBuffer = (UINT8 *)pIo;\r
5223 pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];\r
5224 *(VOID **)pBuffer = NULL;\r
5225\r
5226 //\r
5227 // Network specific receive packet initialization\r
5228 //\r
5229 if ( NULL != pSocket->pApi->pfnRxStart ) {\r
5230 pSocket->pApi->pfnRxStart ( pPort, pIo );\r
5231 }\r
5232\r
5233 //\r
5234 // Start the receive on the packet\r
5235 //\r
5236 Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );\r
5237 if ( !EFI_ERROR ( Status )) {\r
5238 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5239 "0x%08x: Packet receive pending on port 0x%08x\r\n",\r
5240 pPacket,\r
5241 pPort ));\r
5242 //\r
5243 // Allocate the receive control structure\r
5244 //\r
5245 pPort->pRxFree = pIo->pNext;\r
5246 \r
5247 //\r
5248 // Mark this receive as pending\r
5249 //\r
5250 pIo->pNext = pPort->pRxActive;\r
5251 pPort->pRxActive = pIo;\r
5252 \r
5253 }\r
5254 else {\r
5255 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5256 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",\r
5257 pPort,\r
5258 Status ));\r
5259 if ( !EFI_ERROR ( pSocket->RxError )) {\r
5260 //\r
5261 // Save the error status\r
5262 //\r
5263 pSocket->RxError = Status;\r
5264 }\r
5265\r
5266 //\r
5267 // Free the packet\r
5268 //\r
5269 pIo->pPacket = NULL;\r
5270 pPacket->pNext = pSocket->pRxFree;\r
5271 pSocket->pRxFree = pPacket;\r
5272 break;\r
5273 }\r
5274 }\r
5275 }\r
5276 else {\r
5277 if ( NULL == pPort->pRxFree ) {\r
5278 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5279 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",\r
5280 pPort));\r
5281 }\r
5282 if ( pSocket->bRxDisable ) {\r
5283 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5284 "0x%08x: Port, receive disabled!\r\n",\r
5285 pPort ));\r
5286 }\r
5287 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
5288 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5289 "0x%08x: Port, is closing!\r\n",\r
5290 pPort ));\r
5291 }\r
5292 }\r
5293 }\r
5294 else {\r
5295 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
5296 "ERROR - Previous receive error, Status: %r\r\n",\r
5297 pPort->pSocket->RxError ));\r
5298 }\r
5299\r
5300 DBG_EXIT ( );\r
5301}\r
5302\r
5303\r
5304/**\r
5305 Shutdown the socket receive and transmit operations\r
5306\r
5307 This routine sets a flag to stop future transmissions and calls\r
5308 the network specific layer to cancel the pending receive operation.\r
5309\r
5310 The ::shutdown routine calls this routine to stop receive and transmit\r
5311 operations on the socket.\r
5312\r
5313 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
5314 \r
5315 @param [in] How Which operations to stop\r
5316 \r
5317 @param [out] pErrno Address to receive the errno value upon completion.\r
5318\r
5319 @retval EFI_SUCCESS - Socket operations successfully shutdown\r
5320\r
5321 **/\r
5322EFI_STATUS\r
5323EslSocketShutdown (\r
5324 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
5325 IN int How,\r
5326 IN int * pErrno\r
5327 )\r
5328{\r
5329 ESL_IO_MGMT * pIo;\r
5330 ESL_PORT * pPort;\r
5331 ESL_SOCKET * pSocket;\r
5332 EFI_STATUS Status;\r
5333 EFI_TPL TplPrevious;\r
5334 \r
5335 DBG_ENTER ( );\r
5336 \r
5337 //\r
5338 // Assume success\r
5339 //\r
5340 Status = EFI_SUCCESS;\r
5341\r
5342 //\r
5343 // Validate the socket\r
5344 //\r
5345 pSocket = NULL;\r
5346 if ( NULL != pSocketProtocol ) {\r
5347 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
5348\r
5349 //\r
5350 // Verify that the socket is connected\r
5351 //\r
5352 if ( pSocket->bConnected ) {\r
5353 //\r
5354 // Validate the How value\r
5355 //\r
5356 if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {\r
5357 //\r
5358 // Synchronize with the socket layer\r
5359 //\r
5360 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
5361\r
5362 //\r
5363 // Disable the receiver if requested\r
5364 //\r
5365 if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {\r
5366 pSocket->bRxDisable = TRUE;\r
5367 }\r
5368\r
5369 //\r
5370 // Disable the transmitter if requested\r
5371 //\r
5372 if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {\r
5373 pSocket->bTxDisable = TRUE;\r
5374 }\r
5375\r
5376 //\r
5377 // Cancel the pending receive operations\r
5378 //\r
5379 if ( pSocket->bRxDisable ) {\r
5380 //\r
5381 // Walk the list of ports\r
5382 //\r
5383 pPort = pSocket->pPortList;\r
5384 while ( NULL != pPort ) {\r
5385 //\r
5386 // Walk the list of active receive operations\r
5387 //\r
5388 pIo = pPort->pRxActive;\r
5389 while ( NULL != pIo ) {\r
5390 EslSocketRxCancel ( pPort, pIo );\r
5391 }\r
5392\r
5393 //\r
5394 // Set the next port\r
5395 //\r
5396 pPort = pPort->pLinkSocket;\r
5397 }\r
5398 }\r
5399\r
5400 //\r
5401 // Release the socket layer synchronization\r
5402 //\r
5403 RESTORE_TPL ( TplPrevious );\r
5404 }\r
5405 else {\r
5406 //\r
5407 // Invalid How value\r
5408 //\r
5409 pSocket->errno = EINVAL;\r
5410 Status = EFI_INVALID_PARAMETER;\r
5411 }\r
5412 }\r
5413 else {\r
5414 //\r
5415 // The socket is not connected\r
5416 //\r
5417 pSocket->errno = ENOTCONN;\r
5418 Status = EFI_NOT_STARTED;\r
5419 }\r
5420 }\r
5421\r
5422 //\r
5423 // Return the operation status\r
5424 //\r
5425 if ( NULL != pErrno ) {\r
5426 if ( NULL != pSocket ) {\r
5427 *pErrno = pSocket->errno;\r
5428 }\r
5429 else {\r
5430 Status = EFI_INVALID_PARAMETER;\r
5431 *pErrno = ENOTSOCK;\r
5432 }\r
5433 }\r
5434 DBG_EXIT_STATUS ( Status );\r
5435 return Status;\r
5436}\r
5437\r
5438\r
5439/**\r
5440 Send data using a network connection.\r
5441\r
5442 This routine calls the network specific layer to queue the data\r
5443 for transmission. Eventually the buffer will reach the head of\r
5444 the queue and will get transmitted over the network by the\r
5445 \ref TransmitEngine. For datagram\r
5446 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that\r
5447 the data reaches the application running on the remote system.\r
5448\r
5449 The ::sendto routine calls this routine to send data to the remote\r
5450 system. Note that ::send and ::write are layered on top of ::sendto.\r
5451\r
5452 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
5453 \r
5454 @param [in] Flags Message control flags\r
5455 \r
5456 @param [in] BufferLength Length of the the buffer\r
5457 \r
5458 @param [in] pBuffer Address of a buffer containing the data to send\r
5459 \r
5460 @param [in] pDataLength Address to receive the number of data bytes sent\r
5461\r
5462 @param [in] pAddress Network address of the remote system address\r
5463\r
5464 @param [in] AddressLength Length of the remote network address structure\r
5465\r
5466 @param [out] pErrno Address to receive the errno value upon completion.\r
5467\r
5468 @retval EFI_SUCCESS - Socket data successfully queued for transmit\r
5469\r
5470 **/\r
5471EFI_STATUS\r
5472EslSocketTransmit (\r
5473 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
5474 IN int Flags,\r
5475 IN size_t BufferLength,\r
5476 IN CONST UINT8 * pBuffer,\r
5477 OUT size_t * pDataLength,\r
5478 IN const struct sockaddr * pAddress,\r
5479 IN socklen_t AddressLength,\r
5480 IN int * pErrno\r
5481 )\r
5482{\r
5483 ESL_SOCKET * pSocket;\r
5484 EFI_STATUS Status;\r
5485 EFI_TPL TplPrevious;\r
5486\r
5487 DBG_ENTER ( );\r
5488\r
5489 //\r
5490 // Assume success\r
5491 //\r
5492 Status = EFI_SUCCESS;\r
5493\r
5494 //\r
5495 // Validate the socket\r
5496 //\r
5497 pSocket = NULL;\r
5498 if ( NULL != pSocketProtocol ) {\r
5499 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
5500\r
5501 //\r
5502 // Return the transmit error if necessary\r
5503 //\r
5504 if ( EFI_SUCCESS != pSocket->TxError ) {\r
5505 pSocket->errno = EIO;\r
5506 Status = pSocket->TxError;\r
5507 pSocket->TxError = EFI_SUCCESS;\r
5508 }\r
5509 else {\r
5510 //\r
5511 // Verify the socket state\r
5512 //\r
5513 Status = EslSocketIsConfigured ( pSocket );\r
5514 if ( !EFI_ERROR ( Status )) {\r
5515 //\r
5516 // Verify that transmit is still allowed\r
5517 //\r
5518 if ( !pSocket->bTxDisable ) {\r
5519 //\r
5520 // Validate the buffer length\r
5521 //\r
5522 if (( NULL == pDataLength )\r
5523 && ( 0 > pDataLength )\r
5524 && ( NULL == pBuffer )) {\r
5525 if ( NULL == pDataLength ) {\r
5526 DEBUG (( DEBUG_RX,\r
5527 "ERROR - pDataLength is NULL!\r\n" ));\r
5528 }\r
5529 else if ( NULL == pBuffer ) {\r
5530 DEBUG (( DEBUG_RX,\r
5531 "ERROR - pBuffer is NULL!\r\n" ));\r
5532 }\r
5533 else {\r
5534 DEBUG (( DEBUG_RX,\r
5535 "ERROR - Data length < 0!\r\n" ));\r
5536 }\r
5537 Status = EFI_INVALID_PARAMETER;\r
5538 pSocket->errno = EFAULT;\r
5539 }\r
5540 else {\r
5541 //\r
5542 // Validate the remote network address\r
5543 //\r
5544 if (( NULL != pAddress )\r
5545 && ( AddressLength < pAddress->sa_len )) {\r
5546 DEBUG (( DEBUG_TX,\r
5547 "ERROR - Invalid sin_len field in address\r\n" ));\r
5548 Status = EFI_INVALID_PARAMETER;\r
5549 pSocket->errno = EFAULT;\r
5550 }\r
5551 else {\r
5552 //\r
5553 // Verify the API\r
5554 //\r
5555 if ( NULL == pSocket->pApi->pfnTransmit ) {\r
5556 Status = EFI_UNSUPPORTED;\r
5557 pSocket->errno = ENOTSUP;\r
5558 }\r
5559 else {\r
5560 //\r
5561 // Synchronize with the socket layer\r
5562 //\r
5563 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
5564\r
5565 //\r
5566 // Poll the network to increase performance\r
5567 //\r
5568 EslSocketRxPoll ( pSocket );\r
5569\r
5570 //\r
5571 // Attempt to buffer the packet for transmission\r
5572 //\r
5573 Status = pSocket->pApi->pfnTransmit ( pSocket,\r
5574 Flags,\r
5575 BufferLength,\r
5576 pBuffer,\r
5577 pDataLength,\r
5578 pAddress,\r
5579 AddressLength );\r
5580\r
5581 //\r
5582 // Release the socket layer synchronization\r
5583 //\r
5584 RESTORE_TPL ( TplPrevious );\r
5585 }\r
5586 }\r
5587 }\r
5588 }\r
5589 else {\r
5590 //\r
5591 // The transmitter was shutdown\r
5592 //\r
5593 pSocket->errno = EPIPE;\r
5594 Status = EFI_NOT_STARTED;\r
5595 }\r
5596 }\r
5597 }\r
5598 }\r
5599\r
5600 //\r
5601 // Return the operation status\r
5602 //\r
5603 if ( NULL != pErrno ) {\r
5604 if ( NULL != pSocket ) {\r
5605 *pErrno = pSocket->errno;\r
5606 }\r
5607 else {\r
5608 Status = EFI_INVALID_PARAMETER;\r
5609 *pErrno = ENOTSOCK;\r
5610 }\r
5611 }\r
5612 DBG_EXIT_STATUS ( Status );\r
5613 return Status;\r
5614}\r
5615\r
5616\r
5617/**\r
5618 Complete the transmit operation\r
5619\r
5620 This support routine handles the transmit completion processing for\r
5621 the various network layers. It frees the ::ESL_IO_MGMT structure\r
5622 and and frees packet resources by calling ::EslSocketPacketFree.\r
5623 Transmit errors are logged in ESL_SOCKET::TxError.\r
5624 See the \ref TransmitEngine section.\r
5625\r
5626 This routine is called by:\r
5627 <ul>\r
5628 <li>::EslIp4TxComplete</li>\r
5629 <li>::EslTcp4TxComplete</li>\r
5630 <li>::EslTcp4TxOobComplete</li>\r
5631 <li>::EslUdp4TxComplete</li>\r
5632 </ul>\r
5633\r
5634 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
5635 @param [in] LengthInBytes Length of the data in bytes\r
5636 @param [in] Status Transmit operation status\r
5637 @param [in] pQueueType Zero terminated string describing queue type\r
5638 @param [in] ppQueueHead Transmit queue head address\r
5639 @param [in] ppQueueTail Transmit queue tail address\r
5640 @param [in] ppActive Active transmit queue address\r
5641 @param [in] ppFree Free transmit queue address\r
5642\r
5643 **/\r
5644VOID\r
5645EslSocketTxComplete (\r
5646 IN ESL_IO_MGMT * pIo,\r
5647 IN UINT32 LengthInBytes,\r
5648 IN EFI_STATUS Status,\r
5649 IN CONST CHAR8 * pQueueType,\r
5650 IN ESL_PACKET ** ppQueueHead,\r
5651 IN ESL_PACKET ** ppQueueTail,\r
5652 IN ESL_IO_MGMT ** ppActive,\r
5653 IN ESL_IO_MGMT ** ppFree\r
5654 )\r
5655{\r
5656 ESL_PACKET * pCurrentPacket;\r
5657 ESL_IO_MGMT * pIoNext;\r
5658 ESL_PACKET * pNextPacket;\r
5659 ESL_PACKET * pPacket;\r
5660 ESL_PORT * pPort;\r
5661 ESL_SOCKET * pSocket;\r
5662\r
5663 DBG_ENTER ( );\r
5664 VERIFY_AT_TPL ( TPL_SOCKETS );\r
5665\r
5666 //\r
5667 // Locate the active transmit packet\r
5668 //\r
5669 pPacket = pIo->pPacket;\r
5670 pPort = pIo->pPort;\r
5671 pSocket = pPort->pSocket;\r
5672\r
5673 //\r
5674 // No more packet\r
5675 //\r
5676 pIo->pPacket = NULL;\r
5677\r
5678 //\r
5679 // Remove the IO structure from the active list\r
5680 //\r
5681 pIoNext = *ppActive;\r
5682 while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))\r
5683 {\r
5684 pIoNext = pIoNext->pNext;\r
5685 }\r
5686 ASSERT ( NULL != pIoNext );\r
5687 if ( pIoNext == pIo ) {\r
5688 *ppActive = pIo->pNext; // Beginning of list\r
5689 }\r
5690 else {\r
5691 pIoNext->pNext = pIo->pNext; // Middle of list\r
5692 }\r
5693\r
5694 //\r
5695 // Free the IO structure\r
5696 //\r
5697 pIo->pNext = *ppFree;\r
5698 *ppFree = pIo;\r
5699\r
5700 //\r
5701 // Display the results\r
5702 //\r
5703 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5704 "0x%08x: pIo Released\r\n",\r
5705 pIo ));\r
5706\r
5707 //\r
5708 // Save any transmit error\r
5709 //\r
5710 if ( EFI_ERROR ( Status )) {\r
5711 if ( !EFI_ERROR ( pSocket->TxError )) {\r
5712 pSocket->TxError = Status;\r
5713 }\r
5714 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5715 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",\r
5716 pQueueType,\r
5717 pPacket,\r
5718 Status ));\r
5719\r
5720 //\r
5721 // Empty the normal transmit list\r
5722 //\r
5723 pCurrentPacket = pPacket;\r
5724 pNextPacket = *ppQueueHead;\r
5725 while ( NULL != pNextPacket ) {\r
5726 pPacket = pNextPacket;\r
5727 pNextPacket = pPacket->pNext;\r
5728 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
5729 }\r
5730 *ppQueueHead = NULL;\r
5731 *ppQueueTail = NULL;\r
5732 pPacket = pCurrentPacket;\r
5733 }\r
5734 else {\r
5735 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5736 "0x%08x: %apacket transmitted %d bytes successfully\r\n",\r
5737 pPacket,\r
5738 pQueueType,\r
5739 LengthInBytes ));\r
5740\r
5741 //\r
5742 // Verify the transmit engine is still running\r
5743 //\r
5744 if ( !pPort->bCloseNow ) {\r
5745 //\r
5746 // Start the next packet transmission\r
5747 //\r
5748 EslSocketTxStart ( pPort,\r
5749 ppQueueHead,\r
5750 ppQueueTail,\r
5751 ppActive,\r
5752 ppFree );\r
5753 }\r
5754 }\r
5755\r
5756 //\r
5757 // Release this packet\r
5758 //\r
5759 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
5760\r
5761 //\r
5762 // Finish the close operation if necessary\r
5763 //\r
5764 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
5765 //\r
5766 // Indicate that the transmit is complete\r
5767 //\r
5768 EslSocketPortCloseTxDone ( pPort );\r
5769 }\r
5770\r
5771 DBG_EXIT ( );\r
5772}\r
5773\r
5774\r
5775/**\r
5776 Transmit data using a network connection.\r
5777\r
5778 This support routine starts a transmit operation on the\r
5779 underlying network layer.\r
5780\r
5781 The network specific code calls this routine to start a\r
5782 transmit operation. See the \ref TransmitEngine section.\r
5783\r
5784 @param [in] pPort Address of an ::ESL_PORT structure\r
5785 @param [in] ppQueueHead Transmit queue head address\r
5786 @param [in] ppQueueTail Transmit queue tail address\r
5787 @param [in] ppActive Active transmit queue address\r
5788 @param [in] ppFree Free transmit queue address\r
5789\r
5790 **/\r
5791VOID\r
5792EslSocketTxStart (\r
5793 IN ESL_PORT * pPort,\r
5794 IN ESL_PACKET ** ppQueueHead,\r
5795 IN ESL_PACKET ** ppQueueTail,\r
5796 IN ESL_IO_MGMT ** ppActive,\r
5797 IN ESL_IO_MGMT ** ppFree\r
5798 )\r
5799{\r
5800 UINT8 * pBuffer;\r
5801 ESL_IO_MGMT * pIo;\r
5802 ESL_PACKET * pNextPacket;\r
5803 ESL_PACKET * pPacket;\r
5804 VOID ** ppTokenData;\r
5805 ESL_SOCKET * pSocket;\r
5806 EFI_STATUS Status;\r
5807\r
5808 DBG_ENTER ( );\r
5809\r
5810 //\r
5811 // Assume success\r
5812 //\r
5813 Status = EFI_SUCCESS;\r
5814\r
5815 //\r
5816 // Get the packet from the queue head\r
5817 //\r
5818 pPacket = *ppQueueHead;\r
5819 pIo = *ppFree;\r
5820 if (( NULL != pPacket ) && ( NULL != pIo )) {\r
5821 pSocket = pPort->pSocket;\r
5822 //\r
5823 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead\r
5824 // |\r
5825 // V\r
5826 // +------------+ +------------+ +------------+ \r
5827 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
5828 // +------------+ +------------+ +------------+ \r
5829 // ^\r
5830 // |\r
5831 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail\r
5832 //\r
5833 //\r
5834 // Remove the packet from the queue\r
5835 //\r
5836 pNextPacket = pPacket->pNext;\r
5837 *ppQueueHead = pNextPacket;\r
5838 if ( NULL == pNextPacket ) {\r
5839 *ppQueueTail = NULL;\r
5840 }\r
5841 pPacket->pNext = NULL;\r
5842\r
5843 //\r
5844 // Eliminate the need for IP4 and UDP4 specific routines by\r
5845 // connecting the token with the TX data control structure here.\r
5846 //\r
5847 // +--------------------+ +--------------------+\r
5848 // | ESL_IO_MGMT | | ESL_PACKET |\r
5849 // | | | |\r
5850 // | +---------------+ +----------------+ |\r
5851 // | | Token | | Buffer Length | |\r
5852 // | | TxData --> | Buffer Address | |\r
5853 // | | | +----------------+---+\r
5854 // | | Event | | Data Buffer |\r
5855 // +----+---------------+ | |\r
5856 // +--------------------+\r
5857 //\r
5858 // Compute the address of the TxData pointer in the token\r
5859 //\r
5860 pBuffer = (UINT8 *)&pIo->Token;\r
5861 pBuffer = &pBuffer[ pSocket->TxTokenOffset ];\r
5862 ppTokenData = (VOID **)pBuffer;\r
5863\r
5864 //\r
5865 // Compute the address of the TX data control structure in the packet\r
5866 //\r
5867 // * EFI_IP4_TRANSMIT_DATA\r
5868 // * EFI_TCP4_TRANSMIT_DATA\r
5869 // * EFI_UDP4_TRANSMIT_DATA\r
5870 //\r
5871 pBuffer = (UINT8 *)pPacket;\r
5872 pBuffer = &pBuffer[ pSocket->TxPacketOffset ];\r
5873\r
5874 //\r
5875 // Connect the token to the transmit data control structure\r
5876 //\r
5877 *ppTokenData = (VOID **)pBuffer;\r
5878\r
5879 //\r
5880 // Display the results\r
5881 //\r
5882 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5883 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",\r
5884 pIo,\r
5885 pPacket ));\r
5886\r
5887 //\r
5888 // Start the transmit operation\r
5889 //\r
5890 Status = pPort->pfnTxStart ( pPort->pProtocol.v,\r
5891 &pIo->Token );\r
5892 if ( !EFI_ERROR ( Status )) {\r
5893 //\r
5894 // Connect the structures\r
5895 //\r
5896 pIo->pPacket = pPacket;\r
5897\r
5898 //\r
5899 // +-------------+ +-------------+ +-------------+ \r
5900 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
5901 // +-------------+ +-------------+ +-------------+ \r
5902 // ^\r
5903 // |\r
5904 // *ppFree: pPort->pTxFree or pTxOobFree\r
5905 //\r
5906 //\r
5907 // Remove the IO structure from the queue\r
5908 //\r
5909 *ppFree = pIo->pNext;\r
5910 \r
5911 //\r
5912 // *ppActive: pPort->pTxActive or pTxOobActive\r
5913 // |\r
5914 // V\r
5915 // +-------------+ +-------------+ +-------------+ \r
5916 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
5917 // +-------------+ +-------------+ +-------------+ \r
5918 //\r
5919 //\r
5920 // Mark this packet as active\r
5921 //\r
5922 pIo->pPacket = pPacket;\r
5923 pIo->pNext = *ppActive;\r
5924 *ppActive = pIo;\r
5925 }\r
5926 else {\r
5927 if ( EFI_SUCCESS == pSocket->TxError ) {\r
5928 pSocket->TxError = Status;\r
5929 }\r
5930\r
5931 //\r
5932 // Discard the transmit buffer\r
5933 //\r
5934 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
5935 }\r
5936 }\r
5937\r
5938 DBG_EXIT ( );\r
5939}\r