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