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