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