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