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