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