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