]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/EfiSocketLib/Socket.c
Bug fix: CreateEvent sometimes returning EFI_INVALID_PARAMETER due to bad TPL value...
[mirror_edk2.git] / StdLib / EfiSocketLib / Socket.c
CommitLineData
d7ce7006 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
a88c3163 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
d7ce7006 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
a88c3163 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
d7ce7006 476 { L"Tcp4",\r
477 &gEfiTcp4ServiceBindingProtocolGuid,\r
a88c3163 478 &gEfiTcp4ProtocolGuid,\r
d7ce7006 479 &mEslTcp4ServiceGuid,\r
a88c3163 480 OFFSET_OF ( ESL_LAYER, pTcp4List ),\r
481 4, // RX buffers\r
482 4, // TX buffers\r
483 4 }, // TX Oob buffers\r
3bdf9aae 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
d7ce7006 492 { L"Udp4",\r
493 &gEfiUdp4ServiceBindingProtocolGuid,\r
a88c3163 494 &gEfiUdp4ProtocolGuid,\r
d7ce7006 495 &mEslUdp4ServiceGuid,\r
a88c3163 496 OFFSET_OF ( ESL_LAYER, pUdp4List ),\r
497 4, // RX buffers\r
498 4, // TX buffers\r
3bdf9aae 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
a88c3163 507 0 } // TX Oob buffers\r
d7ce7006 508};\r
509\r
510CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );\r
511\r
a88c3163 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
3bdf9aae 535 &cEslTcp6Api, // SOCK_STREAM\r
536 &cEslUdp6Api, // SOCK_DGRAM\r
a88c3163 537 NULL, // SOCK_RAW\r
538 NULL, // SOCK_RDM\r
3bdf9aae 539 &cEslTcp6Api // SOCK_SEQPACKET\r
a88c3163 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
d7ce7006 552\r
553\r
554/**\r
555 Initialize an endpoint for network communication.\r
556\r
a88c3163 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
d7ce7006 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
a88c3163 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
d7ce7006 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
a88c3163 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
d7ce7006 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
3bdf9aae 622 && ( AF_INET6 != domain )\r
a88c3163 623 && ( AF_LOCAL != domain )) {\r
d7ce7006 624 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
a88c3163 625 "ERROR - Invalid domain value\r\n" ));\r
d7ce7006 626 Status = EFI_INVALID_PARAMETER;\r
627 errno = EAFNOSUPPORT;\r
628 break;\r
629 }\r
630\r
a88c3163 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
d7ce7006 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
a88c3163 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
d7ce7006 661 //\r
a88c3163 662 // The socket type is not supported\r
d7ce7006 663 //\r
d7ce7006 664 Status = EFI_INVALID_PARAMETER;\r
a88c3163 665 errno = EPROTOTYPE;\r
d7ce7006 666 break;\r
667 }\r
668\r
a88c3163 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
d7ce7006 677 //\r
678 // Validate the protocol value\r
679 //\r
a88c3163 680 if (( pApi->DefaultProtocol != protocol )\r
681 && ( SOCK_RAW != type )) {\r
d7ce7006 682 Status = EFI_INVALID_PARAMETER;\r
a88c3163 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
d7ce7006 724 break;\r
725 }\r
726\r
727 //\r
728 // Save the socket attributes\r
729 //\r
a88c3163 730 pSocket->pApi = pApi;\r
d7ce7006 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
a88c3163 755 This routine calls the network specific layer to remove the next\r
756 connection from the FIFO.\r
d7ce7006 757\r
a88c3163 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
d7ce7006 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
a88c3163 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
d7ce7006 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
a88c3163 792 ESL_SOCKET * pNewSocket;\r
793 ESL_SOCKET * pSocket;\r
d7ce7006 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
a88c3163 813 // Verify the API\r
d7ce7006 814 //\r
a88c3163 815 if ( NULL == pSocket->pApi->pfnAccept ) {\r
816 Status = EFI_UNSUPPORTED;\r
817 pSocket->errno = ENOTSUP;\r
d7ce7006 818 }\r
819 else {\r
820 //\r
a88c3163 821 // Validate the sockaddr\r
d7ce7006 822 //\r
a88c3163 823 if (( NULL != pSockAddr )\r
824 && ( NULL == pSockAddrLength )) {\r
d7ce7006 825 DEBUG (( DEBUG_ACCEPT,\r
a88c3163 826 "ERROR - pSockAddr is NULL!\r\n" ));\r
827 Status = EFI_INVALID_PARAMETER;\r
828 pSocket->errno = EFAULT;\r
d7ce7006 829 }\r
830 else {\r
831 //\r
a88c3163 832 // Synchronize with the socket layer\r
d7ce7006 833 //\r
a88c3163 834 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
d7ce7006 835\r
a88c3163 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
d7ce7006 843 //\r
a88c3163 844 // Socket does not support listen\r
d7ce7006 845 //\r
a88c3163 846 pSocket->errno = EOPNOTSUPP;\r
847 Status = EFI_UNSUPPORTED;\r
d7ce7006 848 }\r
849 else {\r
850 //\r
a88c3163 851 // Socket supports listen, but not in listen state\r
d7ce7006 852 //\r
a88c3163 853 pSocket->errno = EINVAL;\r
854 Status = EFI_NOT_STARTED;\r
d7ce7006 855 }\r
856 }\r
857 else {\r
d7ce7006 858 //\r
a88c3163 859 // Determine if a socket is available\r
d7ce7006 860 //\r
a88c3163 861 if ( 0 == pSocket->FifoDepth ) {\r
d7ce7006 862 //\r
a88c3163 863 // No connections available\r
864 // Determine if any ports are available\r
d7ce7006 865 //\r
a88c3163 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
d7ce7006 877 }\r
a88c3163 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
d7ce7006 885 }\r
a88c3163 886 }\r
887 else {\r
d7ce7006 888\r
889 //\r
a88c3163 890 // Attempt to accept the connection and\r
891 // get the remote network address\r
d7ce7006 892 //\r
a88c3163 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
d7ce7006 906\r
a88c3163 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
d7ce7006 921 }\r
922 }\r
d7ce7006 923\r
a88c3163 924 //\r
925 // Release the socket layer synchronization\r
926 //\r
927 RESTORE_TPL ( TplPrevious );\r
928 }\r
d7ce7006 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
a88c3163 947 else {\r
d7ce7006 948 Status = EFI_INVALID_PARAMETER;\r
a88c3163 949 *pErrno = ENOTSOCK;\r
d7ce7006 950 }\r
951 }\r
952 DBG_EXIT_STATUS ( Status );\r
953 return Status;\r
954}\r
955\r
956\r
957/**\r
a88c3163 958 Allocate and initialize a ESL_SOCKET structure.\r
d7ce7006 959 \r
a88c3163 960 This support function allocates an ::ESL_SOCKET structure\r
d7ce7006 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
a88c3163 972 @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.\r
d7ce7006 973\r
974 @retval EFI_SUCCESS The protocol was added to ChildHandle.\r
975 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
a88c3163 976 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create\r
d7ce7006 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
a88c3163 986 IN OUT ESL_SOCKET ** ppSocket\r
d7ce7006 987 )\r
988{\r
989 UINTN LengthInBytes;\r
a88c3163 990 ESL_LAYER * pLayer;\r
991 ESL_SOCKET * pSocket;\r
d7ce7006 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
a88c3163 1001 pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );\r
1002 if ( NULL != pSocket ) {\r
d7ce7006 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
d7ce7006 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
d7ce7006 1024 pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;\r
1025 pSocket->SocketProtocol.pfnSocket = EslSocket;\r
a88c3163 1026 pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;\r
d7ce7006 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
a88c3163 1088 Status = EFI_OUT_OF_RESOURCES;\r
d7ce7006 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
a88c3163 1102 This routine calls the network specific layer to save the network\r
1103 address of the local connection point.\r
d7ce7006 1104\r
a88c3163 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
d7ce7006 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
a88c3163 1120 @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.\r
d7ce7006 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
a88c3163 1130 IN CONST struct sockaddr * pSockAddr,\r
d7ce7006 1131 IN socklen_t SockAddrLength,\r
1132 OUT int * pErrno\r
1133 )\r
1134{\r
a88c3163 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
d7ce7006 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
a88c3163 1162 pSocket->errno = 0;\r
d7ce7006 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
a88c3163 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
d7ce7006 1203 //\r
a88c3163 1204 // Synchronize with the socket layer\r
d7ce7006 1205 //\r
a88c3163 1206 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
d7ce7006 1207\r
a88c3163 1208 //\r
1209 // Assume no ports are available\r
1210 //\r
1211 pSocket->errno = EADDRNOTAVAIL;\r
1212 Status = EFI_INVALID_PARAMETER;\r
d7ce7006 1213\r
a88c3163 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
d7ce7006 1222 //\r
a88c3163 1223 // Create the port\r
d7ce7006 1224 //\r
a88c3163 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
d7ce7006 1234\r
d7ce7006 1235 //\r
a88c3163 1236 // Open the port\r
d7ce7006 1237 //\r
a88c3163 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
d7ce7006 1251 }\r
1252\r
1253 //\r
a88c3163 1254 // Set the next service\r
d7ce7006 1255 //\r
a88c3163 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 if ( EADDRNOTAVAIL == pSocket->errno ) {\r
1264 DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
1265 "ERROR - Socket address is not available!\r\n" ));\r
1266 }\r
1267 if ( EADDRINUSE == pSocket->errno ) {\r
1268 DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
1269 "ERROR - Socket address is in use!\r\n" ));\r
d7ce7006 1270 }\r
a88c3163 1271 Status = EFI_INVALID_PARAMETER;\r
1272 }\r
d7ce7006 1273\r
a88c3163 1274 //\r
1275 // Mark this socket as bound if successful\r
1276 //\r
1277 if ( !EFI_ERROR ( Status )) {\r
1278 pSocket->State = SOCKET_STATE_BOUND;\r
1279 pSocket->errno = 0;\r
d7ce7006 1280 }\r
a88c3163 1281\r
1282 //\r
1283 // Release the socket layer synchronization\r
1284 //\r
1285 RESTORE_TPL ( TplPrevious );\r
d7ce7006 1286 }\r
1287 }\r
1288\r
1289 //\r
1290 // Return the operation status\r
1291 //\r
1292 if ( NULL != pErrno ) {\r
1293 if ( NULL != pSocket ) {\r
1294 *pErrno = pSocket->errno;\r
1295 }\r
a88c3163 1296 else {\r
d7ce7006 1297 Status = EFI_INVALID_PARAMETER;\r
a88c3163 1298 *pErrno = ENOTSOCK;\r
d7ce7006 1299 }\r
1300 }\r
1301 DBG_EXIT_STATUS ( Status );\r
1302 return Status;\r
1303}\r
1304\r
1305\r
1306/**\r
a88c3163 1307 Test the bind configuration.\r
d7ce7006 1308\r
a88c3163 1309 @param [in] pPort Address of the ::ESL_PORT structure.\r
1310 @param [in] ErrnoValue errno value if test fails\r
d7ce7006 1311\r
a88c3163 1312 @retval EFI_SUCCESS The connection was successfully established.\r
1313 @retval Others The connection attempt failed.\r
d7ce7006 1314\r
a88c3163 1315 **/\r
d7ce7006 1316EFI_STATUS\r
a88c3163 1317EslSocketBindTest (\r
1318 IN ESL_PORT * pPort,\r
1319 IN int ErrnoValue\r
d7ce7006 1320 )\r
1321{\r
a88c3163 1322 UINT8 * pBuffer;\r
1323 VOID * pConfigData;\r
d7ce7006 1324 EFI_STATUS Status;\r
d7ce7006 1325\r
1326 DBG_ENTER ( );\r
1327\r
1328 //\r
a88c3163 1329 // Locate the configuration data\r
d7ce7006 1330 //\r
a88c3163 1331 pBuffer = (UINT8 *)pPort;\r
1332 pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];\r
1333 pConfigData = (VOID *)pBuffer;\r
d7ce7006 1334\r
1335 //\r
a88c3163 1336 // Attempt to use this configuration\r
d7ce7006 1337 //\r
a88c3163 1338 Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );\r
1339 if ( EFI_ERROR ( Status )) {\r
1340 DEBUG (( DEBUG_WARN | DEBUG_BIND,\r
1341 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",\r
1342 pPort,\r
1343 Status ));\r
1344 pPort->pSocket->errno = ErrnoValue;\r
1345 }\r
1346 else {\r
1347 //\r
1348 // Reset the port\r
1349 //\r
1350 Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );\r
1351 if ( EFI_ERROR ( Status )) {\r
1352 DEBUG (( DEBUG_ERROR | DEBUG_BIND,\r
1353 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",\r
1354 pPort,\r
1355 Status ));\r
1356 ASSERT ( EFI_SUCCESS == Status );\r
1357 }\r
1358 }\r
d7ce7006 1359\r
1360 //\r
a88c3163 1361 // Return the operation status\r
d7ce7006 1362 //\r
a88c3163 1363 DBG_EXIT_STATUS ( Status );\r
1364 return Status;\r
1365}\r
1366\r
1367\r
1368/**\r
1369 Determine if the socket is closed\r
1370\r
1371 This routine checks the state of the socket to determine if\r
1372 the network specific layer has completed the close operation.\r
1373\r
1374 The ::close routine polls this routine to determine when the\r
1375 close operation is complete. The close operation needs to\r
1376 reverse the operations of the ::EslSocketAllocate routine.\r
1377\r
1378 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
1379 @param [out] pErrno Address to receive the errno value upon completion.\r
1380\r
1381 @retval EFI_SUCCESS Socket successfully closed\r
1382 @retval EFI_NOT_READY Close still in progress\r
1383 @retval EFI_ALREADY Close operation already in progress\r
1384 @retval Other Failed to close the socket\r
1385\r
1386**/\r
1387EFI_STATUS\r
1388EslSocketClosePoll (\r
1389 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1390 IN int * pErrno\r
1391 )\r
1392{\r
1393 int errno;\r
1394 ESL_LAYER * pLayer;\r
1395 ESL_SOCKET * pNextSocket;\r
1396 ESL_SOCKET * pSocket;\r
1397 EFI_STATUS Status;\r
1398 EFI_TPL TplPrevious;\r
1399\r
1400 DBG_ENTER ( );\r
1401\r
1402 //\r
1403 // Assume success\r
1404 //\r
1405 errno = 0;\r
1406 Status = EFI_SUCCESS;\r
1407\r
1408 //\r
1409 // Synchronize with the socket layer\r
1410 //\r
1411 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1412\r
1413 //\r
1414 // Locate the socket\r
1415 //\r
1416 pLayer = &mEslLayer;\r
1417 pNextSocket = pLayer->pSocketList;\r
d7ce7006 1418 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1419 while ( NULL != pNextSocket ) {\r
1420 if ( pNextSocket == pSocket ) {\r
1421 //\r
1422 // Determine if the socket is in the closing state\r
1423 //\r
1424 if ( SOCKET_STATE_CLOSED == pSocket->State ) {\r
1425 //\r
1426 // Walk the list of ports\r
1427 //\r
1428 if ( NULL == pSocket->pPortList ) {\r
1429 //\r
1430 // All the ports are closed\r
1431 // Close the WaitAccept event if necessary\r
1432 //\r
1433 if ( NULL != pSocket->WaitAccept ) {\r
1434 Status = gBS->CloseEvent ( pSocket->WaitAccept );\r
1435 if ( !EFI_ERROR ( Status )) {\r
1436 DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
1437 "0x%08x: Closed WaitAccept event\r\n",\r
1438 pSocket->WaitAccept ));\r
1439 //\r
1440 // Return the transmit status\r
1441 //\r
1442 Status = pSocket->TxError;\r
1443 if ( EFI_ERROR ( Status )) {\r
1444 pSocket->errno = EIO;\r
1445 }\r
1446 }\r
1447 else {\r
1448 DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
1449 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",\r
1450 Status ));\r
1451 ASSERT ( EFI_SUCCESS == Status );\r
1452 }\r
1453 }\r
1454 }\r
1455 else {\r
1456 //\r
1457 // At least one port is still open\r
1458 //\r
1459 Status = EFI_NOT_READY;\r
1460 errno = EAGAIN;\r
1461 }\r
1462 }\r
1463 else {\r
1464 //\r
1465 // SocketCloseStart was not called\r
1466 //\r
1467 Status = EFI_NOT_STARTED;\r
1468 errno = EPERM;\r
1469 }\r
1470 break;\r
1471 }\r
1472\r
1473 //\r
1474 // Set the next socket\r
1475 //\r
1476 pNextSocket = pNextSocket->pNext;\r
1477 }\r
1478\r
1479 //\r
1480 // Handle the error case where the socket was already closed\r
1481 //\r
1482 if ( NULL == pSocket ) {\r
1483 //\r
1484 // Socket not found\r
1485 //\r
1486 Status = EFI_NOT_FOUND;\r
1487 errno = ENOTSOCK;\r
1488 }\r
1489\r
1490 //\r
1491 // Release the socket layer synchronization\r
1492 //\r
1493 RESTORE_TPL ( TplPrevious );\r
1494\r
1495 //\r
1496 // Return the operation status\r
1497 //\r
1498 if ( NULL != pErrno ) {\r
1499 *pErrno = errno;\r
1500 }\r
1501 DBG_EXIT_STATUS ( Status );\r
1502 return Status;\r
1503}\r
1504\r
1505\r
1506/**\r
1507 Start the close operation on the socket\r
1508\r
a88c3163 1509 This routine calls the network specific layer to initiate the\r
1510 close state machine. This routine then calls the network\r
1511 specific layer to determine if the close state machine has gone\r
1512 to completion. The result from this poll is returned to the\r
1513 caller.\r
d7ce7006 1514\r
a88c3163 1515 The ::close routine calls this routine to start the close\r
1516 operation which reverses the operations of the\r
1517 ::EslSocketAllocate routine. The close routine then polls\r
1518 the ::EslSocketClosePoll routine to determine when the\r
1519 socket is closed.\r
1520\r
1521 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
d7ce7006 1522 @param [in] bCloseNow Boolean to control close behavior\r
1523 @param [out] pErrno Address to receive the errno value upon completion.\r
1524\r
1525 @retval EFI_SUCCESS Socket successfully closed\r
1526 @retval EFI_NOT_READY Close still in progress\r
1527 @retval EFI_ALREADY Close operation already in progress\r
1528 @retval Other Failed to close the socket\r
1529\r
1530**/\r
1531EFI_STATUS\r
1532EslSocketCloseStart (\r
1533 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1534 IN BOOLEAN bCloseNow,\r
1535 IN int * pErrno\r
1536 )\r
1537{\r
1538 int errno;\r
a88c3163 1539 ESL_PORT * pNextPort;\r
1540 ESL_PORT * pPort;\r
1541 ESL_SOCKET * pSocket;\r
d7ce7006 1542 EFI_STATUS Status;\r
1543 EFI_TPL TplPrevious;\r
1544\r
1545 DBG_ENTER ( );\r
1546\r
1547 //\r
1548 // Assume success\r
1549 //\r
1550 Status = EFI_SUCCESS;\r
1551 errno = 0;\r
1552\r
1553 //\r
1554 // Synchronize with the socket layer\r
1555 //\r
1556 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1557\r
1558 //\r
1559 // Determine if the socket is already closed\r
1560 //\r
1561 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1562 if ( SOCKET_STATE_CLOSED > pSocket->State ) {\r
1563 //\r
1564 // Update the socket state\r
1565 //\r
1566 pSocket->State = SOCKET_STATE_CLOSED;\r
1567\r
1568 //\r
1569 // Walk the list of ports\r
1570 //\r
1571 pPort = pSocket->pPortList;\r
1572 while ( NULL != pPort ) {\r
1573 //\r
1574 // Start closing the ports\r
1575 //\r
1576 pNextPort = pPort->pLinkSocket;\r
a88c3163 1577 Status = EslSocketPortCloseStart ( pPort,\r
1578 bCloseNow,\r
1579 DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );\r
d7ce7006 1580 if (( EFI_SUCCESS != Status )\r
1581 && ( EFI_NOT_READY != Status )) {\r
1582 errno = EIO;\r
1583 break;\r
1584 }\r
1585\r
1586 //\r
1587 // Set the next port\r
1588 //\r
1589 pPort = pNextPort;\r
1590 }\r
1591\r
1592 //\r
1593 // Attempt to finish closing the socket\r
1594 //\r
1595 if ( NULL == pPort ) {\r
1596 Status = EslSocketClosePoll ( pSocketProtocol, &errno );\r
1597 }\r
1598 }\r
1599 else {\r
a88c3163 1600 Status = EFI_NOT_READY;\r
1601 errno = EAGAIN;\r
d7ce7006 1602 }\r
1603\r
1604 //\r
1605 // Release the socket layer synchronization\r
1606 //\r
1607 RESTORE_TPL ( TplPrevious );\r
1608\r
1609 //\r
1610 // Return the operation status\r
1611 //\r
1612 if ( NULL != pErrno ) {\r
1613 *pErrno = errno;\r
1614 }\r
1615 DBG_EXIT_STATUS ( Status );\r
1616 return Status;\r
1617}\r
1618\r
1619\r
1620/**\r
1621 Connect to a remote system via the network.\r
1622\r
a88c3163 1623 This routine calls the network specific layer to establish\r
1624 the remote system address and establish the connection to\r
1625 the remote system.\r
d7ce7006 1626\r
a88c3163 1627 The ::connect routine calls this routine to establish a\r
1628 connection with the specified remote system. This routine\r
1629 is designed to be polled by the connect routine for completion\r
1630 of the network connection.\r
1631 \r
1632 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
d7ce7006 1633\r
1634 @param [in] pSockAddr Network address of the remote system.\r
1635 \r
1636 @param [in] SockAddrLength Length in bytes of the network address.\r
1637 \r
1638 @param [out] pErrno Address to receive the errno value upon completion.\r
1639 \r
1640 @retval EFI_SUCCESS The connection was successfully established.\r
1641 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
1642 @retval Others The connection attempt failed.\r
1643\r
1644 **/\r
1645EFI_STATUS\r
1646EslSocketConnect (\r
1647 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1648 IN const struct sockaddr * pSockAddr,\r
1649 IN socklen_t SockAddrLength,\r
1650 IN int * pErrno\r
1651 )\r
1652{\r
a88c3163 1653 struct sockaddr_in6 LocalAddress;\r
1654 ESL_PORT * pPort;\r
1655 ESL_SOCKET * pSocket;\r
d7ce7006 1656 EFI_STATUS Status;\r
1657 EFI_TPL TplPrevious;\r
1658 \r
1659 DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));\r
1660\r
1661 //\r
1662 // Assume success\r
1663 //\r
1664 Status = EFI_SUCCESS;\r
1665\r
1666 //\r
1667 // Validate the socket\r
1668 //\r
1669 pSocket = NULL;\r
1670 if ( NULL != pSocketProtocol ) {\r
1671 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1672\r
1673 //\r
1674 // Validate the name length\r
1675 //\r
a88c3163 1676 if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {\r
d7ce7006 1677 DEBUG (( DEBUG_CONNECT,\r
a88c3163 1678 "ERROR - Invalid bind name length: %d\r\n",\r
1679 SockAddrLength ));\r
d7ce7006 1680 Status = EFI_INVALID_PARAMETER;\r
1681 pSocket->errno = EINVAL;\r
1682 }\r
1683 else {\r
1684 //\r
1685 // Assume success\r
1686 //\r
1687 pSocket->errno = 0;\r
1688\r
d7ce7006 1689 //\r
1690 // Synchronize with the socket layer\r
1691 //\r
1692 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1693\r
1694 //\r
1695 // Validate the socket state\r
1696 //\r
1697 switch ( pSocket->State ) {\r
1698 default:\r
1699 //\r
1700 // Wrong socket state\r
1701 //\r
1702 pSocket->errno = EIO;\r
1703 Status = EFI_DEVICE_ERROR;\r
1704 break;\r
1705\r
1706 case SOCKET_STATE_NOT_CONFIGURED:\r
1707 case SOCKET_STATE_BOUND:\r
1708 //\r
a88c3163 1709 // Validate the address length\r
d7ce7006 1710 //\r
a88c3163 1711 if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {\r
d7ce7006 1712 //\r
a88c3163 1713 // Verify the API\r
d7ce7006 1714 //\r
a88c3163 1715 if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {\r
d7ce7006 1716 //\r
a88c3163 1717 // Already connected\r
d7ce7006 1718 //\r
a88c3163 1719 pSocket->errno = ENOTSUP;\r
1720 Status = EFI_UNSUPPORTED;\r
1721 }\r
1722 else {\r
d7ce7006 1723 //\r
a88c3163 1724 // Determine if BIND was already called\r
d7ce7006 1725 //\r
a88c3163 1726 if ( NULL == pSocket->pPortList ) {\r
1727 //\r
1728 // Allow any local port\r
1729 //\r
1730 ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
1731 LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;\r
1732 LocalAddress.sin6_family = pSocket->pApi->AddressFamily;\r
1733 Status = EslSocketBind ( &pSocket->SocketProtocol,\r
1734 (struct sockaddr *)&LocalAddress,\r
1735 LocalAddress.sin6_len,\r
1736 &pSocket->errno );\r
d7ce7006 1737 }\r
a88c3163 1738 if ( NULL != pSocket->pPortList ) {\r
1739 //\r
1740 // Walk the list of ports\r
1741 //\r
1742 pPort = pSocket->pPortList;\r
1743 while ( NULL != pPort ) {\r
1744 //\r
1745 // Set the remote address\r
1746 //\r
1747 Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,\r
1748 pSockAddr,\r
1749 SockAddrLength );\r
1750 if ( EFI_ERROR ( Status )) {\r
1751 break;\r
1752 }\r
d7ce7006 1753\r
a88c3163 1754 //\r
1755 // Set the next port\r
1756 //\r
1757 pPort = pPort->pLinkSocket;\r
1758 }\r
1759\r
1760 //\r
1761 // Verify the API\r
1762 //\r
1763 if (( !EFI_ERROR ( Status ))\r
1764 && ( NULL != pSocket->pApi->pfnConnectStart )) {\r
1765 //\r
1766 // Initiate the connection with the remote system\r
1767 //\r
1768 Status = pSocket->pApi->pfnConnectStart ( pSocket );\r
1769\r
1770 //\r
1771 // Set the next state if connecting\r
1772 //\r
1773 if ( EFI_NOT_READY == Status ) {\r
1774 pSocket->State = SOCKET_STATE_CONNECTING;\r
1775 }\r
1776 }\r
1777 }\r
d7ce7006 1778 }\r
a88c3163 1779 }\r
1780 else {\r
1781 DEBUG (( DEBUG_CONNECT,\r
1782 "ERROR - Invalid address length: %d\r\n",\r
1783 SockAddrLength ));\r
1784 Status = EFI_INVALID_PARAMETER;\r
1785 pSocket->errno = EINVAL;\r
d7ce7006 1786 }\r
1787 break;\r
1788\r
1789 case SOCKET_STATE_CONNECTING:\r
1790 //\r
a88c3163 1791 // Poll for connection completion\r
d7ce7006 1792 //\r
a88c3163 1793 if ( NULL == pSocket->pApi->pfnConnectPoll ) {\r
d7ce7006 1794 //\r
a88c3163 1795 // Already connected\r
d7ce7006 1796 //\r
a88c3163 1797 pSocket->errno = EISCONN;\r
1798 Status = EFI_ALREADY_STARTED;\r
1799 }\r
1800 else {\r
1801 Status = pSocket->pApi->pfnConnectPoll ( pSocket );\r
d7ce7006 1802\r
a88c3163 1803 //\r
1804 // Set the next state if connected\r
1805 //\r
1806 if ( EFI_NOT_READY != Status ) {\r
1807 if ( !EFI_ERROR ( Status )) {\r
1808 pSocket->State = SOCKET_STATE_CONNECTED;\r
3bdf9aae 1809\r
1810 //\r
1811 // Start the receive operations\r
1812 //\r
1813 EslSocketRxStart ( pSocket->pPortList );\r
a88c3163 1814 }\r
1815 else {\r
1816 pSocket->State = SOCKET_STATE_BOUND;\r
d7ce7006 1817 }\r
d7ce7006 1818 }\r
d7ce7006 1819 }\r
1820 break;\r
1821\r
1822 case SOCKET_STATE_CONNECTED:\r
1823 //\r
1824 // Already connected\r
1825 //\r
1826 pSocket->errno = EISCONN;\r
1827 Status = EFI_ALREADY_STARTED;\r
1828 break;\r
1829 }\r
1830\r
1831 //\r
1832 // Release the socket layer synchronization\r
1833 //\r
1834 RESTORE_TPL ( TplPrevious );\r
1835 }\r
1836 }\r
1837\r
1838 //\r
1839 // Return the operation status\r
1840 //\r
1841 if ( NULL != pErrno ) {\r
1842 if ( NULL != pSocket ) {\r
1843 *pErrno = pSocket->errno;\r
1844 }\r
a88c3163 1845 else {\r
d7ce7006 1846 //\r
1847 // Bad socket protocol\r
1848 //\r
1849 DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,\r
1850 "ERROR - pSocketProtocol invalid!\r\n" ));\r
1851 Status = EFI_INVALID_PARAMETER;\r
a88c3163 1852 *pErrno = ENOTSOCK;\r
d7ce7006 1853 }\r
1854 }\r
1855\r
1856 //\r
1857 // Return the operation status\r
1858 //\r
1859 DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));\r
1860 return Status;\r
1861}\r
1862\r
1863\r
1864/**\r
a88c3163 1865 Copy a fragmented buffer into a destination buffer.\r
d7ce7006 1866\r
a88c3163 1867 This support routine copies a fragmented buffer to the caller specified buffer.\r
d7ce7006 1868\r
a88c3163 1869 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.\r
d7ce7006 1870\r
a88c3163 1871 @param [in] FragmentCount Number of fragments in the table\r
d7ce7006 1872\r
a88c3163 1873 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure\r
d7ce7006 1874\r
a88c3163 1875 @param [in] BufferLength Length of the the buffer\r
d7ce7006 1876\r
a88c3163 1877 @param [in] pBuffer Address of a buffer to receive the data.\r
d7ce7006 1878\r
a88c3163 1879 @param [in] pDataLength Number of received data bytes in the buffer.\r
d7ce7006 1880\r
a88c3163 1881 @return Returns the address of the next free byte in the buffer.\r
d7ce7006 1882\r
1883**/\r
a88c3163 1884UINT8 *\r
1885EslSocketCopyFragmentedBuffer (\r
1886 IN UINT32 FragmentCount,\r
1887 IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,\r
1888 IN size_t BufferLength,\r
1889 IN UINT8 * pBuffer,\r
1890 OUT size_t * pDataLength\r
d7ce7006 1891 )\r
1892{\r
a88c3163 1893 size_t BytesToCopy;\r
1894 UINT32 Fragment;\r
1895 UINT8 * pBufferEnd;\r
1896 UINT8 * pData;\r
d7ce7006 1897\r
1898 DBG_ENTER ( );\r
1899\r
1900 //\r
a88c3163 1901 // Validate the IP and UDP structures are identical\r
d7ce7006 1902 //\r
a88c3163 1903 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )\r
1904 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));\r
1905 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )\r
1906 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));\r
d7ce7006 1907\r
a88c3163 1908 //\r
1909 // Copy the received data\r
1910 //\r
1911 Fragment = 0;\r
1912 pBufferEnd = &pBuffer [ BufferLength ];\r
1913 while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {\r
d7ce7006 1914 //\r
a88c3163 1915 // Determine the amount of received data\r
d7ce7006 1916 //\r
a88c3163 1917 pData = pFragmentTable[Fragment].FragmentBuffer;\r
1918 BytesToCopy = pFragmentTable[Fragment].FragmentLength;\r
1919 if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {\r
1920 BytesToCopy = pBufferEnd - pBuffer;\r
d7ce7006 1921 }\r
1922\r
1923 //\r
a88c3163 1924 // Move the data into the buffer\r
d7ce7006 1925 //\r
a88c3163 1926 DEBUG (( DEBUG_RX,\r
1927 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",\r
1928 pData,\r
1929 pBuffer,\r
1930 BytesToCopy ));\r
1931 CopyMem ( pBuffer, pData, BytesToCopy );\r
1932 pBuffer += BytesToCopy;\r
1933 Fragment += 1;\r
d7ce7006 1934 }\r
1935\r
1936 //\r
a88c3163 1937 // Return the data length and the buffer address\r
d7ce7006 1938 //\r
a88c3163 1939 *pDataLength = BufferLength - ( pBufferEnd - pBuffer );\r
1940 DBG_EXIT_HEX ( pBuffer );\r
1941 return pBuffer;\r
d7ce7006 1942}\r
1943\r
1944\r
1945/**\r
1946 Get the local address.\r
1947\r
a88c3163 1948 This routine calls the network specific layer to get the network\r
1949 address of the local host connection point.\r
1950\r
1951 The ::getsockname routine calls this routine to obtain the network\r
1952 address associated with the local host connection point.\r
1953\r
1954 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
d7ce7006 1955 \r
1956 @param [out] pAddress Network address to receive the local system address\r
1957\r
1958 @param [in,out] pAddressLength Length of the local network address structure\r
1959\r
1960 @param [out] pErrno Address to receive the errno value upon completion.\r
1961\r
1962 @retval EFI_SUCCESS - Local address successfully returned\r
1963\r
1964 **/\r
1965EFI_STATUS\r
1966EslSocketGetLocalAddress (\r
1967 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
1968 OUT struct sockaddr * pAddress,\r
1969 IN OUT socklen_t * pAddressLength,\r
1970 IN int * pErrno\r
1971 )\r
1972{\r
a88c3163 1973 socklen_t LengthInBytes;\r
1974 ESL_PORT * pPort;\r
1975 ESL_SOCKET * pSocket;\r
d7ce7006 1976 EFI_STATUS Status;\r
1977 EFI_TPL TplPrevious;\r
1978 \r
1979 DBG_ENTER ( );\r
1980 \r
1981 //\r
1982 // Assume success\r
1983 //\r
1984 Status = EFI_SUCCESS;\r
1985 \r
1986 //\r
1987 // Validate the socket\r
1988 //\r
1989 pSocket = NULL;\r
1990 if ( NULL != pSocketProtocol ) {\r
1991 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
1992\r
1993 //\r
a88c3163 1994 // Verify the socket state\r
d7ce7006 1995 //\r
a88c3163 1996 Status = EslSocketIsConfigured ( pSocket );\r
1997 if ( !EFI_ERROR ( Status )) {\r
d7ce7006 1998 //\r
a88c3163 1999 // Verify the address buffer and length address\r
d7ce7006 2000 //\r
a88c3163 2001 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
d7ce7006 2002 //\r
a88c3163 2003 // Verify the socket state\r
d7ce7006 2004 //\r
3bdf9aae 2005 if (( SOCKET_STATE_CONNECTED == pSocket->State )\r
2006 || ( SOCKET_STATE_LISTENING == pSocket->State )) {\r
d7ce7006 2007 //\r
a88c3163 2008 // Verify the API\r
d7ce7006 2009 //\r
a88c3163 2010 if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {\r
2011 Status = EFI_UNSUPPORTED;\r
2012 pSocket->errno = ENOTSUP;\r
2013 }\r
2014 else {\r
d7ce7006 2015 //\r
a88c3163 2016 // Synchronize with the socket layer\r
d7ce7006 2017 //\r
a88c3163 2018 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
d7ce7006 2019\r
d7ce7006 2020 //\r
a88c3163 2021 // Verify that there is just a single connection\r
d7ce7006 2022 //\r
a88c3163 2023 pPort = pSocket->pPortList;\r
2024 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
2025 //\r
2026 // Verify the address length\r
2027 //\r
2028 LengthInBytes = pSocket->pApi->AddressLength;\r
2029 if (( LengthInBytes <= *pAddressLength ) \r
2030 && ( 255 >= LengthInBytes )) {\r
2031 //\r
2032 // Return the local address and address length\r
2033 //\r
2034 ZeroMem ( pAddress, LengthInBytes );\r
2035 pAddress->sa_len = (uint8_t)LengthInBytes;\r
2036 *pAddressLength = pAddress->sa_len;\r
2037 pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );\r
2038 pSocket->errno = 0;\r
2039 Status = EFI_SUCCESS;\r
2040 }\r
2041 else {\r
2042 pSocket->errno = EINVAL;\r
2043 Status = EFI_INVALID_PARAMETER;\r
2044 }\r
2045 }\r
2046 else {\r
2047 pSocket->errno = ENOTCONN;\r
2048 Status = EFI_NOT_STARTED;\r
2049 }\r
2050 \r
2051 //\r
2052 // Release the socket layer synchronization\r
2053 //\r
2054 RESTORE_TPL ( TplPrevious );\r
d7ce7006 2055 }\r
d7ce7006 2056 }\r
a88c3163 2057 else {\r
2058 pSocket->errno = ENOTCONN;\r
2059 Status = EFI_NOT_STARTED;\r
2060 }\r
d7ce7006 2061 }\r
2062 else {\r
a88c3163 2063 pSocket->errno = EINVAL;\r
2064 Status = EFI_INVALID_PARAMETER;\r
d7ce7006 2065 }\r
2066 }\r
d7ce7006 2067 }\r
2068 \r
2069 //\r
2070 // Return the operation status\r
2071 //\r
2072 if ( NULL != pErrno ) {\r
2073 if ( NULL != pSocket ) {\r
2074 *pErrno = pSocket->errno;\r
2075 }\r
a88c3163 2076 else {\r
d7ce7006 2077 Status = EFI_INVALID_PARAMETER;\r
a88c3163 2078 *pErrno = ENOTSOCK;\r
d7ce7006 2079 }\r
2080 }\r
2081 DBG_EXIT_STATUS ( Status );\r
2082 return Status;\r
2083}\r
2084\r
2085\r
2086/**\r
2087 Get the peer address.\r
2088\r
a88c3163 2089 This routine calls the network specific layer to get the remote\r
2090 system connection point.\r
2091\r
2092 The ::getpeername routine calls this routine to obtain the network\r
2093 address of the remote connection point.\r
2094\r
2095 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
d7ce7006 2096 \r
2097 @param [out] pAddress Network address to receive the remote system address\r
2098\r
2099 @param [in,out] pAddressLength Length of the remote network address structure\r
2100\r
2101 @param [out] pErrno Address to receive the errno value upon completion.\r
2102\r
2103 @retval EFI_SUCCESS - Remote address successfully returned\r
2104\r
2105 **/\r
2106EFI_STATUS\r
2107EslSocketGetPeerAddress (\r
2108 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2109 OUT struct sockaddr * pAddress,\r
2110 IN OUT socklen_t * pAddressLength,\r
2111 IN int * pErrno\r
2112 )\r
2113{\r
a88c3163 2114 socklen_t LengthInBytes;\r
2115 ESL_PORT * pPort;\r
2116 ESL_SOCKET * pSocket;\r
d7ce7006 2117 EFI_STATUS Status;\r
2118 EFI_TPL TplPrevious;\r
2119 \r
2120 DBG_ENTER ( );\r
2121 \r
2122 //\r
2123 // Assume success\r
2124 //\r
2125 Status = EFI_SUCCESS;\r
2126 \r
2127 //\r
2128 // Validate the socket\r
2129 //\r
2130 pSocket = NULL;\r
2131 if ( NULL != pSocketProtocol ) {\r
2132 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2133\r
2134 //\r
a88c3163 2135 // Verify the socket state\r
d7ce7006 2136 //\r
a88c3163 2137 Status = EslSocketIsConfigured ( pSocket );\r
2138 if ( !EFI_ERROR ( Status )) {\r
d7ce7006 2139 //\r
a88c3163 2140 // Verify the API\r
d7ce7006 2141 //\r
a88c3163 2142 if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {\r
2143 Status = EFI_UNSUPPORTED;\r
2144 pSocket->errno = ENOTSUP;\r
2145 }\r
2146 else {\r
d7ce7006 2147 //\r
a88c3163 2148 // Verify the address buffer and length address\r
d7ce7006 2149 //\r
a88c3163 2150 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
d7ce7006 2151 //\r
a88c3163 2152 // Verify the socket state\r
d7ce7006 2153 //\r
a88c3163 2154 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
2155 //\r
2156 // Synchronize with the socket layer\r
2157 //\r
2158 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
d7ce7006 2159\r
d7ce7006 2160 //\r
a88c3163 2161 // Verify that there is just a single connection\r
d7ce7006 2162 //\r
a88c3163 2163 pPort = pSocket->pPortList;\r
2164 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
2165 //\r
2166 // Verify the address length\r
2167 //\r
2168 LengthInBytes = pSocket->pApi->AddressLength;\r
2169 if ( LengthInBytes <= *pAddressLength ) {\r
2170 //\r
2171 // Return the local address\r
2172 //\r
2173 ZeroMem ( pAddress, LengthInBytes );\r
2174 pAddress->sa_len = (uint8_t)LengthInBytes;\r
2175 *pAddressLength = pAddress->sa_len;\r
2176 pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );\r
2177 pSocket->errno = 0;\r
2178 Status = EFI_SUCCESS;\r
2179 }\r
2180 else {\r
2181 pSocket->errno = EINVAL;\r
2182 Status = EFI_INVALID_PARAMETER;\r
2183 }\r
2184 }\r
2185 else {\r
2186 pSocket->errno = ENOTCONN;\r
2187 Status = EFI_NOT_STARTED;\r
2188 }\r
d7ce7006 2189\r
d7ce7006 2190 //\r
a88c3163 2191 // Release the socket layer synchronization\r
d7ce7006 2192 //\r
a88c3163 2193 RESTORE_TPL ( TplPrevious );\r
2194 }\r
2195 else {\r
2196 pSocket->errno = ENOTCONN;\r
2197 Status = EFI_NOT_STARTED;\r
d7ce7006 2198 }\r
d7ce7006 2199 }\r
a88c3163 2200 else {\r
2201 pSocket->errno = EINVAL;\r
2202 Status = EFI_INVALID_PARAMETER;\r
2203 }\r
d7ce7006 2204 }\r
2205 }\r
d7ce7006 2206 }\r
a88c3163 2207\r
d7ce7006 2208 //\r
2209 // Return the operation status\r
2210 //\r
2211 if ( NULL != pErrno ) {\r
2212 if ( NULL != pSocket ) {\r
2213 *pErrno = pSocket->errno;\r
2214 }\r
a88c3163 2215 else {\r
d7ce7006 2216 Status = EFI_INVALID_PARAMETER;\r
a88c3163 2217 *pErrno = ENOTSOCK;\r
d7ce7006 2218 }\r
2219 }\r
2220 DBG_EXIT_STATUS ( Status );\r
2221 return Status;\r
2222}\r
2223\r
2224\r
2225/**\r
a88c3163 2226 Free the ESL_IO_MGMT event and structure\r
d7ce7006 2227\r
a88c3163 2228 This support routine walks the free list to close the event in\r
2229 the ESL_IO_MGMT structure and remove the structure from the free\r
2230 list.\r
d7ce7006 2231\r
a88c3163 2232 See the \ref TransmitEngine section.\r
d7ce7006 2233\r
a88c3163 2234 @param [in] pPort Address of an ::ESL_PORT structure\r
2235 @param [in] ppFreeQueue Address of the free queue head\r
2236 @param [in] DebugFlags Flags for debug messages\r
2237 @param [in] pEventName Zero terminated string containing the event name\r
d7ce7006 2238\r
a88c3163 2239 @retval EFI_SUCCESS - The structures were properly initialized\r
d7ce7006 2240\r
2241**/\r
2242EFI_STATUS\r
a88c3163 2243EslSocketIoFree (\r
2244 IN ESL_PORT * pPort,\r
2245 IN ESL_IO_MGMT ** ppFreeQueue,\r
2246 IN UINTN DebugFlags,\r
2247 IN CHAR8 * pEventName\r
d7ce7006 2248 )\r
2249{\r
a88c3163 2250 UINT8 * pBuffer;\r
2251 EFI_EVENT * pEvent;\r
2252 ESL_IO_MGMT * pIo;\r
2253 ESL_SOCKET * pSocket;\r
d7ce7006 2254 EFI_STATUS Status;\r
d7ce7006 2255\r
2256 DBG_ENTER ( );\r
2257\r
2258 //\r
2259 // Assume success\r
2260 //\r
2261 Status = EFI_SUCCESS;\r
2262\r
2263 //\r
a88c3163 2264 // Walk the list of IO structures\r
d7ce7006 2265 //\r
a88c3163 2266 pSocket = pPort->pSocket;\r
2267 while ( *ppFreeQueue ) {\r
d7ce7006 2268 //\r
a88c3163 2269 // Free the event for this structure\r
d7ce7006 2270 //\r
a88c3163 2271 pIo = *ppFreeQueue;\r
2272 pBuffer = (UINT8 *)pIo;\r
2273 pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];\r
2274 pEvent = (EFI_EVENT *)pBuffer;\r
2275 Status = gBS->CloseEvent ( *pEvent );\r
2276 if ( EFI_ERROR ( Status )) {\r
2277 DEBUG (( DEBUG_ERROR | DebugFlags,\r
2278 "ERROR - Failed to close the %a event, Status: %r\r\n",\r
2279 pEventName,\r
2280 Status ));\r
2281 pSocket->errno = ENOMEM;\r
2282 break;\r
2283 }\r
2284 DEBUG (( DebugFlags,\r
2285 "0x%08x: Closed %a event 0x%08x\r\n",\r
2286 pIo,\r
2287 pEventName,\r
2288 *pEvent ));\r
d7ce7006 2289\r
2290 //\r
a88c3163 2291 // Remove this structure from the queue\r
d7ce7006 2292 //\r
a88c3163 2293 *ppFreeQueue = pIo->pNext;\r
d7ce7006 2294 }\r
2295\r
2296 //\r
2297 // Return the operation status\r
2298 //\r
d7ce7006 2299 DBG_EXIT_STATUS ( Status );\r
2300 return Status;\r
2301}\r
2302\r
2303\r
2304/**\r
a88c3163 2305 Initialize the ESL_IO_MGMT structures\r
d7ce7006 2306\r
a88c3163 2307 This support routine initializes the ESL_IO_MGMT structure and\r
2308 places them on to a free list.\r
d7ce7006 2309\r
a88c3163 2310 This routine is called by ::EslSocketPortAllocate routines to prepare\r
2311 the transmit engines. See the \ref TransmitEngine section.\r
d7ce7006 2312\r
a88c3163 2313 @param [in] pPort Address of an ::ESL_PORT structure\r
2314 @param [in, out] ppIo Address containing the first structure address. Upon\r
2315 return this buffer contains the next structure address.\r
2316 @param [in] TokenCount Number of structures to initialize\r
2317 @param [in] ppFreeQueue Address of the free queue head\r
2318 @param [in] DebugFlags Flags for debug messages\r
2319 @param [in] pEventName Zero terminated string containing the event name\r
2320 @param [in] pfnCompletion Completion routine address\r
d7ce7006 2321\r
a88c3163 2322 @retval EFI_SUCCESS - The structures were properly initialized\r
2323\r
2324**/\r
d7ce7006 2325EFI_STATUS\r
a88c3163 2326EslSocketIoInit (\r
2327 IN ESL_PORT * pPort,\r
2328 IN ESL_IO_MGMT ** ppIo,\r
2329 IN UINTN TokenCount,\r
2330 IN ESL_IO_MGMT ** ppFreeQueue,\r
2331 IN UINTN DebugFlags,\r
2332 IN CHAR8 * pEventName,\r
58081f2c 2333 IN PFN_API_IO_COMPLETE pfnCompletion\r
d7ce7006 2334 )\r
2335{\r
a88c3163 2336 ESL_IO_MGMT * pEnd;\r
2337 EFI_EVENT * pEvent;\r
2338 ESL_IO_MGMT * pIo;\r
2339 ESL_SOCKET * pSocket;\r
d7ce7006 2340 EFI_STATUS Status;\r
2341\r
2342 DBG_ENTER ( );\r
2343\r
2344 //\r
a88c3163 2345 // Assume success\r
d7ce7006 2346 //\r
a88c3163 2347 Status = EFI_SUCCESS;\r
d7ce7006 2348\r
2349 //\r
a88c3163 2350 // Walk the list of IO structures\r
d7ce7006 2351 //\r
a88c3163 2352 pSocket = pPort->pSocket;\r
2353 pIo = *ppIo;\r
2354 pEnd = &pIo [ TokenCount ];\r
2355 while ( pEnd > pIo ) {\r
2356 //\r
2357 // Initialize the IO structure\r
2358 //\r
2359 pIo->pPort = pPort;\r
2360 pIo->pPacket = NULL;\r
d7ce7006 2361\r
a88c3163 2362 //\r
2363 // Allocate the event for this structure\r
2364 //\r
2365 pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);\r
2366 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
2367 TPL_SOCKETS,\r
2368 (EFI_EVENT_NOTIFY)pfnCompletion,\r
2369 pIo,\r
2370 pEvent );\r
2371 if ( EFI_ERROR ( Status )) {\r
2372 DEBUG (( DEBUG_ERROR | DebugFlags,\r
2373 "ERROR - Failed to create the %a event, Status: %r\r\n",\r
2374 pEventName,\r
2375 Status ));\r
2376 pSocket->errno = ENOMEM;\r
d7ce7006 2377 break;\r
2378 }\r
a88c3163 2379 DEBUG (( DebugFlags,\r
2380 "0x%08x: Created %a event 0x%08x\r\n",\r
2381 pIo,\r
2382 pEventName,\r
2383 *pEvent ));\r
d7ce7006 2384\r
2385 //\r
a88c3163 2386 // Add this structure to the queue\r
d7ce7006 2387 //\r
a88c3163 2388 pIo->pNext = *ppFreeQueue;\r
2389 *ppFreeQueue = pIo;\r
d7ce7006 2390\r
2391 //\r
a88c3163 2392 // Set the next structure\r
d7ce7006 2393 //\r
a88c3163 2394 pIo += 1;\r
2395 }\r
2396\r
2397 //\r
2398 // Save the next structure\r
2399 //\r
2400 *ppIo = pIo;\r
2401\r
2402 //\r
2403 // Return the operation status\r
2404 //\r
2405 DBG_EXIT_STATUS ( Status );\r
2406 return Status;\r
2407}\r
2408\r
2409\r
2410/**\r
2411 Determine if the socket is configured\r
2412\r
2413 This support routine is called to determine if the socket if the\r
2414 configuration call was made to the network layer. The following\r
2415 routines call this routine to verify that they may be successful\r
2416 in their operations:\r
2417 <ul>\r
2418 <li>::EslSocketGetLocalAddress</li>\r
2419 <li>::EslSocketGetPeerAddress</li>\r
2420 <li>::EslSocketPoll</li>\r
2421 <li>::EslSocketReceive</li>\r
2422 <li>::EslSocketTransmit</li>\r
2423 </ul>\r
2424\r
2425 @param [in] pSocket Address of an ::ESL_SOCKET structure\r
2426\r
2427 @retval EFI_SUCCESS - The socket is configured\r
2428\r
2429**/\r
2430EFI_STATUS\r
2431EslSocketIsConfigured (\r
2432 IN ESL_SOCKET * pSocket\r
2433 )\r
2434{\r
2435 EFI_STATUS Status;\r
2436 EFI_TPL TplPrevious;\r
2437\r
2438 //\r
2439 // Assume success\r
2440 //\r
2441 Status = EFI_SUCCESS;\r
2442\r
2443 //\r
2444 // Verify the socket state\r
2445 //\r
2446 if ( !pSocket->bConfigured ) {\r
2447 DBG_ENTER ( );\r
2448\r
2449 //\r
2450 // Verify the API\r
2451 //\r
2452 if ( NULL == pSocket->pApi->pfnIsConfigured ) {\r
2453 Status = EFI_UNSUPPORTED;\r
2454 pSocket->errno = ENOTSUP;\r
2455 }\r
2456 else {\r
2457 //\r
2458 // Synchronize with the socket layer\r
2459 //\r
2460 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2461\r
2462 //\r
2463 // Determine if the socket is configured\r
2464 //\r
2465 Status = pSocket->pApi->pfnIsConfigured ( pSocket );\r
2466\r
2467 //\r
2468 // Release the socket layer synchronization\r
2469 //\r
2470 RESTORE_TPL ( TplPrevious );\r
2471\r
2472 //\r
2473 // Set errno if a failure occurs\r
2474 //\r
2475 if ( EFI_ERROR ( Status )) {\r
2476 pSocket->errno = EADDRNOTAVAIL;\r
2477 }\r
2478 }\r
2479\r
2480 DBG_EXIT_STATUS ( Status );\r
2481 }\r
2482\r
2483 //\r
2484 // Return the configuration status\r
2485 //\r
2486 return Status;\r
2487}\r
2488\r
2489\r
2490/**\r
2491 Establish the known port to listen for network connections.\r
2492\r
2493 This routine calls into the network protocol layer to establish\r
2494 a handler that is called upon connection completion. The handler\r
2495 is responsible for inserting the connection into the FIFO.\r
2496\r
2497 The ::listen routine indirectly calls this routine to place the\r
2498 socket into a state that enables connection attempts. Connections\r
2499 are placed in a FIFO that is serviced by the application. The\r
2500 application calls the ::accept (::EslSocketAccept) routine to\r
2501 remove the next connection from the FIFO and get the associated\r
2502 socket and address.\r
2503\r
2504 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
2505\r
2506 @param [in] Backlog Backlog specifies the maximum FIFO depth for\r
2507 the connections waiting for the application\r
2508 to call accept. Connection attempts received\r
2509 while the queue is full are refused.\r
2510\r
2511 @param [out] pErrno Address to receive the errno value upon completion.\r
2512\r
2513 @retval EFI_SUCCESS - Socket successfully created\r
2514 @retval Other - Failed to enable the socket for listen\r
2515\r
2516**/\r
2517EFI_STATUS\r
2518EslSocketListen (\r
2519 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2520 IN INT32 Backlog,\r
2521 OUT int * pErrno\r
2522 )\r
2523{\r
2524 ESL_SOCKET * pSocket;\r
2525 EFI_STATUS Status;\r
2526 EFI_STATUS TempStatus;\r
2527 EFI_TPL TplPrevious;\r
2528\r
2529 DBG_ENTER ( );\r
2530\r
2531 //\r
2532 // Assume success\r
2533 //\r
2534 Status = EFI_SUCCESS;\r
2535\r
2536 //\r
2537 // Validate the socket\r
2538 //\r
2539 pSocket = NULL;\r
2540 if ( NULL != pSocketProtocol ) {\r
2541 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2542\r
2543 //\r
2544 // Verify the API\r
2545 //\r
2546 if ( NULL == pSocket->pApi->pfnListen ) {\r
2547 Status = EFI_UNSUPPORTED;\r
2548 pSocket->errno = ENOTSUP;\r
2549 }\r
2550 else {\r
2551 //\r
2552 // Assume success\r
2553 //\r
2554 pSocket->Status = EFI_SUCCESS;\r
2555 pSocket->errno = 0;\r
2556\r
2557 //\r
2558 // Verify that the bind operation was successful\r
2559 //\r
2560 if ( SOCKET_STATE_BOUND == pSocket->State ) {\r
2561 //\r
2562 // Synchronize with the socket layer\r
2563 //\r
2564 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2565\r
2566 //\r
2567 // Create the event for SocketAccept completion\r
2568 //\r
2569 Status = gBS->CreateEvent ( 0,\r
28de8255 2570 TPL_SOCKETS,\r
a88c3163 2571 NULL,\r
2572 NULL,\r
2573 &pSocket->WaitAccept );\r
2574 if ( !EFI_ERROR ( Status )) {\r
2575 DEBUG (( DEBUG_POOL,\r
2576 "0x%08x: Created WaitAccept event\r\n",\r
2577 pSocket->WaitAccept ));\r
2578 //\r
2579 // Set the maximum FIFO depth\r
2580 //\r
2581 if ( 0 >= Backlog ) {\r
2582 Backlog = MAX_PENDING_CONNECTIONS;\r
2583 }\r
2584 else {\r
2585 if ( SOMAXCONN < Backlog ) {\r
2586 Backlog = SOMAXCONN;\r
2587 }\r
2588 else {\r
2589 pSocket->MaxFifoDepth = Backlog;\r
2590 }\r
2591 }\r
2592\r
2593 //\r
2594 // Initiate the connection attempt listen\r
2595 //\r
2596 Status = pSocket->pApi->pfnListen ( pSocket );\r
2597\r
2598 //\r
2599 // Place the socket in the listen state if successful\r
2600 //\r
2601 if ( !EFI_ERROR ( Status )) {\r
2602 pSocket->State = SOCKET_STATE_LISTENING;\r
2603 pSocket->bListenCalled = TRUE;\r
2604 }\r
2605 else {\r
2606 //\r
2607 // Not waiting for SocketAccept to complete\r
2608 //\r
2609 TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );\r
2610 if ( !EFI_ERROR ( TempStatus )) {\r
2611 DEBUG (( DEBUG_POOL,\r
2612 "0x%08x: Closed WaitAccept event\r\n",\r
2613 pSocket->WaitAccept ));\r
2614 pSocket->WaitAccept = NULL;\r
2615 }\r
2616 else {\r
2617 DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
2618 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",\r
2619 TempStatus ));\r
2620 ASSERT ( EFI_SUCCESS == TempStatus );\r
2621 }\r
2622 }\r
2623 }\r
2624 else {\r
2625 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
2626 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",\r
2627 Status ));\r
2628 pSocket->errno = ENOMEM;\r
2629 }\r
2630\r
2631 //\r
2632 // Release the socket layer synchronization\r
2633 //\r
2634 RESTORE_TPL ( TplPrevious );\r
2635 }\r
2636 else {\r
2637 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
2638 "ERROR - Bind operation must be performed first!\r\n" ));\r
2639 pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ\r
2640 : EINVAL;\r
2641 Status = EFI_NO_MAPPING;\r
d7ce7006 2642 }\r
d7ce7006 2643 }\r
2644 }\r
2645\r
2646 //\r
2647 // Return the operation status\r
2648 //\r
2649 if ( NULL != pErrno ) {\r
a88c3163 2650 if ( NULL != pSocket ) {\r
2651 *pErrno = pSocket->errno;\r
2652 }\r
2653 else {\r
2654 Status = EFI_INVALID_PARAMETER;\r
2655 *pErrno = ENOTSOCK;\r
2656 }\r
d7ce7006 2657 }\r
2658 DBG_EXIT_STATUS ( Status );\r
2659 return Status;\r
2660}\r
2661\r
2662\r
2663/**\r
a88c3163 2664 Get the socket options\r
d7ce7006 2665\r
a88c3163 2666 This routine handles the socket level options and passes the\r
2667 others to the network specific layer.\r
d7ce7006 2668\r
a88c3163 2669 The ::getsockopt routine calls this routine to retrieve the\r
2670 socket options one at a time by name.\r
2671\r
2672 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
2673 @param [in] level Option protocol level\r
2674 @param [in] OptionName Name of the option\r
2675 @param [out] pOptionValue Buffer to receive the option value\r
2676 @param [in,out] pOptionLength Length of the buffer in bytes,\r
2677 upon return length of the option value in bytes\r
2678 @param [out] pErrno Address to receive the errno value upon completion.\r
d7ce7006 2679\r
2680 @retval EFI_SUCCESS - Socket data successfully received\r
2681\r
2682 **/\r
2683EFI_STATUS\r
a88c3163 2684EslSocketOptionGet (\r
d7ce7006 2685 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2686 IN int level,\r
2687 IN int OptionName,\r
a88c3163 2688 OUT void * __restrict pOptionValue,\r
2689 IN OUT socklen_t * __restrict pOptionLength,\r
d7ce7006 2690 IN int * pErrno\r
2691 )\r
2692{\r
2693 int errno;\r
2694 socklen_t LengthInBytes;\r
a88c3163 2695 socklen_t MaxBytes;\r
58081f2c 2696 CONST UINT8 * pOptionData;\r
a88c3163 2697 ESL_SOCKET * pSocket;\r
d7ce7006 2698 EFI_STATUS Status;\r
a88c3163 2699\r
d7ce7006 2700 DBG_ENTER ( );\r
a88c3163 2701\r
d7ce7006 2702 //\r
2703 // Assume failure\r
2704 //\r
2705 errno = EINVAL;\r
2706 Status = EFI_INVALID_PARAMETER;\r
a88c3163 2707\r
d7ce7006 2708 //\r
2709 // Validate the socket\r
2710 //\r
2711 pSocket = NULL;\r
a88c3163 2712 if ( NULL == pSocketProtocol ) {\r
2713 DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));\r
2714 }\r
2715 else if ( NULL == pOptionValue ) {\r
2716 DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));\r
2717 }\r
2718 else if ( NULL == pOptionLength ) {\r
2719 DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));\r
2720 }\r
2721 else {\r
d7ce7006 2722 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2723 LengthInBytes = 0;\r
a88c3163 2724 MaxBytes = *pOptionLength;\r
d7ce7006 2725 pOptionData = NULL;\r
2726 switch ( level ) {\r
2727 default:\r
2728 //\r
a88c3163 2729 // See if the protocol will handle the option\r
d7ce7006 2730 //\r
a88c3163 2731 if ( NULL != pSocket->pApi->pfnOptionGet ) {\r
2732 if ( pSocket->pApi->DefaultProtocol == level ) {\r
2733 Status = pSocket->pApi->pfnOptionGet ( pSocket,\r
2734 OptionName,\r
58081f2c 2735 (CONST void ** __restrict)&pOptionData,\r
a88c3163 2736 &LengthInBytes );\r
2737 errno = pSocket->errno;\r
2738 break;\r
2739 }\r
2740 else {\r
2741 //\r
2742 // Protocol not supported\r
2743 //\r
2744 DEBUG (( DEBUG_OPTION,\r
2745 "ERROR - The socket does not support this protocol!\r\n" ));\r
2746 }\r
2747 }\r
2748 else {\r
2749 //\r
2750 // Protocol level not supported\r
2751 //\r
2752 DEBUG (( DEBUG_OPTION,\r
2753 "ERROR - %a does not support any options!\r\n",\r
2754 pSocket->pApi->pName ));\r
2755 }\r
2756 errno = ENOPROTOOPT;\r
2757 Status = EFI_INVALID_PARAMETER;\r
d7ce7006 2758 break;\r
a88c3163 2759\r
d7ce7006 2760 case SOL_SOCKET:\r
2761 switch ( OptionName ) {\r
2762 default:\r
2763 //\r
a88c3163 2764 // Socket option not supported\r
d7ce7006 2765 //\r
a88c3163 2766 DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));\r
2767 errno = EINVAL;\r
2768 Status = EFI_INVALID_PARAMETER;\r
d7ce7006 2769 break;\r
a88c3163 2770\r
2771 case SO_ACCEPTCONN:\r
2772 //\r
2773 // Return the listen flag\r
2774 //\r
58081f2c 2775 pOptionData = (CONST UINT8 *)&pSocket->bListenCalled;\r
a88c3163 2776 LengthInBytes = sizeof ( pSocket->bListenCalled );\r
2777 break;\r
2778\r
2779 case SO_DEBUG:\r
2780 //\r
2781 // Return the debug flags\r
2782 //\r
58081f2c 2783 pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;\r
a88c3163 2784 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
2785 break;\r
2786\r
2787 case SO_OOBINLINE:\r
2788 //\r
2789 // Return the out-of-band inline flag\r
2790 //\r
58081f2c 2791 pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;\r
a88c3163 2792 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
2793 break;\r
2794\r
d7ce7006 2795 case SO_RCVTIMEO:\r
2796 //\r
2797 // Return the receive timeout\r
2798 //\r
58081f2c 2799 pOptionData = (CONST UINT8 *)&pSocket->RxTimeout;\r
d7ce7006 2800 LengthInBytes = sizeof ( pSocket->RxTimeout );\r
2801 break;\r
a88c3163 2802 \r
d7ce7006 2803 case SO_RCVBUF:\r
2804 //\r
a88c3163 2805 // Return the maximum receive buffer size\r
d7ce7006 2806 //\r
58081f2c 2807 pOptionData = (CONST UINT8 *)&pSocket->MaxRxBuf;\r
d7ce7006 2808 LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
2809 break;\r
2810\r
2811 case SO_SNDBUF:\r
d7ce7006 2812 //\r
2813 // Return the maximum transmit buffer size\r
2814 //\r
58081f2c 2815 pOptionData = (CONST UINT8 *)&pSocket->MaxTxBuf;\r
d7ce7006 2816 LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
2817 break;\r
d7ce7006 2818\r
a88c3163 2819 case SO_TYPE:\r
2820 //\r
2821 // Return the socket type\r
2822 //\r
58081f2c 2823 pOptionData = (CONST UINT8 *)&pSocket->Type;\r
a88c3163 2824 LengthInBytes = sizeof ( pSocket->Type );\r
2825 break;\r
2826 }\r
2827 break;\r
2828 }\r
2829\r
2830 //\r
2831 // Return the option length\r
2832 //\r
2833 *pOptionLength = LengthInBytes;\r
2834\r
2835 //\r
2836 // Determine if the option is present\r
2837 //\r
2838 if ( 0 != LengthInBytes ) {\r
2839 //\r
2840 // Silently truncate the value length\r
2841 //\r
2842 if ( LengthInBytes > MaxBytes ) {\r
2843 DEBUG (( DEBUG_OPTION,\r
2844 "INFO - Truncating option from %d to %d bytes\r\n",\r
2845 LengthInBytes,\r
2846 MaxBytes ));\r
2847 LengthInBytes = MaxBytes;\r
2848 }\r
2849\r
2850 //\r
2851 // Return the value\r
2852 //\r
2853 CopyMem ( pOptionValue, pOptionData, LengthInBytes );\r
2854\r
2855 //\r
2856 // Zero fill any remaining space\r
2857 //\r
2858 if ( LengthInBytes < MaxBytes ) {\r
2859 ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );\r
2860 }\r
2861 errno = 0;\r
2862 Status = EFI_SUCCESS;\r
2863 }\r
2864 }\r
2865\r
2866 //\r
2867 // Return the operation status\r
2868 //\r
2869 if ( NULL != pErrno ) {\r
2870 *pErrno = errno;\r
2871 }\r
2872 DBG_EXIT_STATUS ( Status );\r
2873 return Status;\r
2874}\r
2875\r
2876\r
2877/**\r
2878 Set the socket options\r
2879\r
2880 This routine handles the socket level options and passes the\r
2881 others to the network specific layer.\r
2882\r
2883 The ::setsockopt routine calls this routine to adjust the socket\r
2884 options one at a time by name.\r
2885\r
2886 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
2887 @param [in] level Option protocol level\r
2888 @param [in] OptionName Name of the option\r
2889 @param [in] pOptionValue Buffer containing the option value\r
2890 @param [in] OptionLength Length of the buffer in bytes\r
2891 @param [out] pErrno Address to receive the errno value upon completion.\r
2892\r
2893 @retval EFI_SUCCESS - Option successfully set\r
2894\r
2895 **/\r
2896EFI_STATUS\r
2897EslSocketOptionSet (\r
2898 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
2899 IN int level,\r
2900 IN int OptionName,\r
2901 IN CONST void * pOptionValue,\r
2902 IN socklen_t OptionLength,\r
2903 IN int * pErrno\r
2904 )\r
2905{\r
2906 BOOLEAN bTrueFalse;\r
2907 int errno;\r
2908 socklen_t LengthInBytes;\r
2909 UINT8 * pOptionData;\r
2910 ESL_SOCKET * pSocket;\r
2911 EFI_STATUS Status;\r
2912 \r
2913 DBG_ENTER ( );\r
2914 \r
2915 //\r
2916 // Assume failure\r
2917 //\r
2918 errno = EINVAL;\r
2919 Status = EFI_INVALID_PARAMETER;\r
2920\r
2921 //\r
2922 // Validate the socket\r
2923 //\r
2924 pSocket = NULL;\r
2925 if ( NULL == pSocketProtocol ) {\r
2926 DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));\r
2927 }\r
2928 else if ( NULL == pOptionValue ) {\r
2929 DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));\r
2930 }\r
2931 else\r
2932 {\r
2933 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
2934 if ( pSocket->bRxDisable || pSocket->bTxDisable ) {\r
2935 DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));\r
2936 }\r
2937 else {\r
2938 LengthInBytes = 0;\r
2939 pOptionData = NULL;\r
2940 switch ( level ) {\r
2941 default:\r
2942 //\r
2943 // See if the protocol will handle the option\r
2944 //\r
2945 if ( NULL != pSocket->pApi->pfnOptionSet ) {\r
2946 if ( pSocket->pApi->DefaultProtocol == level ) {\r
2947 Status = pSocket->pApi->pfnOptionSet ( pSocket,\r
2948 OptionName,\r
2949 pOptionValue,\r
2950 OptionLength );\r
2951 errno = pSocket->errno;\r
2952 break;\r
2953 }\r
2954 else {\r
2955 //\r
2956 // Protocol not supported\r
2957 //\r
2958 DEBUG (( DEBUG_OPTION,\r
2959 "ERROR - The socket does not support this protocol!\r\n" ));\r
2960 }\r
2961 }\r
2962 else {\r
2963 //\r
2964 // Protocol level not supported\r
2965 //\r
2966 DEBUG (( DEBUG_OPTION,\r
2967 "ERROR - %a does not support any options!\r\n",\r
2968 pSocket->pApi->pName ));\r
2969 }\r
2970 errno = ENOPROTOOPT;\r
2971 Status = EFI_INVALID_PARAMETER;\r
2972 break;\r
2973 \r
2974 case SOL_SOCKET:\r
2975 switch ( OptionName ) {\r
2976 default:\r
2977 //\r
2978 // Option not supported\r
2979 //\r
2980 DEBUG (( DEBUG_OPTION,\r
2981 "ERROR - Sockets does not support this option!\r\n" ));\r
2982 errno = EINVAL;\r
2983 Status = EFI_INVALID_PARAMETER;\r
2984 break;\r
2985\r
2986 case SO_DEBUG:\r
2987 //\r
2988 // Set the debug flags\r
2989 //\r
2990 pOptionData = (UINT8 *)&pSocket->bOobInLine;\r
2991 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
2992 break;\r
2993\r
2994 case SO_OOBINLINE:\r
2995 pOptionData = (UINT8 *)&pSocket->bOobInLine;\r
2996 LengthInBytes = sizeof ( pSocket->bOobInLine );\r
2997\r
2998 //\r
2999 // Validate the option length\r
3000 //\r
3001 if ( sizeof ( UINT32 ) == OptionLength ) {\r
3002 //\r
3003 // Restrict the input to TRUE or FALSE\r
3004 //\r
3005 bTrueFalse = TRUE;\r
3006 if ( 0 == *(UINT32 *)pOptionValue ) {\r
3007 bTrueFalse = FALSE;\r
3008 }\r
3009 pOptionValue = &bTrueFalse;\r
3010 }\r
3011 else {\r
3012 //\r
3013 // Force an invalid option length error\r
3014 //\r
3015 OptionLength = LengthInBytes - 1;\r
3016 }\r
3017 break;\r
3018\r
3019 case SO_RCVTIMEO:\r
3020 //\r
3021 // Return the receive timeout\r
3022 //\r
3023 pOptionData = (UINT8 *)&pSocket->RxTimeout;\r
3024 LengthInBytes = sizeof ( pSocket->RxTimeout );\r
3025 break;\r
3026\r
3027 case SO_RCVBUF:\r
3028 //\r
3029 // Return the maximum receive buffer size\r
3030 //\r
3031 pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
3032 LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
3033 break;\r
3034\r
3035 case SO_SNDBUF:\r
3036 //\r
3037 // Send buffer size\r
3038 //\r
3039 //\r
3040 // Return the maximum transmit buffer size\r
3041 //\r
3042 pOptionData = (UINT8 *)&pSocket->MaxTxBuf;\r
3043 LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
3044 break;\r
3045 }\r
3046 break;\r
3047 }\r
3048\r
3049 //\r
3050 // Determine if an option was found\r
3051 //\r
3052 if ( 0 != LengthInBytes ) {\r
3053 //\r
3054 // Validate the option length\r
3055 //\r
3056 if ( LengthInBytes <= OptionLength ) {\r
3057 //\r
3058 // Set the option value\r
3059 //\r
3060 CopyMem ( pOptionData, pOptionValue, LengthInBytes );\r
3061 errno = 0;\r
3062 Status = EFI_SUCCESS;\r
3063 }\r
3064 else {\r
3065 DEBUG (( DEBUG_OPTION,\r
3066 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",\r
3067 OptionLength,\r
3068 LengthInBytes ));\r
3069 }\r
3070 }\r
3071 }\r
3072 }\r
3073\r
3074 //\r
3075 // Return the operation status\r
3076 //\r
3077 if ( NULL != pErrno ) {\r
3078 *pErrno = errno;\r
3079 }\r
3080 DBG_EXIT_STATUS ( Status );\r
3081 return Status;\r
3082}\r
3083\r
3084\r
3085/**\r
3086 Allocate a packet for a receive or transmit operation\r
3087\r
3088 This support routine is called by ::EslSocketRxStart and the\r
3089 network specific TxBuffer routines to get buffer space for the\r
3090 next operation.\r
3091\r
3092 @param [in] ppPacket Address to receive the ::ESL_PACKET structure\r
3093 @param [in] LengthInBytes Length of the packet structure\r
3094 @param [in] ZeroBytes Length of packet to zero\r
3095 @param [in] DebugFlags Flags for debug messages\r
3096\r
3097 @retval EFI_SUCCESS - The packet was allocated successfully\r
3098\r
3099 **/\r
3100EFI_STATUS\r
3101EslSocketPacketAllocate (\r
3102 IN ESL_PACKET ** ppPacket,\r
3103 IN size_t LengthInBytes,\r
3104 IN size_t ZeroBytes,\r
3105 IN UINTN DebugFlags\r
3106 )\r
3107{\r
3108 ESL_PACKET * pPacket;\r
3109 EFI_STATUS Status;\r
3110\r
3111 DBG_ENTER ( );\r
3112\r
3113 //\r
3114 // Allocate a packet structure\r
3115 //\r
3116 LengthInBytes += sizeof ( *pPacket )\r
3117 - sizeof ( pPacket->Op );\r
3118 Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
3119 LengthInBytes,\r
3120 (VOID **)&pPacket );\r
3121 if ( !EFI_ERROR ( Status )) {\r
3bdf9aae 3122 DEBUG (( DebugFlags | DEBUG_POOL,\r
a88c3163 3123 "0x%08x: Allocate pPacket, %d bytes\r\n",\r
3124 pPacket,\r
3125 LengthInBytes ));\r
3126 if ( 0 != ZeroBytes ) {\r
3127 ZeroMem ( &pPacket->Op, ZeroBytes );\r
3128 }\r
3129 pPacket->PacketSize = LengthInBytes;\r
3130 }\r
3131 else {\r
3132 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
3133 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",\r
3134 LengthInBytes,\r
3135 Status ));\r
3136 pPacket = NULL;\r
3137 }\r
3138\r
3139 //\r
3140 // Return the packet\r
3141 //\r
3142 *ppPacket = pPacket;\r
3143\r
3144 //\r
3145 // Return the operation status\r
3146 //\r
3147 DBG_EXIT_STATUS ( Status );\r
3148 return Status;\r
3149}\r
3150\r
3151\r
3152/**\r
3153 Free a packet used for receive or transmit operation\r
3154\r
3155 This support routine is called by the network specific Close\r
3156 and TxComplete routines and during error cases in RxComplete\r
3157 and TxBuffer. Note that the network layers typically place\r
3158 receive packets on the ESL_SOCKET::pRxFree list for reuse.\r
3159\r
3160 @param [in] pPacket Address of an ::ESL_PACKET structure\r
3161 @param [in] DebugFlags Flags for debug messages\r
3162\r
3163 @retval EFI_SUCCESS - The packet was allocated successfully\r
3164\r
3165 **/\r
3166EFI_STATUS\r
3167EslSocketPacketFree (\r
3168 IN ESL_PACKET * pPacket,\r
3169 IN UINTN DebugFlags\r
3170 )\r
3171{\r
3172 UINTN LengthInBytes;\r
3173 EFI_STATUS Status;\r
3174\r
3175 DBG_ENTER ( );\r
3176\r
3177 //\r
3178 // Allocate a packet structure\r
3179 //\r
3180 LengthInBytes = pPacket->PacketSize;\r
3181 Status = gBS->FreePool ( pPacket );\r
3182 if ( !EFI_ERROR ( Status )) {\r
3183 DEBUG (( DebugFlags | DEBUG_POOL,\r
3184 "0x%08x: Free pPacket, %d bytes\r\n",\r
3185 pPacket,\r
3186 LengthInBytes ));\r
3187 }\r
3188 else {\r
3189 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
3190 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",\r
3191 pPacket,\r
3192 Status ));\r
3193 }\r
3194\r
3195 //\r
3196 // Return the operation status\r
3197 //\r
3198 DBG_EXIT_STATUS ( Status );\r
3199 return Status;\r
3200}\r
3201\r
3202\r
3203/**\r
3204 Poll a socket for pending activity.\r
3205\r
3206 This routine builds a detected event mask which is returned to\r
3207 the caller in the buffer provided.\r
3208\r
3209 The ::poll routine calls this routine to determine if the socket\r
3210 needs to be serviced as a result of connection, error, receive or\r
3211 transmit activity.\r
3212\r
3213 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
3214\r
3215 @param [in] Events Events of interest for this socket\r
3216\r
3217 @param [in] pEvents Address to receive the detected events\r
3218\r
3219 @param [out] pErrno Address to receive the errno value upon completion.\r
3220\r
3221 @retval EFI_SUCCESS - Socket successfully polled\r
3222 @retval EFI_INVALID_PARAMETER - When pEvents is NULL\r
3223\r
3224 **/\r
3225EFI_STATUS\r
3226EslSocketPoll (\r
3227 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
3228 IN short Events,\r
3229 IN short * pEvents,\r
3230 IN int * pErrno\r
3231 )\r
3232{\r
3233 short DetectedEvents;\r
3234 ESL_SOCKET * pSocket;\r
3235 EFI_STATUS Status;\r
3bdf9aae 3236 EFI_TPL TplPrevious;\r
a88c3163 3237 short ValidEvents;\r
3238\r
3239 DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));\r
3240\r
3241 //\r
3242 // Assume success\r
3243 //\r
3244 Status = EFI_SUCCESS;\r
3245 DetectedEvents = 0;\r
3246 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
3247 pSocket->errno = 0;\r
3248\r
3249 //\r
3250 // Verify the socket state\r
3251 //\r
3252 Status = EslSocketIsConfigured ( pSocket );\r
3253 if ( !EFI_ERROR ( Status )) {\r
3254 //\r
3255 // Check for invalid events\r
3256 //\r
3257 ValidEvents = POLLIN\r
3258 | POLLPRI\r
3259 | POLLOUT | POLLWRNORM\r
3260 | POLLERR\r
3261 | POLLHUP\r
3262 | POLLNVAL\r
3263 | POLLRDNORM\r
3264 | POLLRDBAND\r
3265 | POLLWRBAND ;\r
3266 if ( 0 != ( Events & ( ~ValidEvents ))) {\r
3267 DetectedEvents |= POLLNVAL;\r
3268 DEBUG (( DEBUG_INFO | DEBUG_POLL,\r
3269 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",\r
3270 Events & ValidEvents,\r
3271 Events & ( ~ValidEvents )));\r
3272 }\r
3273 else {\r
3bdf9aae 3274 //\r
3275 // Synchronize with the socket layer\r
3276 //\r
3277 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
3278 \r
3279 //\r
3280 // Increase the network performance by extending the\r
3281 // polling (idle) loop down into the LAN driver\r
3282 //\r
3283 EslSocketRxPoll ( pSocket );\r
3284 \r
3285 //\r
3286 // Release the socket layer synchronization\r
3287 //\r
3288 RESTORE_TPL ( TplPrevious );\r
3289\r
a88c3163 3290 //\r
3291 // Check for pending connections\r
3292 //\r
3293 if ( 0 != pSocket->FifoDepth ) {\r
3294 //\r
3295 // A connection is waiting for an accept call\r
3296 // See posix connect documentation at\r
3297 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm\r
3298 //\r
3299 DetectedEvents |= POLLIN | POLLRDNORM;\r
3300 }\r
3301 if ( pSocket->bConnected ) {\r
3302 //\r
3303 // A connection is present\r
3304 // See posix connect documentation at\r
3305 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm\r
3306 //\r
3307 DetectedEvents |= POLLOUT | POLLWRNORM;\r
3308 }\r
3309\r
3310 //\r
3311 // The following bits are set based upon the POSIX poll documentation at\r
3312 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html\r
3313 //\r
3314\r
3315 //\r
3316 // Check for urgent receive data\r
3317 //\r
3318 if ( 0 < pSocket->RxOobBytes ) {\r
3319 DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;\r
3320 }\r
3321\r
3322 //\r
3323 // Check for normal receive data\r
3324 //\r
3325 if (( 0 < pSocket->RxBytes )\r
3326 || ( EFI_SUCCESS != pSocket->RxError )) {\r
3327 DetectedEvents |= POLLRDNORM | POLLIN;\r
3328 }\r
3329\r
3330 //\r
3331 // Handle the receive errors\r
3332 //\r
3333 if (( EFI_SUCCESS != pSocket->RxError )\r
3334 && ( 0 == ( DetectedEvents & POLLIN ))) {\r
3335 DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;\r
3336 }\r
3337\r
3338 //\r
3339 // Check for urgent transmit data buffer space\r
3340 //\r
3341 if (( MAX_TX_DATA > pSocket->TxOobBytes )\r
3342 || ( EFI_SUCCESS != pSocket->TxError )) {\r
3343 DetectedEvents |= POLLWRBAND;\r
3344 }\r
3345\r
3346 //\r
3347 // Check for normal transmit data buffer space\r
3348 //\r
3349 if (( MAX_TX_DATA > pSocket->TxBytes )\r
3350 || ( EFI_SUCCESS != pSocket->TxError )) {\r
3351 DetectedEvents |= POLLWRNORM;\r
3352 }\r
3353\r
3354 //\r
3355 // Handle the transmit error\r
3356 //\r
3357 if ( EFI_ERROR ( pSocket->TxError )) {\r
3358 DetectedEvents |= POLLERR;\r
3359 }\r
3360 }\r
3361 }\r
3362\r
3363 //\r
3364 // Return the detected events\r
3365 //\r
3366 *pEvents = DetectedEvents & ( Events\r
3367 | POLLERR\r
3368 | POLLHUP\r
3369 | POLLNVAL );\r
3370\r
3371 //\r
3372 // Return the operation status\r
3373 //\r
3374 DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));\r
3375 return Status;\r
3376}\r
3377\r
3378\r
3379/**\r
3380 Allocate and initialize a ESL_PORT structure.\r
3381\r
3382 This routine initializes an ::ESL_PORT structure for use by\r
3383 the socket. This routine calls a routine via\r
3384 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network\r
3385 specific resources. The resources are released later by the\r
3386 \ref PortCloseStateMachine.\r
3387\r
3388 This support routine is called by:\r
3389 <ul>\r
3390 <li>::EslSocketBind</li>\r
3391 <li>::EslTcp4ListenComplete</li>\r
3392 </ul>\r
3393 to connect the socket with the underlying network adapter\r
3394 to the socket.\r
3395\r
3396 @param [in] pSocket Address of an ::ESL_SOCKET structure.\r
3397 @param [in] pService Address of an ::ESL_SERVICE structure.\r
3398 @param [in] ChildHandle Network protocol child handle\r
3399 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
3400 connection point on the local machine. An IPv4 address\r
3401 of INADDR_ANY specifies that the connection is made to\r
3402 all of the network stacks on the platform. Specifying a\r
3403 specific IPv4 address restricts the connection to the\r
3404 network stack supporting that address. Specifying zero\r
3405 for the port causes the network layer to assign a port\r
3406 number from the dynamic range. Specifying a specific\r
3407 port number causes the network layer to use that port.\r
3408 @param [in] bBindTest TRUE if EslSocketBindTest should be called\r
3409 @param [in] DebugFlags Flags for debug messages\r
3410 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address\r
3411\r
3412 @retval EFI_SUCCESS - Socket successfully created\r
3413\r
3414 **/\r
3415EFI_STATUS\r
3416EslSocketPortAllocate (\r
3417 IN ESL_SOCKET * pSocket,\r
3418 IN ESL_SERVICE * pService,\r
3419 IN EFI_HANDLE ChildHandle,\r
3420 IN CONST struct sockaddr * pSockAddr,\r
3421 IN BOOLEAN bBindTest,\r
3422 IN UINTN DebugFlags,\r
3423 OUT ESL_PORT ** ppPort\r
3424 )\r
3425{\r
3426 UINTN LengthInBytes;\r
3427 UINT8 * pBuffer;\r
3428 ESL_IO_MGMT * pIo;\r
3429 ESL_LAYER * pLayer;\r
3430 ESL_PORT * pPort;\r
3431 EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
3432 CONST ESL_SOCKET_BINDING * pSocketBinding;\r
3433 EFI_STATUS Status;\r
3434 EFI_STATUS TempStatus;\r
3435\r
3436 DBG_ENTER ( );\r
3437\r
3438 //\r
3439 // Verify the socket layer synchronization\r
3440 //\r
3441 VERIFY_TPL ( TPL_SOCKETS );\r
3442\r
3443 //\r
3444 // Use for/break instead of goto\r
3445 pSocketBinding = pService->pSocketBinding;\r
3446 for ( ; ; ) {\r
3447 //\r
3448 // Allocate a port structure\r
3449 //\r
3450 pLayer = &mEslLayer;\r
3451 LengthInBytes = sizeof ( *pPort )\r
3452 + ESL_STRUCTURE_ALIGNMENT_BYTES\r
3453 + (( pSocketBinding->RxIo\r
3454 + pSocketBinding->TxIoNormal\r
3455 + pSocketBinding->TxIoUrgent )\r
3456 * sizeof ( ESL_IO_MGMT ));\r
3457 pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );\r
3458 if ( NULL == pPort ) {\r
3459 Status = EFI_OUT_OF_RESOURCES;\r
3460 pSocket->errno = ENOMEM;\r
3461 break;\r
3462 }\r
3463 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
3464 "0x%08x: Allocate pPort, %d bytes\r\n",\r
3465 pPort,\r
3466 LengthInBytes ));\r
3467\r
3468 //\r
3469 // Initialize the port\r
3470 //\r
3471 pPort->DebugFlags = DebugFlags;\r
3472 pPort->Handle = ChildHandle;\r
3473 pPort->pService = pService;\r
3474 pPort->pServiceBinding = pService->pServiceBinding;\r
3475 pPort->pSocket = pSocket;\r
3476 pPort->pSocketBinding = pService->pSocketBinding;\r
3477 pPort->Signature = PORT_SIGNATURE;\r
3478\r
3479 //\r
3480 // Open the port protocol\r
3481 //\r
3482 Status = gBS->OpenProtocol ( pPort->Handle,\r
3483 pSocketBinding->pNetworkProtocolGuid,\r
3484 &pPort->pProtocol.v,\r
3485 pLayer->ImageHandle,\r
3486 NULL,\r
3487 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );\r
3488 if ( EFI_ERROR ( Status )) {\r
3489 DEBUG (( DEBUG_ERROR | DebugFlags,\r
3490 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",\r
3491 pPort->Handle ));\r
3492 pSocket->errno = EEXIST;\r
3493 break;\r
3494 }\r
3495 DEBUG (( DebugFlags,\r
3496 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",\r
3497 pPort->pProtocol.v,\r
3498 pPort->Handle ));\r
3499\r
3500 //\r
3501 // Initialize the port specific resources\r
3502 //\r
3503 Status = pSocket->pApi->pfnPortAllocate ( pPort,\r
3504 DebugFlags );\r
3505 if ( EFI_ERROR ( Status )) {\r
3506 break;\r
3507 }\r
3508\r
3509 //\r
3510 // Set the local address\r
3511 //\r
3512 Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );\r
3513 if ( EFI_ERROR ( Status )) {\r
3514 break;\r
3515 }\r
3516\r
3517 //\r
3518 // Test the address/port configuration\r
3519 //\r
3520 if ( bBindTest ) {\r
3521 Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );\r
3522 if ( EFI_ERROR ( Status )) {\r
3523 break;\r
3524 }\r
3525 }\r
3526\r
3527 //\r
3528 // Initialize the receive structures\r
3529 //\r
3530 pBuffer = (UINT8 *)&pPort[ 1 ];\r
3531 pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];\r
3532 pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );\r
3533 pIo = (ESL_IO_MGMT *)pBuffer;\r
3534 if (( 0 != pSocketBinding->RxIo )\r
3535 && ( NULL != pSocket->pApi->pfnRxComplete )) {\r
3536 Status = EslSocketIoInit ( pPort,\r
3537 &pIo,\r
3538 pSocketBinding->RxIo,\r
3539 &pPort->pRxFree,\r
3540 DebugFlags | DEBUG_POOL,\r
3541 "receive",\r
3542 pSocket->pApi->pfnRxComplete );\r
3543 if ( EFI_ERROR ( Status )) {\r
3544 break;\r
3545 }\r
3546 }\r
3547\r
3548 //\r
3549 // Initialize the urgent transmit structures\r
3550 //\r
3551 if (( 0 != pSocketBinding->TxIoUrgent )\r
3552 && ( NULL != pSocket->pApi->pfnTxOobComplete )) {\r
3553 Status = EslSocketIoInit ( pPort,\r
3554 &pIo,\r
3555 pSocketBinding->TxIoUrgent,\r
3556 &pPort->pTxOobFree,\r
3557 DebugFlags | DEBUG_POOL,\r
3558 "urgent transmit",\r
3559 pSocket->pApi->pfnTxOobComplete );\r
3560 if ( EFI_ERROR ( Status )) {\r
3561 break;\r
3562 }\r
3563 }\r
3564\r
3565 //\r
3566 // Initialize the normal transmit structures\r
3567 //\r
3568 if (( 0 != pSocketBinding->TxIoNormal )\r
3569 && ( NULL != pSocket->pApi->pfnTxComplete )) {\r
3570 Status = EslSocketIoInit ( pPort,\r
3571 &pIo,\r
3572 pSocketBinding->TxIoNormal,\r
3573 &pPort->pTxFree,\r
3574 DebugFlags | DEBUG_POOL,\r
3575 "normal transmit",\r
3576 pSocket->pApi->pfnTxComplete );\r
3577 if ( EFI_ERROR ( Status )) {\r
3578 break;\r
3579 }\r
3580 }\r
3581\r
3582 //\r
3583 // Add this port to the socket\r
3584 //\r
3585 pPort->pLinkSocket = pSocket->pPortList;\r
3586 pSocket->pPortList = pPort;\r
3587 DEBUG (( DebugFlags,\r
3588 "0x%08x: Socket adding port: 0x%08x\r\n",\r
3589 pSocket,\r
3590 pPort ));\r
3591\r
3592 //\r
3593 // Add this port to the service\r
3594 //\r
3595 pPort->pLinkService = pService->pPortList;\r
3596 pService->pPortList = pPort;\r
3597\r
3598 //\r
3599 // Return the port\r
3600 //\r
3601 *ppPort = pPort;\r
3602 break;\r
3603 }\r
3604\r
3605 //\r
3606 // Clean up after the error if necessary\r
3607 //\r
3608 if ( EFI_ERROR ( Status )) {\r
3609 if ( NULL != pPort ) {\r
3610 //\r
3611 // Close the port\r
3612 //\r
3613 EslSocketPortClose ( pPort );\r
3614 }\r
3615 else {\r
3616 //\r
3617 // Close the port if necessary\r
3618 //\r
3619 pServiceBinding = pService->pServiceBinding;\r
3620 TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,\r
3621 ChildHandle );\r
3622 if ( !EFI_ERROR ( TempStatus )) {\r
3623 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
3624 "0x%08x: %s port handle destroyed\r\n",\r
3625 ChildHandle,\r
3626 pSocketBinding->pName ));\r
3627 }\r
3628 else {\r
3629 DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,\r
3630 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",\r
3631 pSocketBinding->pName,\r
3632 ChildHandle,\r
3633 TempStatus ));\r
3634 ASSERT ( EFI_SUCCESS == TempStatus );\r
3635 }\r
3636 }\r
3637 }\r
3638 //\r
3639 // Return the operation status\r
3640 //\r
3641 DBG_EXIT_STATUS ( Status );\r
3642 return Status;\r
3643}\r
3644\r
3645\r
3646/**\r
3647 Close a port.\r
3648\r
3649 This routine releases the resources allocated by ::EslSocketPortAllocate.\r
3650 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network\r
3651 specific resources.\r
3652\r
3653 This routine is called by:\r
3654 <ul>\r
3655 <li>::EslSocketPortAllocate - Port initialization failure</li>\r
3656 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>\r
3657 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>\r
3658 </ul>\r
3659 See the \ref PortCloseStateMachine section.\r
3660 \r
3661 @param [in] pPort Address of an ::ESL_PORT structure.\r
3662\r
3663 @retval EFI_SUCCESS The port is closed\r
3664 @retval other Port close error\r
3665\r
3666**/\r
3667EFI_STATUS\r
3668EslSocketPortClose (\r
3669 IN ESL_PORT * pPort\r
3670 )\r
3671{\r
3672 UINTN DebugFlags;\r
3673 ESL_LAYER * pLayer;\r
3674 ESL_PACKET * pPacket;\r
3675 ESL_PORT * pPreviousPort;\r
3676 ESL_SERVICE * pService;\r
3677 EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
3678 CONST ESL_SOCKET_BINDING * pSocketBinding;\r
3679 ESL_SOCKET * pSocket;\r
3680 EFI_STATUS Status;\r
3681 \r
3682 DBG_ENTER ( );\r
3683\r
3684 //\r
3685 // Verify the socket layer synchronization\r
3686 //\r
3687 VERIFY_TPL ( TPL_SOCKETS );\r
3688\r
3689 //\r
3690 // Locate the port in the socket list\r
3691 //\r
3692 Status = EFI_SUCCESS;\r
3693 pLayer = &mEslLayer;\r
3694 DebugFlags = pPort->DebugFlags;\r
3695 pSocket = pPort->pSocket;\r
3696 pPreviousPort = pSocket->pPortList;\r
3697 if ( pPreviousPort == pPort ) {\r
3698 //\r
3699 // Remove this port from the head of the socket list\r
3700 //\r
3701 pSocket->pPortList = pPort->pLinkSocket;\r
3702 }\r
3703 else {\r
3704 //\r
3705 // Locate the port in the middle of the socket list\r
3706 //\r
3707 while (( NULL != pPreviousPort )\r
3708 && ( pPreviousPort->pLinkSocket != pPort )) {\r
3709 pPreviousPort = pPreviousPort->pLinkSocket;\r
3710 }\r
3711 if ( NULL != pPreviousPort ) {\r
3712 //\r
3713 // Remove the port from the middle of the socket list\r
3714 //\r
3715 pPreviousPort->pLinkSocket = pPort->pLinkSocket;\r
3716 }\r
3717 }\r
3718\r
3719 //\r
3720 // Locate the port in the service list\r
3721 // Note that the port may not be in the service list\r
3722 // if the service has been shutdown.\r
3723 //\r
3724 pService = pPort->pService;\r
3725 if ( NULL != pService ) {\r
3726 pPreviousPort = pService->pPortList;\r
3727 if ( pPreviousPort == pPort ) {\r
3728 //\r
3729 // Remove this port from the head of the service list\r
3730 //\r
3731 pService->pPortList = pPort->pLinkService;\r
3732 }\r
3733 else {\r
3734 //\r
3735 // Locate the port in the middle of the service list\r
3736 //\r
3737 while (( NULL != pPreviousPort )\r
3738 && ( pPreviousPort->pLinkService != pPort )) {\r
3739 pPreviousPort = pPreviousPort->pLinkService;\r
3740 }\r
3741 if ( NULL != pPreviousPort ) {\r
3742 //\r
3743 // Remove the port from the middle of the service list\r
3744 //\r
3745 pPreviousPort->pLinkService = pPort->pLinkService;\r
3746 }\r
3747 }\r
3748 }\r
3749\r
3750 //\r
3751 // Empty the urgent receive queue\r
3752 //\r
3753 while ( NULL != pSocket->pRxOobPacketListHead ) {\r
3754 pPacket = pSocket->pRxOobPacketListHead;\r
3755 pSocket->pRxOobPacketListHead = pPacket->pNext;\r
3756 pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );\r
3757 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
3758 }\r
3759 pSocket->pRxOobPacketListTail = NULL;\r
3760 ASSERT ( 0 == pSocket->RxOobBytes );\r
3761\r
3762 //\r
3763 // Empty the receive queue\r
3764 //\r
3765 while ( NULL != pSocket->pRxPacketListHead ) {\r
3766 pPacket = pSocket->pRxPacketListHead;\r
3767 pSocket->pRxPacketListHead = pPacket->pNext;\r
3768 pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );\r
3769 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
3770 }\r
3771 pSocket->pRxPacketListTail = NULL;\r
3772 ASSERT ( 0 == pSocket->RxBytes );\r
3773\r
3774 //\r
3775 // Empty the receive free queue\r
3776 //\r
3777 while ( NULL != pSocket->pRxFree ) {\r
3778 pPacket = pSocket->pRxFree;\r
3779 pSocket->pRxFree = pPacket->pNext;\r
3780 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
3781 }\r
3782\r
3783 //\r
3784 // Release the network specific resources\r
3785 //\r
3786 if ( NULL != pSocket->pApi->pfnPortClose ) {\r
3787 Status = pSocket->pApi->pfnPortClose ( pPort );\r
3788 }\r
3789\r
3790 //\r
3791 // Done with the normal transmit events\r
3792 //\r
3793 Status = EslSocketIoFree ( pPort,\r
3794 &pPort->pTxFree,\r
3795 DebugFlags | DEBUG_POOL,\r
3796 "normal transmit" );\r
3797\r
3798 //\r
3799 // Done with the urgent transmit events\r
3800 //\r
3801 Status = EslSocketIoFree ( pPort,\r
3802 &pPort->pTxOobFree,\r
3803 DebugFlags | DEBUG_POOL,\r
3804 "urgent transmit" );\r
3805\r
3806 //\r
3807 // Done with the receive events\r
3808 //\r
3809 Status = EslSocketIoFree ( pPort,\r
3810 &pPort->pRxFree,\r
3811 DebugFlags | DEBUG_POOL,\r
3812 "receive" );\r
3813\r
3814 //\r
3815 // Done with the lower layer network protocol\r
3816 //\r
3817 pSocketBinding = pPort->pSocketBinding;\r
3818 if ( NULL != pPort->pProtocol.v ) {\r
3819 Status = gBS->CloseProtocol ( pPort->Handle,\r
3820 pSocketBinding->pNetworkProtocolGuid,\r
3821 pLayer->ImageHandle,\r
3822 NULL );\r
3823 if ( !EFI_ERROR ( Status )) {\r
3824 DEBUG (( DebugFlags,\r
3825 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",\r
3826 pPort->pProtocol.v,\r
3827 pPort->Handle ));\r
3828 }\r
3829 else {\r
3830 DEBUG (( DEBUG_ERROR | DebugFlags,\r
3831 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",\r
3832 pPort->Handle,\r
3833 Status ));\r
3834 ASSERT ( EFI_SUCCESS == Status );\r
3835 }\r
3836 }\r
3837\r
3838 //\r
3839 // Done with the network port\r
3840 //\r
3841 pServiceBinding = pPort->pServiceBinding;\r
3842 if ( NULL != pPort->Handle ) {\r
3843 Status = pServiceBinding->DestroyChild ( pServiceBinding,\r
3844 pPort->Handle );\r
3845 if ( !EFI_ERROR ( Status )) {\r
3846 DEBUG (( DebugFlags | DEBUG_POOL,\r
3847 "0x%08x: %s port handle destroyed\r\n",\r
3848 pPort->Handle,\r
3849 pSocketBinding->pName ));\r
3850 }\r
3851 else {\r
3852 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
3853 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",\r
3854 pSocketBinding->pName,\r
3855 Status ));\r
3856 ASSERT ( EFI_SUCCESS == Status );\r
3857 }\r
3858 }\r
3859\r
3860 //\r
3861 // Release the port structure\r
3862 //\r
3863 Status = gBS->FreePool ( pPort );\r
3864 if ( !EFI_ERROR ( Status )) {\r
3865 DEBUG (( DebugFlags | DEBUG_POOL,\r
3866 "0x%08x: Free pPort, %d bytes\r\n",\r
3867 pPort,\r
3868 sizeof ( *pPort )));\r
3869 }\r
3870 else {\r
3871 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
3872 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",\r
3873 pPort,\r
3874 Status ));\r
3875 ASSERT ( EFI_SUCCESS == Status );\r
3876 }\r
3877\r
3878 //\r
3879 // Mark the socket as closed if necessary\r
3880 //\r
3881 if ( NULL == pSocket->pPortList ) {\r
3882 pSocket->State = SOCKET_STATE_CLOSED;\r
3883 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
3884 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",\r
3885 pSocket ));\r
3886 }\r
3887\r
3888 //\r
3889 // Return the operation status\r
3890 //\r
3891 DBG_EXIT_STATUS ( Status );\r
3892 return Status;\r
3893}\r
3894\r
3895\r
3896/**\r
3897 Port close state 3\r
3898\r
3899 This routine attempts to complete the port close operation.\r
3900\r
3901 This routine is called by the TCP layer upon completion of\r
3902 the close operation and by ::EslSocketPortCloseTxDone.\r
3903 See the \ref PortCloseStateMachine section.\r
3904\r
3905 @param [in] Event The close completion event\r
3906\r
3907 @param [in] pPort Address of an ::ESL_PORT structure.\r
3908\r
3909**/\r
3910VOID\r
3911EslSocketPortCloseComplete (\r
3912 IN EFI_EVENT Event,\r
3913 IN ESL_PORT * pPort\r
3914 )\r
3915{\r
3916 ESL_IO_MGMT * pIo;\r
3917 EFI_STATUS Status;\r
3918\r
3919 DBG_ENTER ( );\r
3920 VERIFY_AT_TPL ( TPL_SOCKETS );\r
3921\r
3922 //\r
3923 // Update the port state\r
3924 //\r
3925 pPort->State = PORT_STATE_CLOSE_DONE;\r
3926 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
3927 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",\r
3928 pPort ));\r
3929\r
3930 //\r
3931 // Shutdown the receive operation on the port\r
3932 //\r
3933 if ( NULL != pPort->pfnRxCancel ) {\r
3934 pIo = pPort->pRxActive;\r
3935 while ( NULL != pIo ) {\r
3936 EslSocketRxCancel ( pPort, pIo );\r
3937 pIo = pIo->pNext;\r
d7ce7006 3938 }\r
3939 }\r
a88c3163 3940\r
d7ce7006 3941 //\r
a88c3163 3942 // Determine if the receive operation is pending\r
d7ce7006 3943 //\r
a88c3163 3944 Status = EslSocketPortCloseRxDone ( pPort );\r
d7ce7006 3945 DBG_EXIT_STATUS ( Status );\r
d7ce7006 3946}\r
3947\r
3948\r
3949/**\r
a88c3163 3950 Port close state 4\r
d7ce7006 3951\r
a88c3163 3952 This routine determines the state of the receive operations and\r
3953 continues the close operation after the pending receive operations\r
3954 are cancelled.\r
d7ce7006 3955\r
a88c3163 3956 This routine is called by\r
3957 <ul>\r
3958 <li>::EslSocketPortCloseComplete</li>\r
3959 <li>::EslSocketPortCloseTxDone</li>\r
3960 <li>::EslSocketRxComplete</li>\r
3961 </ul>\r
3962 to determine the state of the receive operations.\r
3963 See the \ref PortCloseStateMachine section.\r
d7ce7006 3964\r
a88c3163 3965 @param [in] pPort Address of an ::ESL_PORT structure.\r
3966\r
3967 @retval EFI_SUCCESS The port is closed\r
3968 @retval EFI_NOT_READY The port is still closing\r
3969 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
3970 most likely the routine was called already.\r
3971\r
3972**/\r
d7ce7006 3973EFI_STATUS\r
a88c3163 3974EslSocketPortCloseRxDone (\r
3975 IN ESL_PORT * pPort\r
d7ce7006 3976 )\r
3977{\r
d7ce7006 3978 EFI_STATUS Status;\r
3979\r
3980 DBG_ENTER ( );\r
3981\r
3982 //\r
a88c3163 3983 // Verify the socket layer synchronization\r
d7ce7006 3984 //\r
a88c3163 3985 VERIFY_TPL ( TPL_SOCKETS );\r
d7ce7006 3986\r
3987 //\r
a88c3163 3988 // Verify that the port is closing\r
d7ce7006 3989 //\r
a88c3163 3990 Status = EFI_ALREADY_STARTED;\r
3991 if ( PORT_STATE_CLOSE_DONE == pPort->State ) {\r
3992 //\r
3993 // Determine if the receive operation is pending\r
3994 //\r
3995 Status = EFI_NOT_READY;\r
3996 if ( NULL == pPort->pRxActive ) {\r
3997 //\r
3998 // The receive operation is complete\r
3999 // Update the port state\r
4000 //\r
4001 pPort->State = PORT_STATE_CLOSE_RX_DONE;\r
4002 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4003 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",\r
4004 pPort ));\r
4005\r
4006 //\r
4007 // Complete the port close operation\r
4008 //\r
4009 Status = EslSocketPortClose ( pPort );\r
4010 }\r
4011 else {\r
4012 DEBUG_CODE_BEGIN ();\r
4013 {\r
4014 ESL_IO_MGMT * pIo;\r
4015 //\r
4016 // Display the outstanding receive operations\r
4017 //\r
4018 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4019 "0x%08x: Port Close: Receive still pending!\r\n",\r
4020 pPort ));\r
4021 pIo = pPort->pRxActive;\r
4022 while ( NULL != pIo ) {\r
4023 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4024 "0x%08x: Packet pending on network adapter\r\n",\r
4025 pIo->pPacket ));\r
4026 pIo = pIo->pNext;\r
4027 }\r
4028 }\r
4029 DEBUG_CODE_END ( );\r
4030 }\r
4031 }\r
d7ce7006 4032\r
4033 //\r
4034 // Return the operation status\r
4035 //\r
4036 DBG_EXIT_STATUS ( Status );\r
4037 return Status;\r
4038}\r
4039\r
4040\r
4041/**\r
a88c3163 4042 Start the close operation on a port, state 1.\r
4043\r
4044 This routine marks the port as closed and initiates the \ref\r
4045 PortCloseStateMachine. The first step is to allow the \ref\r
4046 TransmitEngine to run down.\r
d7ce7006 4047\r
a88c3163 4048 This routine is called by ::EslSocketCloseStart to initiate the socket\r
4049 network specific close operation on the socket.\r
4050\r
4051 @param [in] pPort Address of an ::ESL_PORT structure.\r
4052 @param [in] bCloseNow Set TRUE to abort active transfers\r
d7ce7006 4053 @param [in] DebugFlags Flags for debug messages\r
4054\r
a88c3163 4055 @retval EFI_SUCCESS The port is closed, not normally returned\r
4056 @retval EFI_NOT_READY The port has started the closing process\r
4057 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
4058 most likely the routine was called already.\r
d7ce7006 4059\r
a88c3163 4060**/\r
d7ce7006 4061EFI_STATUS\r
a88c3163 4062EslSocketPortCloseStart (\r
4063 IN ESL_PORT * pPort,\r
4064 IN BOOLEAN bCloseNow,\r
d7ce7006 4065 IN UINTN DebugFlags\r
4066 )\r
4067{\r
a88c3163 4068 ESL_SOCKET * pSocket;\r
d7ce7006 4069 EFI_STATUS Status;\r
4070\r
4071 DBG_ENTER ( );\r
4072\r
4073 //\r
a88c3163 4074 // Verify the socket layer synchronization\r
d7ce7006 4075 //\r
a88c3163 4076 VERIFY_TPL ( TPL_SOCKETS );\r
4077\r
4078 //\r
4079 // Mark the port as closing\r
4080 //\r
4081 Status = EFI_ALREADY_STARTED;\r
4082 pSocket = pPort->pSocket;\r
4083 pSocket->errno = EALREADY;\r
4084 if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {\r
4085\r
4086 //\r
4087 // Update the port state\r
4088 //\r
4089 pPort->State = PORT_STATE_CLOSE_STARTED;\r
4090 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4091 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",\r
4092 pPort ));\r
4093 pPort->bCloseNow = bCloseNow;\r
4094 pPort->DebugFlags = DebugFlags;\r
4095\r
4096 //\r
4097 // Determine if transmits are complete\r
4098 //\r
4099 Status = EslSocketPortCloseTxDone ( pPort );\r
d7ce7006 4100 }\r
4101\r
4102 //\r
4103 // Return the operation status\r
4104 //\r
4105 DBG_EXIT_STATUS ( Status );\r
4106 return Status;\r
4107}\r
4108\r
4109\r
4110/**\r
a88c3163 4111 Port close state 2\r
d7ce7006 4112\r
a88c3163 4113 This routine determines the state of the transmit engine and\r
4114 continue the close operation after the transmission is complete.\r
4115 The next step is to stop the \ref ReceiveEngine.\r
4116 See the \ref PortCloseStateMachine section.\r
d7ce7006 4117\r
a88c3163 4118 This routine is called by ::EslSocketPortCloseStart to determine\r
4119 if the transmission is complete.\r
d7ce7006 4120\r
a88c3163 4121 @param [in] pPort Address of an ::ESL_PORT structure.\r
d7ce7006 4122\r
a88c3163 4123 @retval EFI_SUCCESS The port is closed, not normally returned\r
4124 @retval EFI_NOT_READY The port is still closing\r
4125 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
4126 most likely the routine was called already.\r
d7ce7006 4127\r
a88c3163 4128**/\r
d7ce7006 4129EFI_STATUS\r
a88c3163 4130EslSocketPortCloseTxDone (\r
4131 IN ESL_PORT * pPort\r
d7ce7006 4132 )\r
4133{\r
a88c3163 4134 ESL_IO_MGMT * pIo;\r
4135 ESL_SOCKET * pSocket;\r
d7ce7006 4136 EFI_STATUS Status;\r
d7ce7006 4137\r
a88c3163 4138 DBG_ENTER ( );\r
d7ce7006 4139\r
4140 //\r
a88c3163 4141 // Verify the socket layer synchronization\r
d7ce7006 4142 //\r
a88c3163 4143 VERIFY_TPL ( TPL_SOCKETS );\r
d7ce7006 4144\r
4145 //\r
a88c3163 4146 // All transmissions are complete or must be stopped\r
4147 // Mark the port as TX complete\r
d7ce7006 4148 //\r
a88c3163 4149 Status = EFI_ALREADY_STARTED;\r
4150 if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {\r
d7ce7006 4151 //\r
a88c3163 4152 // Verify that the transmissions are complete\r
d7ce7006 4153 //\r
a88c3163 4154 pSocket = pPort->pSocket;\r
4155 if ( pPort->bCloseNow\r
4156 || ( EFI_SUCCESS != pSocket->TxError )\r
4157 || (( NULL == pPort->pTxActive )\r
4158 && ( NULL == pPort->pTxOobActive ))) {\r
d7ce7006 4159 //\r
a88c3163 4160 // Update the port state\r
d7ce7006 4161 //\r
a88c3163 4162 pPort->State = PORT_STATE_CLOSE_TX_DONE;\r
4163 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4164 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",\r
4165 pPort ));\r
d7ce7006 4166\r
d7ce7006 4167 //\r
a88c3163 4168 // Close the port\r
4169 // Skip the close operation if the port is not configured\r
d7ce7006 4170 //\r
a88c3163 4171 Status = EFI_SUCCESS;\r
4172 pSocket = pPort->pSocket;\r
4173 if (( pPort->bConfigured )\r
4174 && ( NULL != pSocket->pApi->pfnPortCloseOp )) {\r
4175 //\r
4176 // Start the close operation\r
4177 //\r
4178 Status = pSocket->pApi->pfnPortCloseOp ( pPort );\r
4179 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4180 "0x%08x: Port Close: Close operation still pending!\r\n",\r
4181 pPort ));\r
4182 ASSERT ( EFI_SUCCESS == Status );\r
d7ce7006 4183 }\r
a88c3163 4184 else {\r
d7ce7006 4185 //\r
a88c3163 4186 // The receive operation is complete\r
4187 // Update the port state\r
d7ce7006 4188 //\r
a88c3163 4189 EslSocketPortCloseComplete ( NULL, pPort );\r
d7ce7006 4190 }\r
a88c3163 4191 }\r
4192 else {\r
d7ce7006 4193 //\r
a88c3163 4194 // Transmissions are still active, exit\r
d7ce7006 4195 //\r
a88c3163 4196 Status = EFI_NOT_READY;\r
4197 pSocket->errno = EAGAIN;\r
4198 DEBUG_CODE_BEGIN ( );\r
4199 {\r
4200 ESL_PACKET * pPacket;\r
d7ce7006 4201\r
a88c3163 4202 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4203 "0x%08x: Port Close: Transmits are still pending!\r\n",\r
4204 pPort ));\r
d7ce7006 4205\r
a88c3163 4206 //\r
4207 // Display the pending urgent transmit packets\r
4208 //\r
4209 pPacket = pSocket->pTxOobPacketListHead;\r
4210 while ( NULL != pPacket ) {\r
4211 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4212 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",\r
4213 pPacket,\r
4214 pPacket->PacketSize ));\r
4215 pPacket = pPacket->pNext;\r
4216 }\r
d7ce7006 4217\r
a88c3163 4218 pIo = pPort->pTxOobActive;\r
4219 while ( NULL != pIo ) {\r
4220 pPacket = pIo->pPacket;\r
4221 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4222 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",\r
4223 pPacket,\r
4224 pPacket->PacketSize,\r
4225 pIo ));\r
4226 pIo = pIo->pNext;\r
4227 }\r
d7ce7006 4228\r
a88c3163 4229 //\r
4230 // Display the pending normal transmit packets\r
4231 //\r
4232 pPacket = pSocket->pTxPacketListHead;\r
4233 while ( NULL != pPacket ) {\r
4234 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4235 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",\r
4236 pPacket,\r
4237 pPacket->PacketSize ));\r
4238 pPacket = pPacket->pNext;\r
4239 }\r
d7ce7006 4240\r
a88c3163 4241 pIo = pPort->pTxActive;\r
4242 while ( NULL != pIo ) {\r
4243 pPacket = pIo->pPacket;\r
4244 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
4245 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",\r
4246 pPacket,\r
4247 pPacket->PacketSize,\r
4248 pIo ));\r
4249 pIo = pIo->pNext;\r
4250 }\r
d7ce7006 4251 }\r
a88c3163 4252 DEBUG_CODE_END ();\r
4253 }\r
4254 }\r
d7ce7006 4255\r
4256 //\r
4257 // Return the operation status\r
4258 //\r
a88c3163 4259 DBG_EXIT_STATUS ( Status );\r
d7ce7006 4260 return Status;\r
4261}\r
4262\r
4263\r
4264/**\r
4265 Receive data from a network connection.\r
4266\r
a88c3163 4267 This routine calls the network specific routine to remove the\r
4268 next portion of data from the receive queue and return it to the\r
4269 caller.\r
d7ce7006 4270\r
a88c3163 4271 The ::recvfrom routine calls this routine to determine if any data\r
4272 is received from the remote system. Note that the other routines\r
4273 ::recv and ::read are layered on top of ::recvfrom.\r
4274\r
4275 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
d7ce7006 4276 \r
4277 @param [in] Flags Message control flags\r
4278 \r
4279 @param [in] BufferLength Length of the the buffer\r
4280 \r
4281 @param [in] pBuffer Address of a buffer to receive the data.\r
4282 \r
4283 @param [in] pDataLength Number of received data bytes in the buffer.\r
4284\r
4285 @param [out] pAddress Network address to receive the remote system address\r
4286\r
4287 @param [in,out] pAddressLength Length of the remote network address structure\r
4288\r
4289 @param [out] pErrno Address to receive the errno value upon completion.\r
4290\r
4291 @retval EFI_SUCCESS - Socket data successfully received\r
4292\r
4293 **/\r
4294EFI_STATUS\r
4295EslSocketReceive (\r
4296 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
4297 IN INT32 Flags,\r
4298 IN size_t BufferLength,\r
4299 IN UINT8 * pBuffer,\r
4300 OUT size_t * pDataLength,\r
4301 OUT struct sockaddr * pAddress,\r
4302 IN OUT socklen_t * pAddressLength,\r
4303 IN int * pErrno\r
4304 )\r
4305{\r
a88c3163 4306 union {\r
4307 struct sockaddr_in v4;\r
4308 struct sockaddr_in6 v6;\r
4309 } Addr;\r
4310 socklen_t AddressLength;\r
4311 BOOLEAN bConsumePacket;\r
4312 BOOLEAN bUrgentQueue;\r
4313 size_t DataLength;\r
4314 ESL_PACKET * pNextPacket;\r
4315 ESL_PACKET * pPacket;\r
4316 ESL_PORT * pPort;\r
4317 ESL_PACKET ** ppQueueHead;\r
4318 ESL_PACKET ** ppQueueTail;\r
4319 struct sockaddr * pRemoteAddress;\r
4320 size_t * pRxDataBytes;\r
4321 ESL_SOCKET * pSocket;\r
4322 size_t SkipBytes;\r
d7ce7006 4323 EFI_STATUS Status;\r
4324 EFI_TPL TplPrevious;\r
4325\r
4326 DBG_ENTER ( );\r
4327\r
4328 //\r
4329 // Assume success\r
4330 //\r
4331 Status = EFI_SUCCESS;\r
4332\r
4333 //\r
4334 // Validate the socket\r
4335 //\r
4336 pSocket = NULL;\r
4337 if ( NULL != pSocketProtocol ) {\r
4338 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
4339\r
4340 //\r
a88c3163 4341 // Validate the return address parameters\r
d7ce7006 4342 //\r
a88c3163 4343 if (( NULL == pAddress ) || ( NULL != pAddressLength )) {\r
d7ce7006 4344 //\r
a88c3163 4345 // Return the transmit error if necessary\r
d7ce7006 4346 //\r
a88c3163 4347 if ( EFI_SUCCESS != pSocket->TxError ) {\r
4348 pSocket->errno = EIO;\r
4349 Status = pSocket->TxError;\r
4350 pSocket->TxError = EFI_SUCCESS;\r
4351 }\r
4352 else {\r
d7ce7006 4353 //\r
a88c3163 4354 // Verify the socket state\r
d7ce7006 4355 //\r
a88c3163 4356 Status = EslSocketIsConfigured ( pSocket );\r
4357 if ( !EFI_ERROR ( Status )) {\r
d7ce7006 4358 //\r
a88c3163 4359 // Validate the buffer length\r
d7ce7006 4360 //\r
a88c3163 4361 if (( NULL == pDataLength )\r
4362 || ( NULL == pBuffer )) {\r
4363 if ( NULL == pDataLength ) {\r
4364 DEBUG (( DEBUG_RX,\r
4365 "ERROR - pDataLength is NULL!\r\n" ));\r
4366 }\r
4367 else {\r
4368 DEBUG (( DEBUG_RX,\r
4369 "ERROR - pBuffer is NULL!\r\n" ));\r
4370 }\r
d7ce7006 4371 Status = EFI_INVALID_PARAMETER;\r
a88c3163 4372 pSocket->errno = EFAULT;\r
4373 }\r
4374 else {\r
1c34b250 4375 //\r
a88c3163 4376 // Verify the API\r
1c34b250 4377 //\r
a88c3163 4378 if ( NULL == pSocket->pApi->pfnReceive ) {\r
4379 Status = EFI_UNSUPPORTED;\r
4380 pSocket->errno = ENOTSUP;\r
4381 }\r
4382 else {\r
4383 //\r
4384 // Zero the receive address if being returned\r
4385 //\r
4386 pRemoteAddress = NULL;\r
4387 if ( NULL != pAddress ) {\r
4388 pRemoteAddress = (struct sockaddr *)&Addr;\r
4389 ZeroMem ( pRemoteAddress, sizeof ( Addr ));\r
4390 pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;\r
4391 pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;\r
4392 }\r
4393 \r
4394 //\r
4395 // Synchronize with the socket layer\r
4396 //\r
4397 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
d7ce7006 4398\r
a88c3163 4399 //\r
4400 // Assume failure\r
4401 //\r
4402 Status = EFI_UNSUPPORTED;\r
4403 pSocket->errno = ENOTCONN;\r
4404\r
4405 //\r
4406 // Verify that the socket is connected\r
4407 //\r
4408 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
3bdf9aae 4409 //\r
4410 // Poll the network to increase performance\r
4411 //\r
4412 EslSocketRxPoll ( pSocket );\r
4413\r
a88c3163 4414 //\r
4415 // Locate the port\r
4416 //\r
4417 pPort = pSocket->pPortList;\r
4418 if ( NULL != pPort ) {\r
4419 //\r
4420 // Determine the queue head\r
4421 //\r
4422 bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
4423 if ( bUrgentQueue ) {\r
4424 ppQueueHead = &pSocket->pRxOobPacketListHead;\r
4425 ppQueueTail = &pSocket->pRxOobPacketListTail;\r
4426 pRxDataBytes = &pSocket->RxOobBytes;\r
4427 }\r
4428 else {\r
4429 ppQueueHead = &pSocket->pRxPacketListHead;\r
4430 ppQueueTail = &pSocket->pRxPacketListTail;\r
4431 pRxDataBytes = &pSocket->RxBytes;\r
4432 }\r
4433\r
4434 //\r
4435 // Determine if there is any data on the queue\r
4436 //\r
4437 *pDataLength = 0;\r
4438 pPacket = *ppQueueHead;\r
4439 if ( NULL != pPacket ) {\r
4440 //\r
4441 // Copy the received data\r
4442 //\r
4443 do {\r
4444 //\r
4445 // Attempt to receive a packet\r
4446 //\r
4447 SkipBytes = 0;\r
4448 bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));\r
4449 pBuffer = pSocket->pApi->pfnReceive ( pPort,\r
4450 pPacket,\r
4451 &bConsumePacket,\r
4452 BufferLength,\r
4453 pBuffer,\r
4454 &DataLength,\r
4455 (struct sockaddr *)&Addr,\r
4456 &SkipBytes );\r
4457 *pDataLength += DataLength;\r
4458 BufferLength -= DataLength;\r
4459\r
4460 //\r
4461 // Determine if the data is being read\r
4462 //\r
4463 pNextPacket = pPacket->pNext;\r
4464 if ( bConsumePacket ) {\r
4465 //\r
4466 // All done with this packet\r
4467 // Account for any discarded data\r
4468 //\r
4469 pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );\r
4470 if ( 0 != SkipBytes ) {\r
4471 DEBUG (( DEBUG_RX,\r
4472 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",\r
4473 pPort,\r
4474 SkipBytes ));\r
4475 }\r
4476\r
4477 //\r
4478 // Remove this packet from the queue\r
4479 //\r
4480 *ppQueueHead = pPacket->pNext;\r
4481 if ( NULL == *ppQueueHead ) {\r
4482 *ppQueueTail = NULL;\r
4483 }\r
4484\r
4485 //\r
4486 // Move the packet to the free queue\r
4487 //\r
4488 pPacket->pNext = pSocket->pRxFree;\r
4489 pSocket->pRxFree = pPacket;\r
4490 DEBUG (( DEBUG_RX,\r
4491 "0x%08x: Port freeing packet 0x%08x\r\n",\r
4492 pPort,\r
4493 pPacket ));\r
4494\r
4495 //\r
4496 // Restart the receive operation if necessary\r
4497 //\r
4498 if (( NULL != pPort->pRxFree )\r
4499 && ( MAX_RX_DATA > pSocket->RxBytes )) {\r
4500 EslSocketRxStart ( pPort );\r
4501 }\r
4502 }\r
4503\r
4504 //\r
4505 // Get the next packet\r
4506 //\r
4507 pPacket = pNextPacket;\r
4508 } while (( SOCK_STREAM == pSocket->Type )\r
4509 && ( NULL != pPacket )\r
4510 && ( 0 < BufferLength ));\r
4511\r
4512 //\r
4513 // Successful operation\r
4514 //\r
4515 Status = EFI_SUCCESS;\r
4516 pSocket->errno = 0;\r
4517 }\r
4518 else {\r
4519 //\r
4520 // The queue is empty\r
4521 // Determine if it is time to return the receive error\r
4522 //\r
4523 if ( EFI_ERROR ( pSocket->RxError )\r
4524 && ( NULL == pSocket->pRxPacketListHead )\r
4525 && ( NULL == pSocket->pRxOobPacketListHead )) {\r
4526 Status = pSocket->RxError;\r
4527 pSocket->RxError = EFI_SUCCESS;\r
4528 switch ( Status ) {\r
4529 default:\r
4530 pSocket->errno = EIO;\r
4531 break;\r
4532\r
4533 case EFI_CONNECTION_FIN:\r
4534 //\r
4535 // Continue to return zero bytes received when the\r
4536 // peer has successfully closed the connection\r
4537 //\r
4538 pSocket->RxError = EFI_CONNECTION_FIN;\r
4539 *pDataLength = 0;\r
4540 pSocket->errno = 0;\r
4541 Status = EFI_SUCCESS;\r
4542 break;\r
4543\r
4544 case EFI_CONNECTION_REFUSED:\r
4545 pSocket->errno = ECONNREFUSED;\r
4546 break;\r
4547\r
4548 case EFI_CONNECTION_RESET:\r
4549 pSocket->errno = ECONNRESET;\r
4550 break;\r
4551\r
4552 case EFI_HOST_UNREACHABLE:\r
4553 pSocket->errno = EHOSTUNREACH;\r
4554 break;\r
4555\r
4556 case EFI_NETWORK_UNREACHABLE:\r
4557 pSocket->errno = ENETUNREACH;\r
4558 break;\r
4559\r
4560 case EFI_PORT_UNREACHABLE:\r
4561 pSocket->errno = EPROTONOSUPPORT;\r
4562 break;\r
4563\r
4564 case EFI_PROTOCOL_UNREACHABLE:\r
4565 pSocket->errno = ENOPROTOOPT;\r
4566 break;\r
4567 }\r
4568 }\r
4569 else {\r
4570 Status = EFI_NOT_READY;\r
4571 pSocket->errno = EAGAIN;\r
4572 }\r
4573 }\r
4574 }\r
4575 }\r
4576\r
4577 //\r
4578 // Release the socket layer synchronization\r
4579 //\r
4580 RESTORE_TPL ( TplPrevious );\r
4581\r
4582 if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {\r
4583 //\r
4584 // Return the remote address if requested, truncate if necessary\r
4585 //\r
4586 AddressLength = pRemoteAddress->sa_len;\r
4587 if ( AddressLength > *pAddressLength ) {\r
4588 AddressLength = *pAddressLength;\r
4589 }\r
4590 DEBUG (( DEBUG_RX,\r
4591 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));\r
4592 ZeroMem ( pAddress, *pAddressLength );\r
4593 CopyMem ( pAddress, &Addr, AddressLength );\r
4594\r
4595 //\r
4596 // Update the address length\r
4597 //\r
4598 *pAddressLength = pRemoteAddress->sa_len;\r
4599 }\r
4600 }\r
4601 }\r
4602 }\r
4603 }\r
4604\r
4605 \r
4606 }\r
4607 else {\r
4608 //\r
4609 // Bad return address pointer and length\r
4610 //\r
4611 Status = EFI_INVALID_PARAMETER;\r
4612 pSocket->errno = EINVAL;\r
4613 }\r
4614 }\r
4615\r
4616 //\r
4617 // Return the operation status\r
4618 //\r
4619 if ( NULL != pErrno ) {\r
4620 if ( NULL != pSocket ) {\r
4621 *pErrno = pSocket->errno;\r
4622 }\r
4623 else {\r
4624 Status = EFI_INVALID_PARAMETER;\r
4625 *pErrno = ENOTSOCK;\r
4626 }\r
4627 }\r
4628 DBG_EXIT_STATUS ( Status );\r
4629 return Status;\r
4630}\r
4631\r
4632\r
4633/**\r
4634 Cancel the receive operations\r
4635\r
4636 This routine cancels a pending receive operation.\r
4637 See the \ref ReceiveEngine section.\r
4638\r
4639 This routine is called by ::EslSocketShutdown when the socket\r
4640 layer is being shutdown.\r
4641\r
4642 @param [in] pPort Address of an ::ESL_PORT structure\r
4643 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
4644\r
4645 **/\r
4646VOID\r
4647EslSocketRxCancel (\r
4648 IN ESL_PORT * pPort,\r
4649 IN ESL_IO_MGMT * pIo\r
4650 )\r
4651{\r
4652 EFI_STATUS Status;\r
4653\r
4654 DBG_ENTER ( );\r
4655\r
4656 //\r
4657 // Cancel the outstanding receive\r
4658 //\r
4659 Status = pPort->pfnRxCancel ( pPort->pProtocol.v,\r
4660 &pIo->Token );\r
4661 if ( !EFI_ERROR ( Status )) {\r
4662 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
4663 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",\r
4664 pIo->pPacket,\r
4665 pPort ));\r
4666 }\r
4667 else {\r
4668 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
4669 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",\r
4670 pIo->pPacket,\r
4671 pPort,\r
4672 Status ));\r
4673 }\r
4674 DBG_EXIT ( );\r
4675}\r
4676\r
4677\r
4678/**\r
4679 Process the receive completion\r
4680\r
4681 This routine queues the data in FIFO order in either the urgent\r
4682 or normal data queues depending upon the type of data received.\r
4683 See the \ref ReceiveEngine section.\r
4684\r
4685 This routine is called when some data is received by:\r
4686 <ul>\r
4687 <li>::EslIp4RxComplete</li>\r
4688 <li>::EslTcp4RxComplete</li>\r
4689 <li>::EslUdp4RxComplete</li>\r
4690 </ul>\r
4691\r
4692 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
4693 @param [in] Status Receive status\r
4694 @param [in] LengthInBytes Length of the receive data\r
4695 @param [in] bUrgent TRUE if urgent data is received and FALSE\r
4696 for normal data.\r
4697\r
4698**/\r
4699VOID\r
4700EslSocketRxComplete (\r
4701 IN ESL_IO_MGMT * pIo,\r
4702 IN EFI_STATUS Status,\r
4703 IN UINTN LengthInBytes,\r
4704 IN BOOLEAN bUrgent\r
4705 )\r
4706{\r
4707 BOOLEAN bUrgentQueue;\r
4708 ESL_IO_MGMT * pIoNext;\r
4709 ESL_PACKET * pPacket;\r
4710 ESL_PORT * pPort;\r
4711 ESL_PACKET * pPrevious;\r
4712 ESL_PACKET ** ppQueueHead;\r
4713 ESL_PACKET ** ppQueueTail;\r
4714 size_t * pRxBytes;\r
4715 ESL_SOCKET * pSocket;\r
4716\r
4717 DBG_ENTER ( );\r
4718 VERIFY_AT_TPL ( TPL_SOCKETS );\r
4719\r
4720 //\r
4721 // Locate the active receive packet\r
4722 //\r
4723 pPacket = pIo->pPacket;\r
4724 pPort = pIo->pPort;\r
4725 pSocket = pPort->pSocket;\r
4726\r
4727 //\r
4728 // pPort->pRxActive\r
4729 // |\r
4730 // V\r
4731 // +-------------+ +-------------+ +-------------+ \r
4732 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
4733 // +-------------+ +-------------+ +-------------+ \r
4734 //\r
4735 // +-------------+ +-------------+ +-------------+ \r
4736 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
4737 // +-------------+ +-------------+ +-------------+ \r
4738 // ^\r
4739 // |\r
4740 // pPort->pRxFree\r
4741 //\r
4742 //\r
4743 // Remove the IO structure from the active list\r
4744 // The following code searches for the entry in the list and does not\r
4745 // assume that the receive operations complete in the order they were\r
4746 // issued to the UEFI network layer.\r
4747 //\r
4748 pIoNext = pPort->pRxActive;\r
4749 while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))\r
4750 {\r
4751 pIoNext = pIoNext->pNext;\r
4752 }\r
4753 ASSERT ( NULL != pIoNext );\r
4754 if ( pIoNext == pIo ) {\r
4755 pPort->pRxActive = pIo->pNext; // Beginning of list\r
4756 }\r
4757 else {\r
4758 pIoNext->pNext = pIo->pNext; // Middle of list\r
4759 }\r
4760\r
4761 //\r
4762 // Free the IO structure\r
4763 //\r
4764 pIo->pNext = pPort->pRxFree;\r
4765 pPort->pRxFree = pIo;\r
4766\r
4767 //\r
4768 // pRxOobPacketListHead pRxOobPacketListTail\r
4769 // | |\r
4770 // V V\r
4771 // +------------+ +------------+ +------------+ \r
4772 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
4773 // +------------+ +------------+ +------------+ \r
4774 //\r
4775 // +------------+ +------------+ +------------+ \r
4776 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
4777 // +------------+ +------------+ +------------+ \r
4778 // ^ ^\r
4779 // | |\r
4780 // pRxPacketListHead pRxPacketListTail\r
4781 //\r
4782 //\r
4783 // Determine the queue to use\r
4784 //\r
4785 bUrgentQueue = (BOOLEAN)( bUrgent\r
4786 && pSocket->pApi->bOobSupported\r
4787 && ( !pSocket->bOobInLine ));\r
4788 if ( bUrgentQueue ) {\r
4789 ppQueueHead = &pSocket->pRxOobPacketListHead;\r
4790 ppQueueTail = &pSocket->pRxOobPacketListTail;\r
4791 pRxBytes = &pSocket->RxOobBytes;\r
4792 }\r
4793 else {\r
4794 ppQueueHead = &pSocket->pRxPacketListHead;\r
4795 ppQueueTail = &pSocket->pRxPacketListTail;\r
4796 pRxBytes = &pSocket->RxBytes;\r
4797 }\r
4798\r
4799 //\r
4800 // Determine if this receive was successful\r
4801 //\r
4802 if (( !EFI_ERROR ( Status ))\r
4803 && ( PORT_STATE_CLOSE_STARTED > pPort->State )\r
4804 && ( !pSocket->bRxDisable )) {\r
4805 //\r
4806 // Account for the received data\r
4807 //\r
4808 *pRxBytes += LengthInBytes;\r
4809\r
4810 //\r
4811 // Log the received data\r
4812 //\r
4813 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
4814 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",\r
4815 pPacket,\r
4816 bUrgentQueue ? L"urgent" : L"normal",\r
4817 pPort,\r
4818 LengthInBytes,\r
4819 bUrgent ? L"urgent" : L"normal" ));\r
4820\r
4821 //\r
4822 // Add the packet to the list tail.\r
4823 //\r
4824 pPacket->pNext = NULL;\r
4825 pPrevious = *ppQueueTail;\r
4826 if ( NULL == pPrevious ) {\r
4827 *ppQueueHead = pPacket;\r
4828 }\r
4829 else {\r
4830 pPrevious->pNext = pPacket;\r
4831 }\r
4832 *ppQueueTail = pPacket;\r
4833\r
4834 //\r
4835 // Attempt to restart this receive operation\r
4836 //\r
4837 if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {\r
4838 EslSocketRxStart ( pPort );\r
4839 }\r
4840 else {\r
4841 DEBUG (( DEBUG_RX,\r
4842 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",\r
4843 pPort,\r
4844 pSocket->RxBytes ));\r
4845 }\r
4846 }\r
4847 else {\r
4848 if ( EFI_ERROR ( Status )) {\r
4849 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
4850 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",\r
4851 pPort,\r
4852 pPacket,\r
4853 Status ));\r
4854 }\r
4855\r
4856 //\r
4857 // Account for the receive bytes and release the driver's buffer\r
4858 //\r
4859 if ( !EFI_ERROR ( Status )) {\r
4860 *pRxBytes += LengthInBytes;\r
4861 pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );\r
4862 }\r
4863\r
4864 //\r
4865 // Receive error, free the packet save the error\r
4866 //\r
4867 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
4868 if ( !EFI_ERROR ( pSocket->RxError )) {\r
4869 pSocket->RxError = Status;\r
4870 }\r
4871\r
4872 //\r
4873 // Update the port state\r
4874 //\r
4875 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
4876 if ( PORT_STATE_CLOSE_DONE == pPort->State ) {\r
4877 EslSocketPortCloseRxDone ( pPort );\r
4878 }\r
4879 }\r
4880 else {\r
4881 if ( EFI_ERROR ( Status )) {\r
4882 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
4883 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",\r
4884 pPort,\r
4885 Status ));\r
4886 pPort->State = PORT_STATE_RX_ERROR;\r
4887 }\r
4888 }\r
4889 }\r
4890\r
4891 DBG_EXIT ( );\r
4892}\r
4893\r
4894\r
3bdf9aae 4895/**\r
4896 Poll a socket for pending receive activity.\r
4897\r
4898 This routine is called at elivated TPL and extends the idle\r
4899 loop which polls a socket down into the LAN driver layer to\r
4900 determine if there is any receive activity.\r
4901\r
4902 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit\r
4903 routines call this routine when there is nothing to do.\r
4904\r
4905 @param [in] pSocket Address of an ::EFI_SOCKET structure.\r
4906\r
4907 **/\r
4908VOID\r
4909EslSocketRxPoll (\r
4910 IN ESL_SOCKET * pSocket\r
4911 )\r
4912{\r
4913 ESL_PORT * pPort;\r
4914\r
4915 DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));\r
4916\r
4917 //\r
4918 // Increase the network performance by extending the\r
4919 // polling (idle) loop down into the LAN driver\r
4920 //\r
4921 pPort = pSocket->pPortList;\r
4922 while ( NULL != pPort ) {\r
4923 //\r
4924 // Poll the LAN adapter\r
4925 //\r
4926 pPort->pfnRxPoll ( pPort->pProtocol.v );\r
4927\r
4928 //\r
4929 // Locate the next LAN adapter\r
4930 //\r
4931 pPort = pPort->pLinkSocket;\r
4932 }\r
4933\r
4934 DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));\r
4935}\r
4936\r
4937\r
a88c3163 4938/**\r
4939 Start a receive operation\r
4940\r
4941 This routine posts a receive buffer to the network adapter.\r
4942 See the \ref ReceiveEngine section.\r
4943\r
4944 This support routine is called by:\r
4945 <ul>\r
4946 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>\r
4947 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
4948 <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>\r
4949 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>\r
4950 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>\r
4951 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
4952 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>\r
4953 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
4954 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>\r
4955 </ul>\r
4956\r
4957 @param [in] pPort Address of an ::ESL_PORT structure.\r
4958\r
4959 **/\r
4960VOID\r
4961EslSocketRxStart (\r
4962 IN ESL_PORT * pPort\r
4963 )\r
4964{\r
4965 UINT8 * pBuffer;\r
4966 ESL_IO_MGMT * pIo;\r
4967 ESL_PACKET * pPacket;\r
4968 ESL_SOCKET * pSocket;\r
4969 EFI_STATUS Status;\r
4970\r
4971 DBG_ENTER ( );\r
4972\r
4973 //\r
4974 // Determine if a receive is already pending\r
4975 //\r
4976 Status = EFI_SUCCESS;\r
4977 pPacket = NULL;\r
4978 pSocket = pPort->pSocket;\r
4979 if ( !EFI_ERROR ( pPort->pSocket->RxError )) {\r
4980 if (( NULL != pPort->pRxFree )\r
4981 && ( !pSocket->bRxDisable )\r
4982 && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {\r
4983 //\r
4984 // Start all of the pending receive operations\r
4985 //\r
4986 while ( NULL != pPort->pRxFree ) {\r
4987 //\r
4988 // Determine if there are any free packets\r
4989 //\r
4990 pPacket = pSocket->pRxFree;\r
4991 if ( NULL != pPacket ) {\r
4992 //\r
4993 // Remove this packet from the free list\r
4994 //\r
4995 pSocket->pRxFree = pPacket->pNext;\r
4996 DEBUG (( DEBUG_RX,\r
4997 "0x%08x: Port removed packet 0x%08x from free list\r\n",\r
4998 pPort,\r
4999 pPacket ));\r
5000 }\r
5001 else {\r
5002 //\r
5003 // Allocate a packet structure\r
5004 //\r
5005 Status = EslSocketPacketAllocate ( &pPacket,\r
5006 pSocket->pApi->RxPacketBytes,\r
5007 pSocket->pApi->RxZeroBytes,\r
5008 DEBUG_RX );\r
5009 if ( EFI_ERROR ( Status )) {\r
5010 pPacket = NULL;\r
5011 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
5012 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",\r
5013 pPort,\r
5014 Status ));\r
d7ce7006 5015 break;\r
5016 }\r
d7ce7006 5017 }\r
5018\r
5019 //\r
a88c3163 5020 // Connect the IO and packet structures\r
d7ce7006 5021 //\r
a88c3163 5022 pIo = pPort->pRxFree;\r
5023 pIo->pPacket = pPacket;\r
5024\r
5025 //\r
5026 // Eliminate the need for IP4 and UDP4 specific routines by\r
5027 // clearing the RX data pointer here.\r
5028 //\r
5029 // No driver buffer for this packet\r
5030 //\r
5031 // +--------------------+\r
5032 // | ESL_IO_MGMT |\r
5033 // | |\r
5034 // | +---------------+\r
5035 // | | Token |\r
5036 // | | RxData --> NULL\r
5037 // +----+---------------+\r
5038 //\r
5039 pBuffer = (UINT8 *)pIo;\r
5040 pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];\r
5041 *(VOID **)pBuffer = NULL;\r
1c34b250 5042\r
5043 //\r
a88c3163 5044 // Network specific receive packet initialization\r
1c34b250 5045 //\r
a88c3163 5046 if ( NULL != pSocket->pApi->pfnRxStart ) {\r
5047 pSocket->pApi->pfnRxStart ( pPort, pIo );\r
1c34b250 5048 }\r
a88c3163 5049\r
1c34b250 5050 //\r
a88c3163 5051 // Start the receive on the packet\r
1c34b250 5052 //\r
a88c3163 5053 Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );\r
5054 if ( !EFI_ERROR ( Status )) {\r
5055 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5056 "0x%08x: Packet receive pending on port 0x%08x\r\n",\r
5057 pPacket,\r
5058 pPort ));\r
1c34b250 5059 //\r
a88c3163 5060 // Allocate the receive control structure\r
1c34b250 5061 //\r
a88c3163 5062 pPort->pRxFree = pIo->pNext;\r
5063 \r
1c34b250 5064 //\r
a88c3163 5065 // Mark this receive as pending\r
1c34b250 5066 //\r
a88c3163 5067 pIo->pNext = pPort->pRxActive;\r
5068 pPort->pRxActive = pIo;\r
5069 \r
5070 }\r
5071 else {\r
5072 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5073 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",\r
5074 pPort,\r
5075 Status ));\r
5076 if ( !EFI_ERROR ( pSocket->RxError )) {\r
1c34b250 5077 //\r
a88c3163 5078 // Save the error status\r
1c34b250 5079 //\r
a88c3163 5080 pSocket->RxError = Status;\r
1c34b250 5081 }\r
5082\r
5083 //\r
a88c3163 5084 // Free the packet\r
1c34b250 5085 //\r
a88c3163 5086 pIo->pPacket = NULL;\r
5087 pPacket->pNext = pSocket->pRxFree;\r
5088 pSocket->pRxFree = pPacket;\r
5089 break;\r
1c34b250 5090 }\r
d7ce7006 5091 }\r
5092 }\r
a88c3163 5093 else {\r
5094 if ( NULL == pPort->pRxFree ) {\r
5095 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5096 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",\r
5097 pPort));\r
5098 }\r
5099 if ( pSocket->bRxDisable ) {\r
5100 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5101 "0x%08x: Port, receive disabled!\r\n",\r
5102 pPort ));\r
5103 }\r
5104 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
5105 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
5106 "0x%08x: Port, is closing!\r\n",\r
5107 pPort ));\r
5108 }\r
d7ce7006 5109 }\r
5110 }\r
a88c3163 5111 else {\r
5112 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
5113 "ERROR - Previous receive error, Status: %r\r\n",\r
5114 pPort->pSocket->RxError ));\r
5115 }\r
5116\r
5117 DBG_EXIT ( );\r
d7ce7006 5118}\r
5119\r
5120\r
5121/**\r
5122 Shutdown the socket receive and transmit operations\r
5123\r
a88c3163 5124 This routine sets a flag to stop future transmissions and calls\r
5125 the network specific layer to cancel the pending receive operation.\r
d7ce7006 5126\r
a88c3163 5127 The ::shutdown routine calls this routine to stop receive and transmit\r
5128 operations on the socket.\r
5129\r
5130 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
d7ce7006 5131 \r
5132 @param [in] How Which operations to stop\r
5133 \r
5134 @param [out] pErrno Address to receive the errno value upon completion.\r
5135\r
5136 @retval EFI_SUCCESS - Socket operations successfully shutdown\r
5137\r
5138 **/\r
5139EFI_STATUS\r
5140EslSocketShutdown (\r
5141 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
5142 IN int How,\r
5143 IN int * pErrno\r
5144 )\r
5145{\r
a88c3163 5146 ESL_IO_MGMT * pIo;\r
5147 ESL_PORT * pPort;\r
5148 ESL_SOCKET * pSocket;\r
d7ce7006 5149 EFI_STATUS Status;\r
5150 EFI_TPL TplPrevious;\r
5151 \r
5152 DBG_ENTER ( );\r
5153 \r
5154 //\r
5155 // Assume success\r
5156 //\r
5157 Status = EFI_SUCCESS;\r
5158\r
5159 //\r
5160 // Validate the socket\r
5161 //\r
5162 pSocket = NULL;\r
5163 if ( NULL != pSocketProtocol ) {\r
5164 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
5165\r
5166 //\r
5167 // Verify that the socket is connected\r
5168 //\r
5169 if ( pSocket->bConnected ) {\r
5170 //\r
5171 // Validate the How value\r
5172 //\r
5173 if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {\r
5174 //\r
5175 // Synchronize with the socket layer\r
5176 //\r
5177 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
5178\r
5179 //\r
5180 // Disable the receiver if requested\r
5181 //\r
5182 if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {\r
5183 pSocket->bRxDisable = TRUE;\r
5184 }\r
5185\r
5186 //\r
5187 // Disable the transmitter if requested\r
5188 //\r
5189 if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {\r
5190 pSocket->bTxDisable = TRUE;\r
5191 }\r
5192\r
5193 //\r
a88c3163 5194 // Cancel the pending receive operations\r
d7ce7006 5195 //\r
a88c3163 5196 if ( pSocket->bRxDisable ) {\r
d7ce7006 5197 //\r
a88c3163 5198 // Walk the list of ports\r
d7ce7006 5199 //\r
a88c3163 5200 pPort = pSocket->pPortList;\r
5201 while ( NULL != pPort ) {\r
d7ce7006 5202 //\r
a88c3163 5203 // Walk the list of active receive operations\r
d7ce7006 5204 //\r
a88c3163 5205 pIo = pPort->pRxActive;\r
5206 while ( NULL != pIo ) {\r
5207 EslSocketRxCancel ( pPort, pIo );\r
5208 }\r
5209\r
d7ce7006 5210 //\r
a88c3163 5211 // Set the next port\r
d7ce7006 5212 //\r
a88c3163 5213 pPort = pPort->pLinkSocket;\r
d7ce7006 5214 }\r
d7ce7006 5215 }\r
a88c3163 5216\r
d7ce7006 5217 //\r
5218 // Release the socket layer synchronization\r
5219 //\r
5220 RESTORE_TPL ( TplPrevious );\r
5221 }\r
5222 else {\r
5223 //\r
a88c3163 5224 // Invalid How value\r
d7ce7006 5225 //\r
a88c3163 5226 pSocket->errno = EINVAL;\r
5227 Status = EFI_INVALID_PARAMETER;\r
d7ce7006 5228 }\r
5229 }\r
5230 else {\r
5231 //\r
a88c3163 5232 // The socket is not connected\r
d7ce7006 5233 //\r
a88c3163 5234 pSocket->errno = ENOTCONN;\r
5235 Status = EFI_NOT_STARTED;\r
d7ce7006 5236 }\r
5237 }\r
5238\r
5239 //\r
5240 // Return the operation status\r
5241 //\r
5242 if ( NULL != pErrno ) {\r
5243 if ( NULL != pSocket ) {\r
5244 *pErrno = pSocket->errno;\r
5245 }\r
a88c3163 5246 else {\r
d7ce7006 5247 Status = EFI_INVALID_PARAMETER;\r
a88c3163 5248 *pErrno = ENOTSOCK;\r
d7ce7006 5249 }\r
5250 }\r
5251 DBG_EXIT_STATUS ( Status );\r
5252 return Status;\r
5253}\r
5254\r
5255\r
5256/**\r
5257 Send data using a network connection.\r
5258\r
a88c3163 5259 This routine calls the network specific layer to queue the data\r
5260 for transmission. Eventually the buffer will reach the head of\r
5261 the queue and will get transmitted over the network by the\r
5262 \ref TransmitEngine. For datagram\r
5263 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that\r
5264 the data reaches the application running on the remote system.\r
d7ce7006 5265\r
a88c3163 5266 The ::sendto routine calls this routine to send data to the remote\r
5267 system. Note that ::send and ::write are layered on top of ::sendto.\r
5268\r
5269 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
d7ce7006 5270 \r
5271 @param [in] Flags Message control flags\r
5272 \r
5273 @param [in] BufferLength Length of the the buffer\r
5274 \r
5275 @param [in] pBuffer Address of a buffer containing the data to send\r
5276 \r
5277 @param [in] pDataLength Address to receive the number of data bytes sent\r
5278\r
5279 @param [in] pAddress Network address of the remote system address\r
5280\r
5281 @param [in] AddressLength Length of the remote network address structure\r
5282\r
5283 @param [out] pErrno Address to receive the errno value upon completion.\r
5284\r
5285 @retval EFI_SUCCESS - Socket data successfully queued for transmit\r
5286\r
5287 **/\r
5288EFI_STATUS\r
5289EslSocketTransmit (\r
5290 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
5291 IN int Flags,\r
5292 IN size_t BufferLength,\r
5293 IN CONST UINT8 * pBuffer,\r
5294 OUT size_t * pDataLength,\r
5295 IN const struct sockaddr * pAddress,\r
5296 IN socklen_t AddressLength,\r
5297 IN int * pErrno\r
5298 )\r
5299{\r
a88c3163 5300 ESL_SOCKET * pSocket;\r
d7ce7006 5301 EFI_STATUS Status;\r
5302 EFI_TPL TplPrevious;\r
5303\r
5304 DBG_ENTER ( );\r
5305\r
5306 //\r
5307 // Assume success\r
5308 //\r
5309 Status = EFI_SUCCESS;\r
5310\r
5311 //\r
5312 // Validate the socket\r
5313 //\r
5314 pSocket = NULL;\r
5315 if ( NULL != pSocketProtocol ) {\r
5316 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
5317\r
5318 //\r
1c34b250 5319 // Return the transmit error if necessary\r
d7ce7006 5320 //\r
1c34b250 5321 if ( EFI_SUCCESS != pSocket->TxError ) {\r
5322 pSocket->errno = EIO;\r
5323 Status = pSocket->TxError;\r
5324 pSocket->TxError = EFI_SUCCESS;\r
5325 }\r
5326 else {\r
d7ce7006 5327 //\r
1c34b250 5328 // Verify the socket state\r
d7ce7006 5329 //\r
a88c3163 5330 Status = EslSocketIsConfigured ( pSocket );\r
1c34b250 5331 if ( !EFI_ERROR ( Status )) {\r
5332 //\r
5333 // Verify that transmit is still allowed\r
5334 //\r
5335 if ( !pSocket->bTxDisable ) {\r
d7ce7006 5336 //\r
1c34b250 5337 // Validate the buffer length\r
d7ce7006 5338 //\r
1c34b250 5339 if (( NULL == pDataLength )\r
5340 && ( 0 > pDataLength )\r
5341 && ( NULL == pBuffer )) {\r
5342 if ( NULL == pDataLength ) {\r
5343 DEBUG (( DEBUG_RX,\r
5344 "ERROR - pDataLength is NULL!\r\n" ));\r
5345 }\r
5346 else if ( NULL == pBuffer ) {\r
5347 DEBUG (( DEBUG_RX,\r
5348 "ERROR - pBuffer is NULL!\r\n" ));\r
5349 }\r
5350 else {\r
5351 DEBUG (( DEBUG_RX,\r
5352 "ERROR - Data length < 0!\r\n" ));\r
5353 }\r
d7ce7006 5354 Status = EFI_INVALID_PARAMETER;\r
5355 pSocket->errno = EFAULT;\r
5356 }\r
5357 else {\r
5358 //\r
1c34b250 5359 // Validate the remote network address\r
d7ce7006 5360 //\r
1c34b250 5361 if (( NULL != pAddress )\r
5362 && ( AddressLength < pAddress->sa_len )) {\r
5363 DEBUG (( DEBUG_TX,\r
5364 "ERROR - Invalid sin_len field in address\r\n" ));\r
d7ce7006 5365 Status = EFI_INVALID_PARAMETER;\r
1c34b250 5366 pSocket->errno = EFAULT;\r
5367 }\r
5368 else {\r
5369 //\r
a88c3163 5370 // Verify the API\r
d7ce7006 5371 //\r
a88c3163 5372 if ( NULL == pSocket->pApi->pfnTransmit ) {\r
5373 Status = EFI_UNSUPPORTED;\r
5374 pSocket->errno = ENOTSUP;\r
5375 }\r
5376 else {\r
1c34b250 5377 //\r
a88c3163 5378 // Synchronize with the socket layer\r
1c34b250 5379 //\r
a88c3163 5380 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
1c34b250 5381\r
3bdf9aae 5382 //\r
5383 // Poll the network to increase performance\r
5384 //\r
5385 EslSocketRxPoll ( pSocket );\r
5386\r
a88c3163 5387 //\r
5388 // Attempt to buffer the packet for transmission\r
5389 //\r
5390 Status = pSocket->pApi->pfnTransmit ( pSocket,\r
5391 Flags,\r
5392 BufferLength,\r
5393 pBuffer,\r
5394 pDataLength,\r
5395 pAddress,\r
5396 AddressLength );\r
1c34b250 5397\r
a88c3163 5398 //\r
5399 // Release the socket layer synchronization\r
5400 //\r
5401 RESTORE_TPL ( TplPrevious );\r
d7ce7006 5402 }\r
1c34b250 5403 }\r
d7ce7006 5404 }\r
5405 }\r
1c34b250 5406 else {\r
5407 //\r
5408 // The transmitter was shutdown\r
5409 //\r
5410 pSocket->errno = EPIPE;\r
5411 Status = EFI_NOT_STARTED;\r
5412 }\r
d7ce7006 5413 }\r
5414 }\r
5415 }\r
5416\r
5417 //\r
5418 // Return the operation status\r
5419 //\r
5420 if ( NULL != pErrno ) {\r
5421 if ( NULL != pSocket ) {\r
5422 *pErrno = pSocket->errno;\r
5423 }\r
a88c3163 5424 else {\r
d7ce7006 5425 Status = EFI_INVALID_PARAMETER;\r
a88c3163 5426 *pErrno = ENOTSOCK;\r
d7ce7006 5427 }\r
5428 }\r
5429 DBG_EXIT_STATUS ( Status );\r
5430 return Status;\r
5431}\r
5432\r
5433\r
5434/**\r
a88c3163 5435 Complete the transmit operation\r
5436\r
5437 This support routine handles the transmit completion processing for\r
5438 the various network layers. It frees the ::ESL_IO_MGMT structure\r
5439 and and frees packet resources by calling ::EslSocketPacketFree.\r
5440 Transmit errors are logged in ESL_SOCKET::TxError.\r
5441 See the \ref TransmitEngine section.\r
5442\r
5443 This routine is called by:\r
5444 <ul>\r
5445 <li>::EslIp4TxComplete</li>\r
5446 <li>::EslTcp4TxComplete</li>\r
5447 <li>::EslTcp4TxOobComplete</li>\r
5448 <li>::EslUdp4TxComplete</li>\r
5449 </ul>\r
5450\r
5451 @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
5452 @param [in] LengthInBytes Length of the data in bytes\r
5453 @param [in] Status Transmit operation status\r
5454 @param [in] pQueueType Zero terminated string describing queue type\r
5455 @param [in] ppQueueHead Transmit queue head address\r
5456 @param [in] ppQueueTail Transmit queue tail address\r
5457 @param [in] ppActive Active transmit queue address\r
5458 @param [in] ppFree Free transmit queue address\r
5459\r
5460 **/\r
5461VOID\r
5462EslSocketTxComplete (\r
5463 IN ESL_IO_MGMT * pIo,\r
5464 IN UINT32 LengthInBytes,\r
5465 IN EFI_STATUS Status,\r
5466 IN CONST CHAR8 * pQueueType,\r
5467 IN ESL_PACKET ** ppQueueHead,\r
5468 IN ESL_PACKET ** ppQueueTail,\r
5469 IN ESL_IO_MGMT ** ppActive,\r
5470 IN ESL_IO_MGMT ** ppFree\r
5471 )\r
5472{\r
5473 ESL_PACKET * pCurrentPacket;\r
5474 ESL_IO_MGMT * pIoNext;\r
5475 ESL_PACKET * pNextPacket;\r
5476 ESL_PACKET * pPacket;\r
5477 ESL_PORT * pPort;\r
5478 ESL_SOCKET * pSocket;\r
5479\r
5480 DBG_ENTER ( );\r
5481 VERIFY_AT_TPL ( TPL_SOCKETS );\r
5482\r
5483 //\r
5484 // Locate the active transmit packet\r
5485 //\r
5486 pPacket = pIo->pPacket;\r
5487 pPort = pIo->pPort;\r
5488 pSocket = pPort->pSocket;\r
5489\r
5490 //\r
5491 // No more packet\r
5492 //\r
5493 pIo->pPacket = NULL;\r
5494\r
5495 //\r
5496 // Remove the IO structure from the active list\r
5497 //\r
5498 pIoNext = *ppActive;\r
5499 while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))\r
5500 {\r
5501 pIoNext = pIoNext->pNext;\r
5502 }\r
5503 ASSERT ( NULL != pIoNext );\r
5504 if ( pIoNext == pIo ) {\r
5505 *ppActive = pIo->pNext; // Beginning of list\r
5506 }\r
5507 else {\r
5508 pIoNext->pNext = pIo->pNext; // Middle of list\r
5509 }\r
5510\r
5511 //\r
5512 // Free the IO structure\r
5513 //\r
5514 pIo->pNext = *ppFree;\r
5515 *ppFree = pIo;\r
5516\r
5517 //\r
5518 // Display the results\r
5519 //\r
5520 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5521 "0x%08x: pIo Released\r\n",\r
5522 pIo ));\r
5523\r
5524 //\r
5525 // Save any transmit error\r
5526 //\r
5527 if ( EFI_ERROR ( Status )) {\r
5528 if ( !EFI_ERROR ( pSocket->TxError )) {\r
5529 pSocket->TxError = Status;\r
5530 }\r
5531 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5532 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",\r
5533 pQueueType,\r
5534 pPacket,\r
5535 Status ));\r
5536\r
5537 //\r
5538 // Empty the normal transmit list\r
5539 //\r
5540 pCurrentPacket = pPacket;\r
5541 pNextPacket = *ppQueueHead;\r
5542 while ( NULL != pNextPacket ) {\r
5543 pPacket = pNextPacket;\r
5544 pNextPacket = pPacket->pNext;\r
5545 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
5546 }\r
5547 *ppQueueHead = NULL;\r
5548 *ppQueueTail = NULL;\r
5549 pPacket = pCurrentPacket;\r
5550 }\r
5551 else {\r
5552 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5553 "0x%08x: %apacket transmitted %d bytes successfully\r\n",\r
5554 pPacket,\r
5555 pQueueType,\r
5556 LengthInBytes ));\r
5557\r
5558 //\r
5559 // Verify the transmit engine is still running\r
5560 //\r
5561 if ( !pPort->bCloseNow ) {\r
5562 //\r
5563 // Start the next packet transmission\r
5564 //\r
5565 EslSocketTxStart ( pPort,\r
5566 ppQueueHead,\r
5567 ppQueueTail,\r
5568 ppActive,\r
5569 ppFree );\r
5570 }\r
5571 }\r
5572\r
5573 //\r
5574 // Release this packet\r
5575 //\r
5576 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
5577\r
5578 //\r
5579 // Finish the close operation if necessary\r
5580 //\r
5581 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
5582 //\r
5583 // Indicate that the transmit is complete\r
5584 //\r
5585 EslSocketPortCloseTxDone ( pPort );\r
5586 }\r
5587\r
5588 DBG_EXIT ( );\r
5589}\r
5590\r
5591\r
5592/**\r
5593 Transmit data using a network connection.\r
5594\r
5595 This support routine starts a transmit operation on the\r
5596 underlying network layer.\r
5597\r
5598 The network specific code calls this routine to start a\r
5599 transmit operation. See the \ref TransmitEngine section.\r
5600\r
5601 @param [in] pPort Address of an ::ESL_PORT structure\r
5602 @param [in] ppQueueHead Transmit queue head address\r
5603 @param [in] ppQueueTail Transmit queue tail address\r
5604 @param [in] ppActive Active transmit queue address\r
5605 @param [in] ppFree Free transmit queue address\r
5606\r
5607 **/\r
5608VOID\r
5609EslSocketTxStart (\r
5610 IN ESL_PORT * pPort,\r
5611 IN ESL_PACKET ** ppQueueHead,\r
5612 IN ESL_PACKET ** ppQueueTail,\r
5613 IN ESL_IO_MGMT ** ppActive,\r
5614 IN ESL_IO_MGMT ** ppFree\r
5615 )\r
5616{\r
5617 UINT8 * pBuffer;\r
5618 ESL_IO_MGMT * pIo;\r
5619 ESL_PACKET * pNextPacket;\r
5620 ESL_PACKET * pPacket;\r
5621 VOID ** ppTokenData;\r
5622 ESL_SOCKET * pSocket;\r
5623 EFI_STATUS Status;\r
5624\r
5625 DBG_ENTER ( );\r
5626\r
5627 //\r
5628 // Assume success\r
5629 //\r
5630 Status = EFI_SUCCESS;\r
5631\r
5632 //\r
5633 // Get the packet from the queue head\r
5634 //\r
5635 pPacket = *ppQueueHead;\r
5636 pIo = *ppFree;\r
5637 if (( NULL != pPacket ) && ( NULL != pIo )) {\r
5638 pSocket = pPort->pSocket;\r
5639 //\r
5640 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead\r
5641 // |\r
5642 // V\r
5643 // +------------+ +------------+ +------------+ \r
5644 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
5645 // +------------+ +------------+ +------------+ \r
5646 // ^\r
5647 // |\r
5648 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail\r
5649 //\r
5650 //\r
5651 // Remove the packet from the queue\r
5652 //\r
5653 pNextPacket = pPacket->pNext;\r
5654 *ppQueueHead = pNextPacket;\r
5655 if ( NULL == pNextPacket ) {\r
5656 *ppQueueTail = NULL;\r
5657 }\r
5658 pPacket->pNext = NULL;\r
5659\r
5660 //\r
5661 // Eliminate the need for IP4 and UDP4 specific routines by\r
5662 // connecting the token with the TX data control structure here.\r
5663 //\r
5664 // +--------------------+ +--------------------+\r
5665 // | ESL_IO_MGMT | | ESL_PACKET |\r
5666 // | | | |\r
5667 // | +---------------+ +----------------+ |\r
5668 // | | Token | | Buffer Length | |\r
5669 // | | TxData --> | Buffer Address | |\r
5670 // | | | +----------------+---+\r
5671 // | | Event | | Data Buffer |\r
5672 // +----+---------------+ | |\r
5673 // +--------------------+\r
5674 //\r
5675 // Compute the address of the TxData pointer in the token\r
5676 //\r
5677 pBuffer = (UINT8 *)&pIo->Token;\r
5678 pBuffer = &pBuffer[ pSocket->TxTokenOffset ];\r
5679 ppTokenData = (VOID **)pBuffer;\r
5680\r
5681 //\r
5682 // Compute the address of the TX data control structure in the packet\r
5683 //\r
5684 // * EFI_IP4_TRANSMIT_DATA\r
5685 // * EFI_TCP4_TRANSMIT_DATA\r
5686 // * EFI_UDP4_TRANSMIT_DATA\r
5687 //\r
5688 pBuffer = (UINT8 *)pPacket;\r
5689 pBuffer = &pBuffer[ pSocket->TxPacketOffset ];\r
5690\r
5691 //\r
5692 // Connect the token to the transmit data control structure\r
5693 //\r
5694 *ppTokenData = (VOID **)pBuffer;\r
5695\r
5696 //\r
5697 // Display the results\r
5698 //\r
5699 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
5700 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",\r
5701 pIo,\r
5702 pPacket ));\r
5703\r
5704 //\r
5705 // Start the transmit operation\r
5706 //\r
5707 Status = pPort->pfnTxStart ( pPort->pProtocol.v,\r
5708 &pIo->Token );\r
5709 if ( !EFI_ERROR ( Status )) {\r
5710 //\r
5711 // Connect the structures\r
5712 //\r
5713 pIo->pPacket = pPacket;\r
5714\r
5715 //\r
5716 // +-------------+ +-------------+ +-------------+ \r
5717 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
5718 // +-------------+ +-------------+ +-------------+ \r
5719 // ^\r
5720 // |\r
5721 // *ppFree: pPort->pTxFree or pTxOobFree\r
5722 //\r
5723 //\r
5724 // Remove the IO structure from the queue\r
5725 //\r
5726 *ppFree = pIo->pNext;\r
5727 \r
5728 //\r
5729 // *ppActive: pPort->pTxActive or pTxOobActive\r
5730 // |\r
5731 // V\r
5732 // +-------------+ +-------------+ +-------------+ \r
5733 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
5734 // +-------------+ +-------------+ +-------------+ \r
5735 //\r
5736 //\r
5737 // Mark this packet as active\r
5738 //\r
5739 pIo->pPacket = pPacket;\r
5740 pIo->pNext = *ppActive;\r
5741 *ppActive = pIo;\r
5742 }\r
5743 else {\r
5744 if ( EFI_SUCCESS == pSocket->TxError ) {\r
5745 pSocket->TxError = Status;\r
5746 }\r
5747\r
5748 //\r
5749 // Discard the transmit buffer\r
5750 //\r
5751 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
5752 }\r
5753 }\r
5754\r
5755 DBG_EXIT ( );\r
5756}\r