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