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