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