8a67d61d |
1 | /** @file\r |
2 | \r |
3 | Copyright (c) 2005 - 2006, Intel Corporation\r |
4 | All rights reserved. This program and the accompanying materials\r |
5 | are licensed and made available under the terms and conditions of the BSD License\r |
6 | which accompanies this distribution. The full text of the license may be found at\r |
7 | http://opensource.org/licenses/bsd-license.php\r |
8 | \r |
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
11 | \r |
12 | Module Name:\r |
13 | \r |
14 | SockInterface.c\r |
15 | \r |
16 | Abstract:\r |
17 | \r |
18 | \r |
19 | **/\r |
20 | \r |
21 | \r |
22 | #include "SockImpl.h"\r |
23 | \r |
24 | \r |
25 | /**\r |
26 | Check whether the Event is in the List.\r |
27 | \r |
28 | @param List Pointer to the token list to be searched.\r |
29 | @param Event The event to be checked.\r |
30 | \r |
31 | @retval BOOLEAN If TRUE, the specific Event exists in the List. If\r |
32 | FALSE, the specific Event is not in the List.\r |
33 | \r |
34 | **/\r |
8a67d61d |
35 | BOOLEAN\r |
36 | SockTokenExistedInList (\r |
e48e37fc |
37 | IN LIST_ENTRY *List,\r |
8a67d61d |
38 | IN EFI_EVENT Event\r |
39 | )\r |
40 | {\r |
e48e37fc |
41 | LIST_ENTRY *ListEntry;\r |
8a67d61d |
42 | SOCK_TOKEN *SockToken;\r |
43 | \r |
44 | NET_LIST_FOR_EACH (ListEntry, List) {\r |
45 | SockToken = NET_LIST_USER_STRUCT (\r |
46 | ListEntry,\r |
47 | SOCK_TOKEN,\r |
48 | TokenList\r |
49 | );\r |
50 | \r |
51 | if (Event == SockToken->Token->Event) {\r |
52 | return TRUE;\r |
53 | }\r |
54 | }\r |
55 | \r |
56 | return FALSE;\r |
57 | }\r |
58 | \r |
59 | \r |
60 | /**\r |
61 | Call SockTokenExistedInList() to check whether the Event is\r |
62 | in the related socket's lists.\r |
63 | \r |
64 | @param Sock Pointer to the instance's socket.\r |
65 | @param Event The event to be checked.\r |
66 | \r |
67 | @return The specific Event exists in one of socket's lists or not.\r |
68 | \r |
69 | **/\r |
70 | BOOLEAN\r |
71 | SockTokenExisted (\r |
72 | IN SOCKET *Sock,\r |
73 | IN EFI_EVENT Event\r |
74 | )\r |
75 | {\r |
76 | \r |
77 | if (SockTokenExistedInList (&Sock->SndTokenList, Event) ||\r |
78 | SockTokenExistedInList (&Sock->ProcessingSndTokenList, Event) ||\r |
79 | SockTokenExistedInList (&Sock->RcvTokenList, Event) ||\r |
80 | SockTokenExistedInList (&Sock->ListenTokenList, Event)\r |
81 | ) {\r |
82 | \r |
83 | return TRUE;\r |
84 | }\r |
85 | \r |
86 | if ((Sock->ConnectionToken != NULL) &&\r |
87 | (Sock->ConnectionToken->Event == Event)) {\r |
88 | \r |
89 | return TRUE;\r |
90 | }\r |
91 | \r |
92 | if ((Sock->CloseToken != NULL) && (Sock->CloseToken->Event == Event)) {\r |
93 | return TRUE;\r |
94 | }\r |
95 | \r |
96 | return FALSE;\r |
97 | }\r |
98 | \r |
99 | \r |
100 | /**\r |
101 | Buffer a token into the specific list of socket Sock.\r |
102 | \r |
103 | @param Sock Pointer to the instance's socket.\r |
104 | @param List Pointer to the list to store the token.\r |
105 | @param Token Pointer to the token to be buffered.\r |
106 | @param DataLen The data length of the buffer contained in Token.\r |
107 | \r |
108 | @return Pointer to the token that wraps Token. If NULL, error condition occurred.\r |
109 | \r |
110 | **/\r |
111 | SOCK_TOKEN *\r |
112 | SockBufferToken (\r |
113 | IN SOCKET *Sock,\r |
e48e37fc |
114 | IN LIST_ENTRY *List,\r |
8a67d61d |
115 | IN VOID *Token,\r |
116 | IN UINT32 DataLen\r |
117 | )\r |
118 | {\r |
119 | SOCK_TOKEN *SockToken;\r |
120 | \r |
e48e37fc |
121 | SockToken = AllocatePool (sizeof (SOCK_TOKEN));\r |
8a67d61d |
122 | if (NULL == SockToken) {\r |
123 | \r |
e48e37fc |
124 | DEBUG ((EFI_D_ERROR, "SockBufferIOToken: No Memory "\r |
8a67d61d |
125 | "to allocate SockToken\n"));\r |
126 | \r |
127 | return NULL;\r |
128 | }\r |
129 | \r |
130 | SockToken->Sock = Sock;\r |
131 | SockToken->Token = (SOCK_COMPLETION_TOKEN *) Token;\r |
132 | SockToken->RemainDataLen = DataLen;\r |
e48e37fc |
133 | InsertTailList (List, &SockToken->TokenList);\r |
8a67d61d |
134 | \r |
135 | return SockToken;\r |
136 | }\r |
137 | \r |
138 | \r |
139 | /**\r |
140 | Destory the socket Sock and its associated protocol control block.\r |
141 | \r |
142 | @param Sock The socket to be destroyed.\r |
143 | \r |
144 | @retval EFI_SUCCESS The socket Sock is destroyed successfully.\r |
145 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r |
146 | \r |
147 | **/\r |
148 | EFI_STATUS\r |
149 | SockDestroyChild (\r |
150 | IN SOCKET *Sock\r |
151 | )\r |
152 | {\r |
153 | EFI_STATUS Status;\r |
154 | \r |
155 | ASSERT (Sock && Sock->ProtoHandler);\r |
156 | \r |
157 | if (Sock->IsDestroyed) {\r |
158 | return EFI_SUCCESS;\r |
159 | }\r |
160 | \r |
161 | Sock->IsDestroyed = TRUE;\r |
162 | \r |
e48e37fc |
163 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
164 | if (EFI_ERROR (Status)) {\r |
165 | \r |
e48e37fc |
166 | DEBUG ((EFI_D_ERROR, "SockDestroyChild: Get the lock to "\r |
8a67d61d |
167 | "access socket failed with %r\n", Status));\r |
168 | \r |
169 | return EFI_ACCESS_DENIED;\r |
170 | }\r |
171 | \r |
172 | //\r |
173 | // force protocol layer to detach the PCB\r |
174 | //\r |
175 | Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);\r |
176 | \r |
177 | if (EFI_ERROR (Status)) {\r |
178 | \r |
e48e37fc |
179 | DEBUG ((EFI_D_ERROR, "SockDestroyChild: Protocol detach socket"\r |
8a67d61d |
180 | " failed with %r\n", Status));\r |
181 | \r |
182 | Sock->IsDestroyed = FALSE;\r |
183 | } else if (SOCK_IS_CONFIGURED (Sock)) {\r |
184 | \r |
185 | SockConnFlush (Sock);\r |
186 | SockSetState (Sock, SO_CLOSED);\r |
187 | \r |
188 | Sock->ConfigureState = SO_UNCONFIGURED;\r |
189 | }\r |
190 | \r |
e48e37fc |
191 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
192 | \r |
193 | if (EFI_ERROR (Status)) {\r |
194 | return Status;\r |
195 | }\r |
196 | \r |
197 | SockDestroy (Sock);\r |
198 | return EFI_SUCCESS;\r |
199 | }\r |
200 | \r |
201 | \r |
202 | /**\r |
203 | Create a socket and its associated protocol control block\r |
204 | with the intial data SockInitData and protocol specific\r |
205 | data ProtoData.\r |
206 | \r |
207 | @param SockInitData Inital data to setting the socket.\r |
208 | @param ProtoData Pointer to the protocol specific data.\r |
209 | @param Len Length of the protocol specific data.\r |
210 | \r |
211 | @return Pointer to the newly created socket. If NULL, error condition occured.\r |
212 | \r |
213 | **/\r |
214 | SOCKET *\r |
215 | SockCreateChild (\r |
4f6e31e4 |
216 | IN SOCK_INIT_DATA *SockInitData\r |
8a67d61d |
217 | )\r |
218 | {\r |
219 | SOCKET *Sock;\r |
220 | EFI_STATUS Status;\r |
221 | \r |
8a67d61d |
222 | //\r |
223 | // create a new socket\r |
224 | //\r |
225 | Sock = SockCreate (SockInitData);\r |
226 | if (NULL == Sock) {\r |
227 | \r |
e48e37fc |
228 | DEBUG ((EFI_D_ERROR, "SockCreateChild: No resource to "\r |
8a67d61d |
229 | "create a new socket\n"));\r |
230 | \r |
231 | return NULL;\r |
232 | }\r |
233 | \r |
e48e37fc |
234 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
235 | if (EFI_ERROR (Status)) {\r |
236 | \r |
e48e37fc |
237 | DEBUG ((EFI_D_ERROR, "SockCreateChild: Get the lock to "\r |
8a67d61d |
238 | "access socket failed with %r\n", Status));\r |
239 | \r |
240 | SockDestroy (Sock);\r |
241 | return NULL;\r |
242 | }\r |
243 | //\r |
244 | // inform the protocol layer to attach the socket\r |
245 | // with a new protocol control block\r |
246 | //\r |
247 | Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);\r |
248 | if (EFI_ERROR (Status)) {\r |
249 | \r |
e48e37fc |
250 | DEBUG ((EFI_D_ERROR, "SockCreateChild: Protocol failed to"\r |
8a67d61d |
251 | " attach a socket with %r\n", Status));\r |
252 | \r |
253 | SockDestroy (Sock);\r |
254 | Sock = NULL;\r |
255 | }\r |
256 | \r |
e48e37fc |
257 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
258 | return Sock;\r |
259 | }\r |
260 | \r |
261 | \r |
262 | /**\r |
263 | Configure the specific socket Sock using configuration data\r |
264 | ConfigData.\r |
265 | \r |
266 | @param Sock Pointer to the socket to be configured.\r |
267 | @param ConfigData Pointer to the configuration data.\r |
268 | \r |
269 | @retval EFI_SUCCESS The socket is configured successfully.\r |
270 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket or the\r |
271 | socket is already configured.\r |
272 | \r |
273 | **/\r |
274 | EFI_STATUS\r |
275 | SockConfigure (\r |
276 | IN SOCKET *Sock,\r |
277 | IN VOID *ConfigData\r |
278 | )\r |
279 | {\r |
280 | EFI_STATUS Status;\r |
281 | \r |
e48e37fc |
282 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
283 | if (EFI_ERROR (Status)) {\r |
284 | \r |
e48e37fc |
285 | DEBUG ((EFI_D_ERROR, "SockConfigure: Get the access for "\r |
8a67d61d |
286 | "socket failed with %r", Status));\r |
287 | \r |
288 | return EFI_ACCESS_DENIED;\r |
289 | }\r |
290 | \r |
291 | if (SOCK_IS_CONFIGURED (Sock)) {\r |
292 | Status = EFI_ACCESS_DENIED;\r |
293 | goto OnExit;\r |
294 | }\r |
295 | \r |
296 | ASSERT (Sock->State == SO_CLOSED);\r |
297 | \r |
298 | Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);\r |
299 | \r |
300 | OnExit:\r |
e48e37fc |
301 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
302 | \r |
303 | return Status;\r |
304 | }\r |
305 | \r |
306 | \r |
307 | /**\r |
308 | Initiate a connection establishment process.\r |
309 | \r |
310 | @param Sock Pointer to the socket to initiate the initate the\r |
311 | connection.\r |
312 | @param Token Pointer to the token used for the connection\r |
313 | operation.\r |
314 | \r |
315 | @retval EFI_SUCCESS The connection is initialized successfully.\r |
316 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r |
317 | socket is closed, or the socket is not configured to\r |
318 | be an active one, or the token is already in one of\r |
319 | this socket's lists.\r |
320 | @retval EFI_NO_MAPPING The IP address configuration operation is not\r |
321 | finished.\r |
322 | @retval EFI_NOT_STARTED The socket is not configured.\r |
323 | \r |
324 | **/\r |
325 | EFI_STATUS\r |
326 | SockConnect (\r |
327 | IN SOCKET *Sock,\r |
328 | IN VOID *Token\r |
329 | )\r |
330 | {\r |
331 | EFI_STATUS Status;\r |
332 | EFI_EVENT Event;\r |
333 | \r |
e48e37fc |
334 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
335 | if (EFI_ERROR (Status)) {\r |
336 | \r |
e48e37fc |
337 | DEBUG ((EFI_D_ERROR, "SockConnect: Get the access for "\r |
8a67d61d |
338 | "socket failed with %r", Status));\r |
339 | \r |
340 | return EFI_ACCESS_DENIED;\r |
341 | }\r |
342 | \r |
343 | if (SOCK_IS_NO_MAPPING (Sock)) {\r |
344 | Status = EFI_NO_MAPPING;\r |
345 | goto OnExit;\r |
346 | }\r |
347 | \r |
348 | if (SOCK_IS_UNCONFIGURED (Sock)) {\r |
349 | \r |
350 | Status = EFI_NOT_STARTED;\r |
351 | goto OnExit;\r |
352 | }\r |
353 | \r |
354 | if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {\r |
355 | \r |
356 | Status = EFI_ACCESS_DENIED;\r |
357 | goto OnExit;\r |
358 | }\r |
359 | \r |
360 | Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r |
361 | \r |
362 | if (SockTokenExisted (Sock, Event)) {\r |
363 | \r |
364 | Status = EFI_ACCESS_DENIED;\r |
365 | goto OnExit;\r |
366 | }\r |
367 | \r |
368 | Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;\r |
369 | SockSetState (Sock, SO_CONNECTING);\r |
370 | Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);\r |
371 | \r |
372 | OnExit:\r |
e48e37fc |
373 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
374 | return Status;\r |
375 | }\r |
376 | \r |
377 | \r |
378 | /**\r |
379 | Issue a listen token to get an existed connected network instance\r |
380 | or wait for a connection if there is none.\r |
381 | \r |
382 | @param Sock Pointer to the socket to accept connections.\r |
383 | @param Token The token to accept a connection.\r |
384 | \r |
385 | @retval EFI_SUCCESS Either a connection is accpeted or the Token is\r |
386 | buffered for further acception.\r |
387 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r |
388 | socket is closed, or the socket is not configured to\r |
389 | be a passive one, or the token is already in one of\r |
390 | this socket's lists.\r |
391 | @retval EFI_NO_MAPPING The IP address configuration operation is not\r |
392 | finished.\r |
393 | @retval EFI_NOT_STARTED The socket is not configured.\r |
394 | @retval EFI_OUT_OF_RESOURCE Failed to buffer the Token due to memory limit.\r |
395 | \r |
396 | **/\r |
397 | EFI_STATUS\r |
398 | SockAccept (\r |
399 | IN SOCKET *Sock,\r |
400 | IN VOID *Token\r |
401 | )\r |
402 | {\r |
403 | EFI_TCP4_LISTEN_TOKEN *ListenToken;\r |
e48e37fc |
404 | LIST_ENTRY *ListEntry;\r |
8a67d61d |
405 | EFI_STATUS Status;\r |
406 | SOCKET *Socket;\r |
407 | EFI_EVENT Event;\r |
408 | \r |
409 | ASSERT (SOCK_STREAM == Sock->Type);\r |
410 | \r |
e48e37fc |
411 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
412 | if (EFI_ERROR (Status)) {\r |
413 | \r |
e48e37fc |
414 | DEBUG ((EFI_D_ERROR, "SockAccept: Get the access for socket"\r |
8a67d61d |
415 | " failed with %r", Status));\r |
416 | \r |
417 | return EFI_ACCESS_DENIED;\r |
418 | }\r |
419 | \r |
420 | if (SOCK_IS_NO_MAPPING (Sock)) {\r |
421 | Status = EFI_NO_MAPPING;\r |
422 | goto Exit;\r |
423 | }\r |
424 | \r |
425 | if (SOCK_IS_UNCONFIGURED (Sock)) {\r |
426 | \r |
427 | Status = EFI_NOT_STARTED;\r |
428 | goto Exit;\r |
429 | }\r |
430 | \r |
431 | if (!SOCK_IS_LISTENING (Sock)) {\r |
432 | \r |
433 | Status = EFI_ACCESS_DENIED;\r |
434 | goto Exit;\r |
435 | }\r |
436 | \r |
437 | Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r |
438 | \r |
439 | if (SockTokenExisted (Sock, Event)) {\r |
440 | \r |
441 | Status = EFI_ACCESS_DENIED;\r |
442 | goto Exit;\r |
443 | }\r |
444 | \r |
445 | ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;\r |
446 | \r |
447 | //\r |
448 | // Check if a connection has already in this Sock->ConnectionList\r |
449 | //\r |
450 | NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {\r |
451 | \r |
452 | Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);\r |
453 | \r |
454 | if (SOCK_IS_CONNECTED (Socket)) {\r |
455 | ListenToken->NewChildHandle = Socket->SockHandle;\r |
456 | SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r |
457 | \r |
e48e37fc |
458 | RemoveEntryList (ListEntry);\r |
8a67d61d |
459 | \r |
460 | ASSERT (Socket->Parent);\r |
461 | \r |
462 | Socket->Parent->ConnCnt--;\r |
463 | \r |
e48e37fc |
464 | DEBUG (\r |
465 | (EFI_D_WARN,\r |
466 | "SockAccept: Accept a socket, now conncount is %d",\r |
467 | Socket->Parent->ConnCnt)\r |
8a67d61d |
468 | );\r |
469 | Socket->Parent = NULL;\r |
470 | \r |
471 | goto Exit;\r |
472 | }\r |
473 | }\r |
474 | \r |
475 | //\r |
476 | // Buffer this token for latter incoming connection request\r |
477 | //\r |
478 | if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {\r |
479 | \r |
480 | Status = EFI_OUT_OF_RESOURCES;\r |
481 | }\r |
482 | \r |
483 | Exit:\r |
e48e37fc |
484 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
485 | \r |
486 | return Status;\r |
487 | }\r |
488 | \r |
489 | \r |
490 | /**\r |
491 | Issue a token with data to the socket to send out.\r |
492 | \r |
493 | @param Sock Pointer to the socket to process the token with\r |
494 | data.\r |
495 | @param Token The token with data that needs to send out.\r |
496 | \r |
497 | @retval EFI_SUCCESS The token is processed successfully.\r |
498 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r |
499 | socket is closed, or the socket is not in a\r |
500 | synchronized state , or the token is already in one\r |
501 | of this socket's lists.\r |
502 | @retval EFI_NO_MAPPING The IP address configuration operation is not\r |
503 | finished.\r |
504 | @retval EFI_NOT_STARTED The socket is not configured.\r |
505 | @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r |
506 | \r |
507 | **/\r |
508 | EFI_STATUS\r |
509 | SockSend (\r |
510 | IN SOCKET *Sock,\r |
511 | IN VOID *Token\r |
512 | )\r |
513 | {\r |
514 | SOCK_IO_TOKEN *SndToken;\r |
515 | EFI_EVENT Event;\r |
516 | UINT32 FreeSpace;\r |
517 | EFI_TCP4_TRANSMIT_DATA *TxData;\r |
518 | EFI_STATUS Status;\r |
519 | SOCK_TOKEN *SockToken;\r |
520 | UINT32 DataLen;\r |
521 | \r |
522 | ASSERT (SOCK_STREAM == Sock->Type);\r |
523 | \r |
e48e37fc |
524 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
525 | if (EFI_ERROR (Status)) {\r |
526 | \r |
e48e37fc |
527 | DEBUG ((EFI_D_ERROR, "SockSend: Get the access for socket"\r |
8a67d61d |
528 | " failed with %r", Status));\r |
529 | \r |
530 | return EFI_ACCESS_DENIED;\r |
531 | }\r |
532 | \r |
533 | if (SOCK_IS_NO_MAPPING (Sock)) {\r |
534 | Status = EFI_NO_MAPPING;\r |
535 | goto Exit;\r |
536 | }\r |
537 | \r |
538 | SndToken = (SOCK_IO_TOKEN *) Token;\r |
539 | TxData = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;\r |
540 | \r |
541 | if (SOCK_IS_UNCONFIGURED (Sock)) {\r |
542 | Status = EFI_NOT_STARTED;\r |
543 | goto Exit;\r |
544 | }\r |
545 | \r |
546 | if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {\r |
547 | \r |
548 | Status = EFI_ACCESS_DENIED;\r |
549 | goto Exit;\r |
550 | }\r |
551 | \r |
552 | //\r |
553 | // check if a token is already in the token buffer\r |
554 | //\r |
555 | Event = SndToken->Token.Event;\r |
556 | \r |
557 | if (SockTokenExisted (Sock, Event)) {\r |
558 | Status = EFI_ACCESS_DENIED;\r |
559 | goto Exit;\r |
560 | }\r |
561 | \r |
4eb65aff |
562 | DataLen = (UINT32) TxData->DataLength;\r |
8a67d61d |
563 | \r |
564 | //\r |
565 | // process this sending token now or buffer it only?\r |
566 | //\r |
567 | FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r |
568 | \r |
569 | if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {\r |
570 | \r |
571 | SockToken = SockBufferToken (\r |
572 | Sock,\r |
573 | &Sock->SndTokenList,\r |
574 | SndToken,\r |
575 | DataLen\r |
576 | );\r |
577 | \r |
578 | if (NULL == SockToken) {\r |
579 | Status = EFI_OUT_OF_RESOURCES;\r |
580 | }\r |
581 | } else {\r |
582 | \r |
583 | SockToken = SockBufferToken (\r |
584 | Sock,\r |
585 | &Sock->ProcessingSndTokenList,\r |
586 | SndToken,\r |
587 | DataLen\r |
588 | );\r |
589 | \r |
590 | if (NULL == SockToken) {\r |
e48e37fc |
591 | DEBUG ((EFI_D_ERROR, "SockSend: Failed to buffer IO token into"\r |
8a67d61d |
592 | " socket processing SndToken List\n", Status));\r |
593 | \r |
594 | Status = EFI_OUT_OF_RESOURCES;\r |
595 | goto Exit;\r |
596 | }\r |
597 | \r |
598 | Status = SockProcessTcpSndData (Sock, TxData);\r |
599 | \r |
600 | if (EFI_ERROR (Status)) {\r |
e48e37fc |
601 | DEBUG ((EFI_D_ERROR, "SockSend: Failed to process "\r |
8a67d61d |
602 | "Snd Data\n", Status));\r |
603 | \r |
e48e37fc |
604 | RemoveEntryList (&(SockToken->TokenList));\r |
605 | gBS->FreePool (SockToken);\r |
8a67d61d |
606 | }\r |
607 | }\r |
608 | \r |
609 | Exit:\r |
e48e37fc |
610 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
611 | return Status;\r |
612 | }\r |
613 | \r |
614 | \r |
615 | /**\r |
616 | Issue a token to get data from the socket.\r |
617 | \r |
618 | @param Sock Pointer to the socket to get data from.\r |
619 | @param Token The token to store the received data from the\r |
620 | socket.\r |
621 | \r |
622 | @retval EFI_SUCCESS The token is processed successfully.\r |
623 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r |
624 | socket is closed, or the socket is not in a\r |
625 | synchronized state , or the token is already in one\r |
626 | of this socket's lists.\r |
627 | @retval EFI_NO_MAPPING The IP address configuration operation is not\r |
628 | finished.\r |
629 | @retval EFI_NOT_STARTED The socket is not configured.\r |
630 | @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.\r |
631 | @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r |
632 | \r |
633 | **/\r |
634 | EFI_STATUS\r |
635 | SockRcv (\r |
636 | IN SOCKET *Sock,\r |
637 | IN VOID *Token\r |
638 | )\r |
639 | {\r |
640 | SOCK_IO_TOKEN *RcvToken;\r |
641 | UINT32 RcvdBytes;\r |
642 | EFI_STATUS Status;\r |
643 | EFI_EVENT Event;\r |
644 | \r |
645 | ASSERT (SOCK_STREAM == Sock->Type);\r |
646 | \r |
e48e37fc |
647 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
648 | if (EFI_ERROR (Status)) {\r |
649 | \r |
e48e37fc |
650 | DEBUG ((EFI_D_ERROR, "SockRcv: Get the access for socket"\r |
8a67d61d |
651 | " failed with %r", Status));\r |
652 | \r |
653 | return EFI_ACCESS_DENIED;\r |
654 | }\r |
655 | \r |
656 | if (SOCK_IS_NO_MAPPING (Sock)) {\r |
657 | \r |
658 | Status = EFI_NO_MAPPING;\r |
659 | goto Exit;\r |
660 | }\r |
661 | \r |
662 | if (SOCK_IS_UNCONFIGURED (Sock)) {\r |
663 | \r |
664 | Status = EFI_NOT_STARTED;\r |
665 | goto Exit;\r |
666 | }\r |
667 | \r |
668 | if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {\r |
669 | \r |
670 | Status = EFI_ACCESS_DENIED;\r |
671 | goto Exit;\r |
672 | }\r |
673 | \r |
674 | RcvToken = (SOCK_IO_TOKEN *) Token;\r |
675 | \r |
676 | //\r |
677 | // check if a token is already in the token buffer of this socket\r |
678 | //\r |
679 | Event = RcvToken->Token.Event;\r |
680 | if (SockTokenExisted (Sock, Event)) {\r |
681 | Status = EFI_ACCESS_DENIED;\r |
682 | goto Exit;\r |
683 | }\r |
684 | \r |
685 | RcvToken = (SOCK_IO_TOKEN *) Token;\r |
686 | RcvdBytes = GET_RCV_DATASIZE (Sock);\r |
687 | \r |
688 | //\r |
689 | // check whether an error has happened before\r |
690 | //\r |
691 | if (EFI_ABORTED != Sock->SockError) {\r |
692 | \r |
693 | SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);\r |
694 | Sock->SockError = EFI_ABORTED;\r |
695 | goto Exit;\r |
696 | }\r |
697 | \r |
698 | //\r |
699 | // check whether can not receive and there is no any\r |
700 | // data buffered in Sock->RcvBuffer\r |
701 | //\r |
702 | if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {\r |
703 | \r |
704 | Status = EFI_CONNECTION_FIN;\r |
705 | goto Exit;\r |
706 | }\r |
707 | \r |
708 | if (RcvdBytes != 0) {\r |
709 | Status = SockProcessRcvToken (Sock, RcvToken);\r |
710 | \r |
711 | if (EFI_ERROR (Status)) {\r |
712 | goto Exit;\r |
713 | }\r |
714 | \r |
715 | Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);\r |
716 | } else {\r |
717 | \r |
718 | if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {\r |
719 | Status = EFI_OUT_OF_RESOURCES;\r |
720 | }\r |
721 | }\r |
722 | \r |
723 | Exit:\r |
e48e37fc |
724 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
725 | return Status;\r |
726 | }\r |
727 | \r |
728 | \r |
729 | /**\r |
730 | Reset the socket and its associated protocol control block.\r |
731 | \r |
732 | @param Sock Pointer to the socket to be flushed.\r |
733 | \r |
734 | @retval EFI_SUCCESS The socket is flushed successfully.\r |
735 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r |
736 | \r |
737 | **/\r |
738 | EFI_STATUS\r |
739 | SockFlush (\r |
740 | IN SOCKET *Sock\r |
741 | )\r |
742 | {\r |
743 | EFI_STATUS Status;\r |
744 | \r |
745 | ASSERT (SOCK_STREAM == Sock->Type);\r |
746 | \r |
e48e37fc |
747 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
748 | if (EFI_ERROR (Status)) {\r |
749 | \r |
e48e37fc |
750 | DEBUG ((EFI_D_ERROR, "SockFlush: Get the access for socket"\r |
8a67d61d |
751 | " failed with %r", Status));\r |
752 | \r |
753 | return EFI_ACCESS_DENIED;\r |
754 | }\r |
755 | \r |
756 | if (!SOCK_IS_CONFIGURED (Sock)) {\r |
757 | goto Exit;\r |
758 | }\r |
759 | \r |
760 | Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);\r |
761 | if (EFI_ERROR (Status)) {\r |
762 | \r |
e48e37fc |
763 | DEBUG ((EFI_D_ERROR, "SockFlush: Protocol failed handling"\r |
8a67d61d |
764 | " SOCK_FLUSH with %r", Status));\r |
765 | \r |
766 | goto Exit;\r |
767 | }\r |
768 | \r |
769 | SOCK_ERROR (Sock, EFI_ABORTED);\r |
770 | SockConnFlush (Sock);\r |
771 | SockSetState (Sock, SO_CLOSED);\r |
772 | \r |
773 | Sock->ConfigureState = SO_UNCONFIGURED;\r |
774 | \r |
775 | Exit:\r |
e48e37fc |
776 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
777 | return Status;\r |
778 | }\r |
779 | \r |
780 | \r |
781 | /**\r |
782 | Close or abort the socket associated connection.\r |
783 | \r |
784 | @param Sock Pointer to the socket of the connection to close or\r |
785 | abort.\r |
786 | @param Token The token for close operation.\r |
787 | @param OnAbort TRUE for aborting the connection, FALSE to close it.\r |
788 | \r |
789 | @retval EFI_SUCCESS The close or abort operation is initialized\r |
790 | successfully.\r |
791 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r |
792 | socket is closed, or the socket is not in a\r |
793 | synchronized state , or the token is already in one\r |
794 | of this socket's lists.\r |
795 | @retval EFI_NO_MAPPING The IP address configuration operation is not\r |
796 | finished.\r |
797 | @retval EFI_NOT_STARTED The socket is not configured.\r |
798 | \r |
799 | **/\r |
800 | EFI_STATUS\r |
801 | SockClose (\r |
802 | IN SOCKET *Sock,\r |
803 | IN VOID *Token,\r |
804 | IN BOOLEAN OnAbort\r |
805 | )\r |
806 | {\r |
807 | EFI_STATUS Status;\r |
808 | EFI_EVENT Event;\r |
809 | \r |
810 | ASSERT (SOCK_STREAM == Sock->Type);\r |
811 | \r |
e48e37fc |
812 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
813 | if (EFI_ERROR (Status)) {\r |
e48e37fc |
814 | DEBUG ((EFI_D_ERROR, "SockClose: Get the access for socket"\r |
8a67d61d |
815 | " failed with %r", Status));\r |
816 | \r |
817 | return EFI_ACCESS_DENIED;\r |
818 | }\r |
819 | \r |
820 | if (SOCK_IS_NO_MAPPING (Sock)) {\r |
821 | Status = EFI_NO_MAPPING;\r |
822 | goto Exit;\r |
823 | }\r |
824 | \r |
825 | if (SOCK_IS_UNCONFIGURED (Sock)) {\r |
826 | Status = EFI_NOT_STARTED;\r |
827 | goto Exit;\r |
828 | }\r |
829 | \r |
830 | if (SOCK_IS_DISCONNECTING (Sock)) {\r |
831 | Status = EFI_ACCESS_DENIED;\r |
832 | goto Exit;\r |
833 | }\r |
834 | \r |
835 | Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r |
836 | \r |
837 | if (SockTokenExisted (Sock, Event)) {\r |
838 | Status = EFI_ACCESS_DENIED;\r |
839 | goto Exit;\r |
840 | }\r |
841 | \r |
842 | Sock->CloseToken = Token;\r |
843 | SockSetState (Sock, SO_DISCONNECTING);\r |
844 | \r |
845 | if (OnAbort) {\r |
846 | Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);\r |
847 | } else {\r |
848 | Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);\r |
849 | }\r |
850 | \r |
851 | Exit:\r |
e48e37fc |
852 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
853 | return Status;\r |
854 | }\r |
855 | \r |
856 | \r |
857 | /**\r |
858 | Get the mode data of the low layer protocol.\r |
859 | \r |
860 | @param Sock Pointer to the socket to get mode data from.\r |
861 | @param Mode Pointer to the data to store the low layer mode\r |
862 | information.\r |
863 | \r |
864 | @retval EFI_SUCCESS The mode data is got successfully.\r |
865 | @retval EFI_NOT_STARTED The socket is not configured.\r |
866 | \r |
867 | **/\r |
868 | EFI_STATUS\r |
869 | SockGetMode (\r |
870 | IN SOCKET *Sock,\r |
871 | IN VOID *Mode\r |
872 | )\r |
873 | {\r |
874 | return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);\r |
875 | }\r |
876 | \r |
877 | \r |
878 | /**\r |
879 | Configure the low level protocol to join a multicast group for\r |
880 | this socket's connection.\r |
881 | \r |
882 | @param Sock Pointer to the socket of the connection to join the\r |
883 | specific multicast group.\r |
884 | @param GroupInfo Pointer to the multicast group info.\r |
885 | \r |
886 | @retval EFI_SUCCESS The configuration is done successfully.\r |
887 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r |
888 | @retval EFI_NOT_STARTED The socket is not configured.\r |
889 | \r |
890 | **/\r |
891 | EFI_STATUS\r |
892 | SockGroup (\r |
893 | IN SOCKET *Sock,\r |
894 | IN VOID *GroupInfo\r |
895 | )\r |
896 | {\r |
897 | EFI_STATUS Status;\r |
898 | \r |
e48e37fc |
899 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
900 | \r |
901 | if (EFI_ERROR (Status)) {\r |
902 | \r |
e48e37fc |
903 | DEBUG ((EFI_D_ERROR, "SockGroup: Get the access for socket"\r |
8a67d61d |
904 | " failed with %r", Status));\r |
905 | \r |
906 | return EFI_ACCESS_DENIED;\r |
907 | }\r |
908 | \r |
909 | if (SOCK_IS_UNCONFIGURED (Sock)) {\r |
910 | Status = EFI_NOT_STARTED;\r |
911 | goto Exit;\r |
912 | }\r |
913 | \r |
914 | Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);\r |
915 | \r |
916 | Exit:\r |
e48e37fc |
917 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
918 | return Status;\r |
919 | }\r |
920 | \r |
921 | \r |
922 | /**\r |
923 | Add or remove route information in IP route table associated\r |
924 | with this socket.\r |
925 | \r |
926 | @param Sock Pointer to the socket associated with the IP route\r |
927 | table to operate on.\r |
928 | @param RouteInfo Pointer to the route information to be processed.\r |
929 | \r |
930 | @retval EFI_SUCCESS The route table is updated successfully.\r |
931 | @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r |
932 | @retval EFI_NO_MAPPING The IP address configuration operation is not\r |
933 | finished.\r |
934 | @retval EFI_NOT_STARTED The socket is not configured.\r |
935 | \r |
936 | **/\r |
937 | EFI_STATUS\r |
938 | SockRoute (\r |
939 | IN SOCKET *Sock,\r |
940 | IN VOID *RouteInfo\r |
941 | )\r |
942 | {\r |
943 | EFI_STATUS Status;\r |
944 | \r |
e48e37fc |
945 | Status = EfiAcquireLockOrFail (&(Sock->Lock));\r |
8a67d61d |
946 | if (EFI_ERROR (Status)) {\r |
e48e37fc |
947 | DEBUG ((EFI_D_ERROR, "SockRoute: Get the access for socket"\r |
8a67d61d |
948 | " failed with %r", Status));\r |
949 | \r |
950 | return EFI_ACCESS_DENIED;\r |
951 | }\r |
952 | \r |
953 | if (SOCK_IS_NO_MAPPING (Sock)) {\r |
954 | Status = EFI_NO_MAPPING;\r |
955 | goto Exit;\r |
956 | }\r |
957 | \r |
958 | if (SOCK_IS_UNCONFIGURED (Sock)) {\r |
959 | Status = EFI_NOT_STARTED;\r |
960 | goto Exit;\r |
961 | }\r |
962 | \r |
963 | Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);\r |
964 | \r |
965 | Exit:\r |
e48e37fc |
966 | EfiReleaseLock (&(Sock->Lock));\r |
8a67d61d |
967 | return Status;\r |
968 | }\r |