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