• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   The implementation for Shell command IfConfig6.
3 
4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 #include "UefiShellNetwork2CommandsLib.h"
16 
17 enum {
18   IfConfig6OpList     = 1,
19   IfConfig6OpSet      = 2,
20   IfConfig6OpClear    = 3
21 };
22 
23 typedef enum {
24   VarCheckReserved      = -1,
25   VarCheckOk            = 0,
26   VarCheckDuplicate,
27   VarCheckConflict,
28   VarCheckUnknown,
29   VarCheckLackValue,
30   VarCheckOutOfMem
31 } VAR_CHECK_CODE;
32 
33 typedef enum {
34   FlagTypeSingle         = 0,
35   FlagTypeNeedVar,
36   FlagTypeNeedSet,
37   FlagTypeSkipUnknown
38 } VAR_CHECK_FLAG_TYPE;
39 
40 #define MACADDRMAXSIZE    32
41 #define PREFIXMAXLEN      16
42 
43 typedef struct _IFCONFIG6_INTERFACE_CB {
44   EFI_HANDLE                                  NicHandle;
45   LIST_ENTRY                                  Link;
46   EFI_IP6_CONFIG_PROTOCOL                     *IfCfg;
47   EFI_IP6_CONFIG_INTERFACE_INFO               *IfInfo;
48   EFI_IP6_CONFIG_INTERFACE_ID                 *IfId;
49   EFI_IP6_CONFIG_POLICY                       Policy;
50   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS    Xmits;
51   UINT32                                      DnsCnt;
52   EFI_IPv6_ADDRESS                            DnsAddr[1];
53 } IFCONFIG6_INTERFACE_CB;
54 
55 typedef struct _ARG_LIST ARG_LIST;
56 
57 struct _ARG_LIST {
58   ARG_LIST    *Next;
59   CHAR16      *Arg;
60 };
61 
62 typedef struct _IFCONFIG6_PRIVATE_DATA {
63   EFI_HANDLE  ImageHandle;
64   LIST_ENTRY  IfList;
65 
66   UINT32      OpCode;
67   CHAR16      *IfName;
68   ARG_LIST    *VarArg;
69 } IFCONFIG6_PRIVATE_DATA;
70 
71 typedef struct _VAR_CHECK_ITEM{
72   CHAR16                 *FlagStr;
73   UINT32                 FlagID;
74   UINT32                 ConflictMask;
75   VAR_CHECK_FLAG_TYPE    FlagType;
76 } VAR_CHECK_ITEM;
77 
78 
79 SHELL_PARAM_ITEM    mIfConfig6CheckList[] = {
80   {
81     L"-b",
82     TypeFlag
83   },
84   {
85     L"-s",
86     TypeMaxValue
87   },
88   {
89     L"-l",
90     TypeValue
91   },
92   {
93     L"-r",
94     TypeValue
95   },
96   {
97     L"-?",
98     TypeFlag
99   },
100   {
101     NULL,
102     TypeMax
103   },
104 };
105 
106 VAR_CHECK_ITEM  mIfConfig6SetCheckList[] = {
107   {
108    L"auto",
109     0x00000001,
110     0x00000001,
111     FlagTypeSingle
112   },
113   {
114     L"man",
115     0x00000002,
116     0x00000001,
117     FlagTypeSingle
118   },
119   {
120     L"host",
121     0x00000004,
122     0x00000002,
123     FlagTypeSingle
124   },
125   {
126     L"dad",
127     0x00000008,
128     0x00000004,
129     FlagTypeSingle
130   },
131   {
132     L"gw",
133     0x00000010,
134     0x00000008,
135     FlagTypeSingle
136   },
137   {
138     L"dns",
139     0x00000020,
140     0x00000010,
141     FlagTypeSingle
142   },
143   {
144     L"id",
145     0x00000040,
146     0x00000020,
147     FlagTypeSingle
148   },
149   {
150     NULL,
151     0x0,
152     0x0,
153     FlagTypeSkipUnknown
154   },
155 };
156 
157 /**
158   Free the ARG_LIST.
159 
160   @param List Pointer to ARG_LIST to free.
161 **/
162 VOID
IfConfig6FreeArgList(ARG_LIST * List)163 IfConfig6FreeArgList (
164   ARG_LIST       *List
165 )
166 {
167   ARG_LIST       *Next;
168   while (List->Next != NULL) {
169     Next = List->Next;
170     FreePool (List);
171     List = Next;
172   }
173 
174   FreePool (List);
175 }
176 
177 /**
178   Split a string with specified separator and save the substring to a list.
179 
180   @param[in]    String       The pointer of the input string.
181   @param[in]    Separator    The specified separator.
182 
183   @return The pointer of headnode of ARG_LIST.
184 
185 **/
186 ARG_LIST *
IfConfig6SplitStrToList(IN CONST CHAR16 * String,IN CHAR16 Separator)187 IfConfig6SplitStrToList (
188   IN CONST CHAR16    *String,
189   IN CHAR16          Separator
190   )
191 {
192   CHAR16      *Str;
193   CHAR16      *ArgStr;
194   ARG_LIST    *ArgList;
195   ARG_LIST    *ArgNode;
196 
197   if (String == NULL || *String == L'\0') {
198     return NULL;
199   }
200 
201   //
202   // Copy the CONST string to a local copy.
203   //
204   Str = AllocateCopyPool (StrSize (String), String);
205   if (Str == NULL) {
206     return NULL;
207   }
208   ArgStr  = Str;
209 
210   //
211   // init a node for the list head.
212   //
213   ArgNode = (ARG_LIST *) AllocateZeroPool (sizeof (ARG_LIST));
214   if (ArgNode == NULL) {
215     return NULL;
216   }
217   ArgList = ArgNode;
218 
219   //
220   // Split the local copy and save in the list node.
221   //
222   while (*Str != L'\0') {
223     if (*Str == Separator) {
224       *Str          = L'\0';
225       ArgNode->Arg  = ArgStr;
226       ArgStr        = Str + 1;
227       ArgNode->Next = (ARG_LIST *) AllocateZeroPool (sizeof (ARG_LIST));
228       if (ArgNode->Next == NULL) {
229         //
230         // Free the local copy of string stored in the first node
231         //
232         FreePool (ArgList->Arg);
233         IfConfig6FreeArgList (ArgList);
234         return NULL;
235       }
236       ArgNode = ArgNode->Next;
237     }
238 
239     Str++;
240   }
241 
242   ArgNode->Arg  = ArgStr;
243   ArgNode->Next = NULL;
244 
245   return ArgList;
246 }
247 
248 /**
249   Check the correctness of input Args with '-s' option.
250 
251   @param[in]    CheckList    The pointer of VAR_CHECK_ITEM array.
252   @param[in]    Name         The pointer of input arg.
253   @param[in]    Init         The switch to execute the check.
254 
255   @return The value of VAR_CHECK_CODE.
256 
257 **/
258 VAR_CHECK_CODE
IfConfig6RetriveCheckListByName(IN VAR_CHECK_ITEM * CheckList,IN CHAR16 * Name,IN BOOLEAN Init)259 IfConfig6RetriveCheckListByName(
260   IN VAR_CHECK_ITEM    *CheckList,
261   IN CHAR16            *Name,
262   IN BOOLEAN           Init
263 )
264 {
265   STATIC UINT32     CheckDuplicate;
266   STATIC UINT32     CheckConflict;
267   VAR_CHECK_CODE    RtCode;
268   UINT32            Index;
269   VAR_CHECK_ITEM    Arg;
270 
271   if (Init) {
272     CheckDuplicate = 0;
273     CheckConflict  = 0;
274     return VarCheckOk;
275   }
276 
277   RtCode  = VarCheckOk;
278   Index   = 0;
279   Arg     = CheckList[Index];
280 
281   //
282   // Check the Duplicated/Conflicted/Unknown input Args.
283   //
284   while (Arg.FlagStr != NULL) {
285     if (StrCmp (Arg.FlagStr, Name) == 0) {
286 
287       if (CheckDuplicate & Arg.FlagID) {
288         RtCode = VarCheckDuplicate;
289         break;
290       }
291 
292       if (CheckConflict & Arg.ConflictMask) {
293         RtCode = VarCheckConflict;
294         break;
295       }
296 
297       CheckDuplicate |= Arg.FlagID;
298       CheckConflict  |= Arg.ConflictMask;
299       break;
300     }
301 
302     Arg = CheckList[++Index];
303   }
304 
305   if (Arg.FlagStr == NULL) {
306     RtCode = VarCheckUnknown;
307   }
308 
309   return RtCode;
310 }
311 
312 /**
313   The notify function of create event when performing a manual config.
314 
315   @param[in]    Event        The event this notify function registered to.
316   @param[in]    Context      Pointer to the context data registered to the event.
317 
318 **/
319 VOID
320 EFIAPI
IfConfig6ManualAddressNotify(IN EFI_EVENT Event,IN VOID * Context)321 IfConfig6ManualAddressNotify (
322   IN EFI_EVENT    Event,
323   IN VOID         *Context
324   )
325 {
326   *((BOOLEAN *) Context) = TRUE;
327 }
328 
329 /**
330   Print MAC address.
331 
332   @param[in]    Node    The pointer of MAC address buffer.
333   @param[in]    Size    The size of MAC address buffer.
334 
335 **/
336 VOID
IfConfig6PrintMacAddr(IN UINT8 * Node,IN UINT32 Size)337 IfConfig6PrintMacAddr (
338   IN UINT8     *Node,
339   IN UINT32    Size
340   )
341 {
342   UINTN    Index;
343 
344   ASSERT (Size <= MACADDRMAXSIZE);
345 
346   for (Index = 0; Index < Size; Index++) {
347     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_MAC_ADDR_BODY), gShellNetwork2HiiHandle, Node[Index]);
348     if (Index + 1 < Size) {
349       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle);
350     }
351   }
352 
353   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle);
354 }
355 
356 /**
357   Print IPv6 address.
358 
359   @param[in]    Ip           The pointer of Ip bufffer in EFI_IPv6_ADDRESS format.
360   @param[in]    PrefixLen    The pointer of PrefixLen that describes the size Prefix.
361 
362 **/
363 VOID
IfConfig6PrintIpAddr(IN EFI_IPv6_ADDRESS * Ip,IN UINT8 * PrefixLen)364 IfConfig6PrintIpAddr (
365   IN EFI_IPv6_ADDRESS    *Ip,
366   IN UINT8               *PrefixLen
367   )
368 {
369   UINTN      Index;
370   BOOLEAN    Short;
371 
372   Short = FALSE;
373 
374   for (Index = 0; Index < PREFIXMAXLEN; Index = Index + 2) {
375 
376     if (!Short && (Index + 1 < PREFIXMAXLEN) && (Index % 2 == 0) && (Ip->Addr[Index] == 0) && (Ip->Addr[Index + 1] == 0)) {
377       //
378       // Deal with the case of ::.
379       //
380       if (Index == 0) {
381         //
382         // :: is at the beginning of the address.
383         //
384         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle);
385       }
386       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle);
387 
388       while ((Ip->Addr[Index] == 0) && (Ip->Addr[Index + 1] == 0) && (Index < PREFIXMAXLEN)) {
389         Index = Index + 2;
390         if (Index > PREFIXMAXLEN - 2) {
391           break;
392         }
393       }
394 
395       Short = TRUE;
396 
397       if (Index == PREFIXMAXLEN) {
398         //
399         // :: is at the end of the address.
400         //
401         break;
402       }
403     }
404 
405     if (Index < PREFIXMAXLEN - 1) {
406       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_BODY), gShellNetwork2HiiHandle, Ip->Addr[Index]);
407       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_BODY), gShellNetwork2HiiHandle, Ip->Addr[Index + 1]);
408     }
409 
410     if (Index + 2 < PREFIXMAXLEN) {
411       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle);
412     }
413   }
414 
415   if (PrefixLen != NULL) {
416     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_PREFIX_LEN), gShellNetwork2HiiHandle, *PrefixLen);
417   }
418 }
419 
420 /**
421   Pick up host IPv6 address in string format from Args with "-s" option and convert it to EFI_IP6_CONFIG_MANUAL_ADDRESS format.
422 
423   @param[in, out]    Arg        The pointer of the address of ARG_LIST which save Args with the "-s" option.
424   @param[out]        Buf        The pointer of the address of EFI_IP6_CONFIG_MANUAL_ADDRESS.
425   @param[out]        BufSize    The pointer of BufSize that describes the size of Buf in bytes.
426 
427   @retval EFI_SUCCESS    The convertion is successful.
428   @retval Others         Does't find the host address, or it is an invalid IPv6 address in string format.
429 
430 **/
431 EFI_STATUS
IfConfig6ParseManualAddressList(IN OUT ARG_LIST ** Arg,OUT EFI_IP6_CONFIG_MANUAL_ADDRESS ** Buf,OUT UINTN * BufSize)432 IfConfig6ParseManualAddressList (
433   IN OUT ARG_LIST                         **Arg,
434      OUT EFI_IP6_CONFIG_MANUAL_ADDRESS    **Buf,
435      OUT UINTN                            *BufSize
436   )
437 {
438   EFI_STATUS                       Status;
439   EFI_IP6_CONFIG_MANUAL_ADDRESS    *AddrBuf;
440   ARG_LIST                         *VarArg;
441   EFI_IPv6_ADDRESS                 Address;
442   UINT8                            Prefix;
443   UINT8                            AddrCnt;
444 
445   Prefix   = 0;
446   AddrCnt  = 0;
447   *BufSize = 0;
448   *Buf     = NULL;
449   VarArg   = *Arg;
450   Status   = EFI_SUCCESS;
451 
452   //
453   // Go through the list to check the correctness of input host ip6 address.
454   //
455   while ((!EFI_ERROR (Status)) && (VarArg != NULL)) {
456 
457     Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix);
458 
459     if (EFI_ERROR (Status)) {
460       //
461       // host ip ip ... gw
462       //
463       break;
464     }
465 
466     VarArg = VarArg->Next;
467     AddrCnt++;
468   }
469 
470   if (AddrCnt == 0) {
471     return EFI_INVALID_PARAMETER;
472   }
473 
474   AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
475   ASSERT (AddrBuf != NULL);
476 
477   AddrCnt = 0;
478   VarArg  = *Arg;
479   Status  = EFI_SUCCESS;
480 
481   //
482   // Go through the list to fill in the EFI_IP6_CONFIG_MANUAL_ADDRESS structure.
483   //
484   while ((!EFI_ERROR (Status)) && (VarArg != NULL)) {
485 
486     Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix);
487 
488     if (EFI_ERROR (Status)) {
489       break;
490     }
491 
492     //
493     // If prefix length is not set, set it as Zero here. In the IfConfigSetInterfaceInfo()
494     // Zero prefix, length will be transfered to default prefix length.
495     //
496     if (Prefix == 0xFF) {
497       Prefix = 0;
498     }
499     AddrBuf[AddrCnt].IsAnycast    = FALSE;
500     AddrBuf[AddrCnt].PrefixLength = Prefix;
501     IP6_COPY_ADDRESS (&AddrBuf[AddrCnt].Address, &Address);
502     VarArg = VarArg->Next;
503     AddrCnt++;
504   }
505 
506   *Arg = VarArg;
507 
508   if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) {
509     goto ON_ERROR;
510   }
511 
512   *Buf     = AddrBuf;
513   *BufSize = AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
514 
515   return EFI_SUCCESS;
516 
517 ON_ERROR:
518 
519   FreePool (AddrBuf);
520   return Status;
521 }
522 
523 /**
524   Pick up gw/dns IPv6 address in string format from Args with "-s" option and convert it to EFI_IPv6_ADDRESS format.
525 
526   @param[in, out]    Arg        The pointer of the address of ARG_LIST that save Args with the "-s" option.
527   @param[out]        Buf        The pointer of the address of EFI_IPv6_ADDRESS.
528   @param[out]        BufSize    The pointer of BufSize that describes the size of Buf in bytes.
529 
530   @retval EFI_SUCCESS    The conversion is successful.
531   @retval Others         Doesn't find the host address, or it is an invalid IPv6 address in string format.
532 
533 **/
534 EFI_STATUS
IfConfig6ParseGwDnsAddressList(IN OUT ARG_LIST ** Arg,OUT EFI_IPv6_ADDRESS ** Buf,OUT UINTN * BufSize)535 IfConfig6ParseGwDnsAddressList (
536   IN OUT ARG_LIST            **Arg,
537      OUT EFI_IPv6_ADDRESS    **Buf,
538      OUT UINTN               *BufSize
539   )
540 {
541   EFI_STATUS          Status;
542   EFI_IPv6_ADDRESS    *AddrBuf;
543   ARG_LIST            *VarArg;
544   EFI_IPv6_ADDRESS    Address;
545   UINT8               Prefix;
546   UINT8               AddrCnt;
547 
548   AddrCnt  = 0;
549   *BufSize = 0;
550   *Buf     = NULL;
551   VarArg   = *Arg;
552   Status   = EFI_SUCCESS;
553 
554   //
555   // Go through the list to check the correctness of input gw/dns address.
556   //
557   while ((!EFI_ERROR (Status)) && (VarArg != NULL)) {
558 
559     Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix);
560 
561     if (EFI_ERROR (Status)) {
562       //
563       // gw ip ip ... host
564       //
565       break;
566     }
567 
568     VarArg = VarArg->Next;
569     AddrCnt++;
570   }
571 
572   if (AddrCnt == 0) {
573     return EFI_INVALID_PARAMETER;
574   }
575 
576   AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IPv6_ADDRESS));
577   ASSERT (AddrBuf != NULL);
578 
579   AddrCnt = 0;
580   VarArg  = *Arg;
581   Status  = EFI_SUCCESS;
582 
583   //
584   // Go through the list to fill in the EFI_IPv6_ADDRESS structure.
585   //
586   while ((!EFI_ERROR (Status)) && (VarArg != NULL)) {
587 
588     Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix);
589 
590     if (EFI_ERROR (Status)) {
591       break;
592     }
593 
594     IP6_COPY_ADDRESS (&AddrBuf[AddrCnt], &Address);
595 
596     VarArg = VarArg->Next;
597     AddrCnt++;
598   }
599 
600   *Arg = VarArg;
601 
602   if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) {
603    goto ON_ERROR;
604   }
605 
606   *Buf     = AddrBuf;
607   *BufSize = AddrCnt * sizeof (EFI_IPv6_ADDRESS);
608 
609   return EFI_SUCCESS;
610 
611 ON_ERROR:
612 
613   FreePool (AddrBuf);
614   return Status;
615 }
616 
617 /**
618   Parse InterfaceId in string format from Args with the "-s" option and convert it to EFI_IP6_CONFIG_INTERFACE_ID format.
619 
620   @param[in, out]   Arg     The pointer of the address of ARG_LIST that saves Args with the "-s" option.
621   @param[out]       IfId    The pointer of EFI_IP6_CONFIG_INTERFACE_ID.
622 
623   @retval EFI_SUCCESS              The get status processed successfullly.
624   @retval EFI_INVALID_PARAMETER    The get status process failed.
625 
626 **/
627 EFI_STATUS
IfConfig6ParseInterfaceId(IN OUT ARG_LIST ** Arg,OUT EFI_IP6_CONFIG_INTERFACE_ID ** IfId)628 IfConfig6ParseInterfaceId (
629   IN OUT ARG_LIST                       **Arg,
630      OUT EFI_IP6_CONFIG_INTERFACE_ID    **IfId
631   )
632 {
633   UINT8     Index;
634   UINT8     NodeVal;
635   CHAR16    *IdStr;
636 
637   if (*Arg == NULL) {
638     return EFI_INVALID_PARAMETER;
639   }
640 
641   Index = 0;
642   IdStr = (*Arg)->Arg;
643   ASSERT (IfId != NULL);
644   *IfId = AllocateZeroPool (sizeof (EFI_IP6_CONFIG_INTERFACE_ID));
645   ASSERT (*IfId != NULL);
646 
647   while ((*IdStr != L'\0') && (Index < 8)) {
648 
649     NodeVal = 0;
650     while ((*IdStr != L':') && (*IdStr != L'\0')) {
651 
652       if ((*IdStr <= L'F') && (*IdStr >= L'A')) {
653         NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'A' + 10);
654       } else if ((*IdStr <= L'f') && (*IdStr >= L'a')) {
655         NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'a' + 10);
656       } else if ((*IdStr <= L'9') && (*IdStr >= L'0')) {
657         NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'0');
658       } else {
659         FreePool (*IfId);
660         return EFI_INVALID_PARAMETER;
661       }
662 
663       IdStr++;
664     }
665 
666     (*IfId)->Id[Index++] = NodeVal;
667 
668     if (*IdStr == L':') {
669       IdStr++;
670     }
671   }
672 
673   *Arg = (*Arg)->Next;
674   return EFI_SUCCESS;
675 }
676 
677 /**
678   Parse dad in string format from Args with the "-s" option and convert it to UINT32 format.
679 
680   @param[in, out]   Arg      The pointer of the address of ARG_LIST that saves Args with the "-s" option.
681   @param[out]       Xmits    The pointer of Xmits.
682 
683   @retval EFI_SUCCESS    The get status processed successfully.
684   @retval others         The get status process failed.
685 
686 **/
687 EFI_STATUS
IfConfig6ParseDadXmits(IN OUT ARG_LIST ** Arg,OUT UINT32 * Xmits)688 IfConfig6ParseDadXmits (
689   IN OUT ARG_LIST    **Arg,
690      OUT UINT32      *Xmits
691   )
692 {
693   CHAR16    *ValStr;
694 
695   if (*Arg == NULL) {
696     return EFI_INVALID_PARAMETER;
697   }
698 
699   ValStr = (*Arg)->Arg;
700   *Xmits = 0;
701 
702   while (*ValStr != L'\0') {
703 
704     if ((*ValStr <= L'9') && (*ValStr >= L'0')) {
705 
706       *Xmits = (*Xmits * 10) + (*ValStr - L'0');
707 
708     } else {
709 
710       return EFI_INVALID_PARAMETER;
711     }
712 
713     ValStr++;
714   }
715 
716   *Arg = (*Arg)->Next;
717   return EFI_SUCCESS;
718 }
719 
720 /**
721   The get current status of all handles.
722 
723   @param[in]   ImageHandle    The handle of  ImageHandle.
724   @param[in]   IfName         The pointer of  IfName(interface name).
725   @param[in]   IfList         The pointer of  IfList(interface list).
726 
727   @retval EFI_SUCCESS    The get status processed successfully.
728   @retval others         The get status process failed.
729 
730 **/
731 EFI_STATUS
IfConfig6GetInterfaceInfo(IN EFI_HANDLE ImageHandle,IN CHAR16 * IfName,IN LIST_ENTRY * IfList)732 IfConfig6GetInterfaceInfo (
733   IN EFI_HANDLE    ImageHandle,
734   IN CHAR16        *IfName,
735   IN LIST_ENTRY    *IfList
736   )
737 {
738   EFI_STATUS                       Status;
739   UINTN                            HandleIndex;
740   UINTN                            HandleNum;
741   EFI_HANDLE                       *HandleBuffer;
742   EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;
743   EFI_IP6_CONFIG_INTERFACE_INFO    *IfInfo;
744   IFCONFIG6_INTERFACE_CB           *IfCb;
745   UINTN                            DataSize;
746 
747   HandleBuffer = NULL;
748   HandleNum    = 0;
749 
750   IfInfo       = NULL;
751   IfCb         = NULL;
752 
753   //
754   // Locate all the handles with ip6 service binding protocol.
755   //
756   Status = gBS->LocateHandleBuffer (
757                   ByProtocol,
758                   &gEfiIp6ServiceBindingProtocolGuid,
759                   NULL,
760                   &HandleNum,
761                   &HandleBuffer
762                  );
763   if (EFI_ERROR (Status) || (HandleNum == 0)) {
764     return Status;
765   }
766 
767   //
768   // Enumerate all handles that installed with ip6 service binding protocol.
769   //
770   for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {
771     IfCb      = NULL;
772     IfInfo    = NULL;
773     DataSize  = 0;
774 
775     //
776     // Ip6config protocol and ip6 service binding protocol are installed
777     // on the same handle.
778     //
779     ASSERT (HandleBuffer != NULL);
780     Status = gBS->HandleProtocol (
781                     HandleBuffer[HandleIndex],
782                     &gEfiIp6ConfigProtocolGuid,
783                     (VOID **) &Ip6Cfg
784                     );
785 
786     if (EFI_ERROR (Status)) {
787       goto ON_ERROR;
788     }
789     //
790     // Get the interface information size.
791     //
792     Status = Ip6Cfg->GetData (
793                        Ip6Cfg,
794                        Ip6ConfigDataTypeInterfaceInfo,
795                        &DataSize,
796                        NULL
797                        );
798 
799     if (Status != EFI_BUFFER_TOO_SMALL) {
800       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
801       goto ON_ERROR;
802     }
803 
804     IfInfo = AllocateZeroPool (DataSize);
805 
806     if (IfInfo == NULL) {
807       Status = EFI_OUT_OF_RESOURCES;
808       goto ON_ERROR;
809     }
810     //
811     // Get the interface info.
812     //
813     Status = Ip6Cfg->GetData (
814                        Ip6Cfg,
815                        Ip6ConfigDataTypeInterfaceInfo,
816                        &DataSize,
817                        IfInfo
818                        );
819 
820     if (EFI_ERROR (Status)) {
821       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
822       goto ON_ERROR;
823     }
824     //
825     // Check the interface name if required.
826     //
827     if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) != 0)) {
828       FreePool (IfInfo);
829       continue;
830     }
831 
832     DataSize = 0;
833     //
834     // Get the size of dns server list.
835     //
836     Status = Ip6Cfg->GetData (
837                        Ip6Cfg,
838                        Ip6ConfigDataTypeDnsServer,
839                        &DataSize,
840                        NULL
841                        );
842 
843     if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) {
844       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
845       goto ON_ERROR;
846     }
847 
848     IfCb = AllocateZeroPool (sizeof (IFCONFIG6_INTERFACE_CB) + DataSize);
849 
850     if (IfCb == NULL) {
851       Status = EFI_OUT_OF_RESOURCES;
852       goto ON_ERROR;
853     }
854 
855     IfCb->NicHandle = HandleBuffer[HandleIndex];
856     IfCb->IfInfo    = IfInfo;
857     IfCb->IfCfg     = Ip6Cfg;
858     IfCb->DnsCnt    = (UINT32) (DataSize / sizeof (EFI_IPv6_ADDRESS));
859 
860     //
861     // Get the dns server list if has.
862     //
863     if (DataSize > 0) {
864 
865       Status = Ip6Cfg->GetData (
866                          Ip6Cfg,
867                          Ip6ConfigDataTypeDnsServer,
868                          &DataSize,
869                          IfCb->DnsAddr
870                          );
871 
872       if (EFI_ERROR (Status)) {
873         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
874         goto ON_ERROR;
875       }
876     }
877     //
878     // Get the interface id if has.
879     //
880     DataSize   = sizeof (EFI_IP6_CONFIG_INTERFACE_ID);
881     IfCb->IfId = AllocateZeroPool (DataSize);
882 
883     if (IfCb->IfId == NULL) {
884       goto ON_ERROR;
885     }
886 
887     Status = Ip6Cfg->GetData (
888                        Ip6Cfg,
889                        Ip6ConfigDataTypeAltInterfaceId,
890                        &DataSize,
891                        IfCb->IfId
892                        );
893 
894     if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
895       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
896       goto ON_ERROR;
897     }
898 
899     if (Status == EFI_NOT_FOUND) {
900       FreePool (IfCb->IfId);
901       IfCb->IfId = NULL;
902     }
903     //
904     // Get the config policy.
905     //
906     DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
907     Status   = Ip6Cfg->GetData (
908                          Ip6Cfg,
909                          Ip6ConfigDataTypePolicy,
910                          &DataSize,
911                          &IfCb->Policy
912                          );
913 
914     if (EFI_ERROR (Status)) {
915       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
916       goto ON_ERROR;
917     }
918     //
919     // Get the dad transmits.
920     //
921     DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
922     Status   = Ip6Cfg->GetData (
923                          Ip6Cfg,
924                          Ip6ConfigDataTypeDupAddrDetectTransmits,
925                          &DataSize,
926                          &IfCb->Xmits
927                          );
928 
929     if (EFI_ERROR (Status)) {
930       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
931       goto ON_ERROR;
932     }
933 
934     InsertTailList (IfList, &IfCb->Link);
935 
936     if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) == 0)) {
937       //
938       // Only need the appointed interface, keep the allocated buffer.
939       //
940       IfCb   = NULL;
941       IfInfo = NULL;
942       break;
943     }
944   }
945 
946   if (HandleBuffer != NULL) {
947     FreePool (HandleBuffer);
948   }
949 
950   return EFI_SUCCESS;
951 
952 ON_ERROR:
953 
954   if (IfInfo != NULL) {
955     FreePool (IfInfo);
956   }
957 
958   if (IfCb != NULL) {
959     if (IfCb->IfId != NULL) {
960       FreePool (IfCb->IfId);
961     }
962 
963     FreePool (IfCb);
964   }
965 
966   return Status;
967 }
968 
969 /**
970   The list process of the IfConfig6 application.
971 
972   @param[in]   IfList    The pointer of IfList(interface list).
973 
974   @retval SHELL_SUCCESS  The IfConfig6 list processed successfully.
975   @retval others         The IfConfig6 list process failed.
976 
977 **/
978 SHELL_STATUS
IfConfig6ShowInterfaceInfo(IN LIST_ENTRY * IfList)979 IfConfig6ShowInterfaceInfo (
980   IN LIST_ENTRY    *IfList
981   )
982 {
983   LIST_ENTRY                *Entry;
984   IFCONFIG6_INTERFACE_CB    *IfCb;
985   UINTN                     Index;
986 
987   Entry  = IfList->ForwardLink;
988 
989   if (IsListEmpty (IfList)) {
990     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle);
991   }
992 
993   //
994   // Go through the interface list.
995   //
996   while (Entry != IfList) {
997 
998     IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link);
999 
1000     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_BREAK), gShellNetwork2HiiHandle);
1001 
1002     //
1003     // Print interface name.
1004     //
1005     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IF_NAME), gShellNetwork2HiiHandle, IfCb->IfInfo->Name);
1006 
1007     //
1008     // Print interface config policy.
1009     //
1010     if (IfCb->Policy == Ip6ConfigPolicyAutomatic) {
1011       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_POLICY_AUTO), gShellNetwork2HiiHandle);
1012     } else {
1013       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_POLICY_MAN), gShellNetwork2HiiHandle);
1014     }
1015 
1016     //
1017     // Print dad transmit.
1018     //
1019     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_DAD_TRANSMITS), gShellNetwork2HiiHandle, IfCb->Xmits);
1020 
1021     //
1022     // Print interface id if has.
1023     //
1024     if (IfCb->IfId != NULL) {
1025       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_INTERFACE_ID_HEAD), gShellNetwork2HiiHandle);
1026 
1027       IfConfig6PrintMacAddr (
1028         IfCb->IfId->Id,
1029         8
1030         );
1031     }
1032     //
1033     // Print mac address of the interface.
1034     //
1035     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_MAC_ADDR_HEAD), gShellNetwork2HiiHandle);
1036 
1037     IfConfig6PrintMacAddr (
1038       IfCb->IfInfo->HwAddress.Addr,
1039       IfCb->IfInfo->HwAddressSize
1040       );
1041 
1042     //
1043     // Print ip addresses list of the interface.
1044     //
1045     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_HEAD), gShellNetwork2HiiHandle);
1046 
1047     for (Index = 0; Index < IfCb->IfInfo->AddressInfoCount; Index++) {
1048       IfConfig6PrintIpAddr (
1049         &IfCb->IfInfo->AddressInfo[Index].Address,
1050         &IfCb->IfInfo->AddressInfo[Index].PrefixLength
1051         );
1052       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle);
1053     }
1054 
1055     //
1056     // Print dns server addresses list of the interface if has.
1057     //
1058     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_DNS_ADDR_HEAD), gShellNetwork2HiiHandle);
1059 
1060     for (Index = 0; Index < IfCb->DnsCnt; Index++) {
1061       IfConfig6PrintIpAddr (
1062         &IfCb->DnsAddr[Index],
1063         NULL
1064         );
1065       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle);
1066     }
1067 
1068     //
1069     // Print route table of the interface if has.
1070     //
1071     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_ROUTE_HEAD), gShellNetwork2HiiHandle);
1072 
1073     for (Index = 0; Index < IfCb->IfInfo->RouteCount; Index++) {
1074       IfConfig6PrintIpAddr (
1075         &IfCb->IfInfo->RouteTable[Index].Destination,
1076         &IfCb->IfInfo->RouteTable[Index].PrefixLength
1077         );
1078       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_JOINT), gShellNetwork2HiiHandle);
1079 
1080       IfConfig6PrintIpAddr (
1081         &IfCb->IfInfo->RouteTable[Index].Gateway,
1082         NULL
1083         );
1084       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle);
1085     }
1086 
1087     Entry = Entry->ForwardLink;
1088   }
1089 
1090   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_BREAK), gShellNetwork2HiiHandle);
1091   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle);
1092 
1093   return SHELL_SUCCESS;
1094 }
1095 
1096 /**
1097   The clean process of the IfConfig6 application.
1098 
1099   @param[in]   IfList    The pointer of IfList(interface list).
1100   @param[in]   IfName    The pointer of interface name.
1101 
1102   @retval SHELL_SUCCESS  The IfConfig6 clean processed successfully.
1103   @retval others         The IfConfig6 clean process failed.
1104 
1105 **/
1106 SHELL_STATUS
IfConfig6ClearInterfaceInfo(IN LIST_ENTRY * IfList,IN CHAR16 * IfName)1107 IfConfig6ClearInterfaceInfo (
1108   IN LIST_ENTRY    *IfList,
1109   IN CHAR16        *IfName
1110   )
1111 {
1112   EFI_STATUS                Status;
1113   SHELL_STATUS              ShellStatus;
1114   LIST_ENTRY                *Entry;
1115   IFCONFIG6_INTERFACE_CB    *IfCb;
1116   EFI_IP6_CONFIG_POLICY     Policy;
1117 
1118   Entry  = IfList->ForwardLink;
1119   Status = EFI_SUCCESS;
1120   ShellStatus = SHELL_SUCCESS;
1121 
1122   if (IsListEmpty (IfList)) {
1123     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle);
1124   }
1125 
1126   //
1127   // Go through the interface list.If the interface name is specified, then
1128   // need to refresh the configuration.
1129   //
1130   while (Entry != IfList) {
1131 
1132     IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link);
1133 
1134     if ((IfName != NULL) && (StrCmp (IfName, IfCb->IfInfo->Name) == 0)) {
1135       Policy = Ip6ConfigPolicyManual;
1136 
1137       Status = IfCb->IfCfg->SetData (
1138                               IfCb->IfCfg,
1139                               Ip6ConfigDataTypePolicy,
1140                               sizeof (EFI_IP6_CONFIG_POLICY),
1141                               &Policy
1142                               );
1143       if (EFI_ERROR (Status)) {
1144         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork2HiiHandle, L"ifconfig6");
1145         ShellStatus = SHELL_ACCESS_DENIED;
1146         break;
1147       }
1148     }
1149 
1150     Policy = Ip6ConfigPolicyAutomatic;
1151 
1152     Status = IfCb->IfCfg->SetData (
1153                             IfCb->IfCfg,
1154                             Ip6ConfigDataTypePolicy,
1155                             sizeof (EFI_IP6_CONFIG_POLICY),
1156                             &Policy
1157                             );
1158 
1159     if (EFI_ERROR (Status)) {
1160       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork2HiiHandle, L"ifconfig6");
1161       ShellStatus = SHELL_ACCESS_DENIED;
1162       break;
1163     }
1164 
1165     Entry  = Entry->ForwardLink;
1166   }
1167 
1168   return ShellStatus;
1169 }
1170 
1171 /**
1172   The set process of the IfConfig6 application.
1173 
1174   @param[in]   IfList    The pointer of IfList(interface list).
1175   @param[in]   VarArg    The pointer of ARG_LIST(Args with "-s" option).
1176 
1177   @retval SHELL_SUCCESS  The IfConfig6 set processed successfully.
1178   @retval others         The IfConfig6 set process failed.
1179 
1180 **/
1181 SHELL_STATUS
IfConfig6SetInterfaceInfo(IN LIST_ENTRY * IfList,IN ARG_LIST * VarArg)1182 IfConfig6SetInterfaceInfo (
1183   IN LIST_ENTRY    *IfList,
1184   IN ARG_LIST      *VarArg
1185   )
1186 {
1187   EFI_STATUS                       Status;
1188   SHELL_STATUS                     ShellStatus;
1189   IFCONFIG6_INTERFACE_CB           *IfCb;
1190   EFI_IP6_CONFIG_MANUAL_ADDRESS    *CfgManAddr;
1191   EFI_IPv6_ADDRESS                 *CfgAddr;
1192   UINTN                            AddrSize;
1193   EFI_IP6_CONFIG_INTERFACE_ID      *InterfaceId;
1194   UINT32                           DadXmits;
1195   UINT32                           CurDadXmits;
1196   UINTN                            CurDadXmitsLen;
1197   EFI_IP6_CONFIG_POLICY            Policy;
1198 
1199   VAR_CHECK_CODE                   CheckCode;
1200   EFI_EVENT                        TimeOutEvt;
1201   EFI_EVENT                        MappedEvt;
1202   BOOLEAN                          IsAddressOk;
1203 
1204   UINTN                            DataSize;
1205   UINT32                           Index;
1206   UINT32                           Index2;
1207   BOOLEAN                          IsAddressSet;
1208   EFI_IP6_CONFIG_INTERFACE_INFO    *IfInfo;
1209 
1210   CfgManAddr  = NULL;
1211   CfgAddr     = NULL;
1212   TimeOutEvt  = NULL;
1213   MappedEvt   = NULL;
1214   IfInfo      = NULL;
1215   InterfaceId = NULL;
1216   CurDadXmits = 0;
1217 
1218   if (IsListEmpty (IfList)) {
1219     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle);
1220     return SHELL_INVALID_PARAMETER;
1221   }
1222   //
1223   // Make sure to set only one interface each time.
1224   //
1225   IfCb   = BASE_CR (IfList->ForwardLink, IFCONFIG6_INTERFACE_CB, Link);
1226   Status = EFI_SUCCESS;
1227   ShellStatus = SHELL_SUCCESS;
1228 
1229   //
1230   // Initialize check list mechanism.
1231   //
1232   CheckCode = IfConfig6RetriveCheckListByName(
1233                 NULL,
1234                 NULL,
1235                 TRUE
1236                 );
1237 
1238   //
1239   // Create events & timers for asynchronous settings.
1240   //
1241   Status = gBS->CreateEvent (
1242                   EVT_TIMER,
1243                   TPL_CALLBACK,
1244                   NULL,
1245                   NULL,
1246                   &TimeOutEvt
1247                   );
1248   if (EFI_ERROR (Status)) {
1249     ShellStatus = SHELL_ACCESS_DENIED;
1250     goto ON_EXIT;
1251   }
1252 
1253   Status = gBS->CreateEvent (
1254                   EVT_NOTIFY_SIGNAL,
1255                   TPL_NOTIFY,
1256                   IfConfig6ManualAddressNotify,
1257                   &IsAddressOk,
1258                   &MappedEvt
1259                   );
1260   if (EFI_ERROR (Status)) {
1261     ShellStatus = SHELL_ACCESS_DENIED;
1262     goto ON_EXIT;
1263   }
1264   //
1265   // Parse the setting variables.
1266   //
1267   while (VarArg != NULL) {
1268      //
1269      // Check invalid parameters (duplication & unknown & conflict).
1270      //
1271     CheckCode = IfConfig6RetriveCheckListByName(
1272                   mIfConfig6SetCheckList,
1273                   VarArg->Arg,
1274                   FALSE
1275                   );
1276 
1277     if (VarCheckOk != CheckCode) {
1278       switch (CheckCode) {
1279         case VarCheckDuplicate:
1280           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_DUPLICATE_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg);
1281           break;
1282 
1283         case VarCheckConflict:
1284           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_CONFLICT_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg);
1285           break;
1286 
1287         case VarCheckUnknown:
1288           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_UNKNOWN_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg);
1289           break;
1290 
1291         default:
1292           break;
1293       }
1294 
1295       VarArg = VarArg->Next;
1296       continue;
1297     }
1298     //
1299     // Process valid variables.
1300     //
1301     if (StrCmp(VarArg->Arg, L"auto") == 0) {
1302       //
1303       // Set automaic config policy
1304       //
1305       Policy = Ip6ConfigPolicyAutomatic;
1306       Status = IfCb->IfCfg->SetData (
1307                               IfCb->IfCfg,
1308                               Ip6ConfigDataTypePolicy,
1309                               sizeof (EFI_IP6_CONFIG_POLICY),
1310                               &Policy
1311                               );
1312 
1313       if (EFI_ERROR(Status)) {
1314         ShellStatus = SHELL_ACCESS_DENIED;
1315         goto ON_EXIT;
1316       }
1317 
1318       VarArg= VarArg->Next;
1319 
1320       if (StrCmp (VarArg->Arg, L"host") == 0) {
1321         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_IP_CONFIG), gShellNetwork2HiiHandle, Status);
1322         ShellStatus = SHELL_INVALID_PARAMETER;
1323         goto ON_EXIT;
1324       } else if (StrCmp (VarArg->Arg, L"gw") == 0) {
1325         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_GW_CONFIG), gShellNetwork2HiiHandle, Status);
1326         ShellStatus = SHELL_INVALID_PARAMETER;
1327         goto ON_EXIT;
1328       } else if (StrCmp (VarArg->Arg, L"dns") == 0) {
1329         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_DNS_CONFIG), gShellNetwork2HiiHandle, Status);
1330         ShellStatus = SHELL_INVALID_PARAMETER;
1331         goto ON_EXIT;
1332       }
1333 
1334     } else if (StrCmp (VarArg->Arg, L"man") == 0) {
1335       //
1336       // Set manual config policy.
1337       //
1338       Policy = Ip6ConfigPolicyManual;
1339       Status = IfCb->IfCfg->SetData (
1340                               IfCb->IfCfg,
1341                               Ip6ConfigDataTypePolicy,
1342                               sizeof (EFI_IP6_CONFIG_POLICY),
1343                               &Policy
1344                               );
1345 
1346       if (EFI_ERROR(Status)) {
1347         ShellStatus = SHELL_ACCESS_DENIED;
1348         goto ON_EXIT;
1349       }
1350 
1351       VarArg= VarArg->Next;
1352 
1353     } else if (StrCmp (VarArg->Arg, L"host") == 0) {
1354       //
1355       // Parse till the next tag or the end of command line.
1356       //
1357       VarArg = VarArg->Next;
1358       Status = IfConfig6ParseManualAddressList (
1359                  &VarArg,
1360                  &CfgManAddr,
1361                  &AddrSize
1362                  );
1363 
1364       if (EFI_ERROR (Status)) {
1365         if (Status == EFI_INVALID_PARAMETER) {
1366           ShellStatus = SHELL_INVALID_PARAMETER;
1367           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"host");
1368           continue;
1369         } else {
1370           ShellStatus = SHELL_ACCESS_DENIED;
1371           goto ON_EXIT;
1372         }
1373       }
1374       //
1375       // Set static host ip6 address list.
1376       //   This is a asynchronous process.
1377       //
1378       IsAddressOk = FALSE;
1379 
1380       Status = IfCb->IfCfg->RegisterDataNotify (
1381                               IfCb->IfCfg,
1382                               Ip6ConfigDataTypeManualAddress,
1383                               MappedEvt
1384                               );
1385       if (EFI_ERROR (Status)) {
1386         ShellStatus = SHELL_ACCESS_DENIED;
1387         goto ON_EXIT;
1388       }
1389 
1390       Status = IfCb->IfCfg->SetData (
1391                               IfCb->IfCfg,
1392                               Ip6ConfigDataTypeManualAddress,
1393                               AddrSize,
1394                               CfgManAddr
1395                               );
1396 
1397       if (Status == EFI_NOT_READY) {
1398         //
1399         // Get current dad transmits count.
1400         //
1401         CurDadXmitsLen = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
1402         IfCb->IfCfg->GetData (
1403                        IfCb->IfCfg,
1404                        Ip6ConfigDataTypeDupAddrDetectTransmits,
1405                        &CurDadXmitsLen,
1406                        &CurDadXmits
1407                        );
1408 
1409         gBS->SetTimer (TimeOutEvt, TimerRelative, 50000000 + 10000000 * CurDadXmits);
1410 
1411         while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
1412           if (IsAddressOk) {
1413             Status = EFI_SUCCESS;
1414             break;
1415           }
1416         }
1417       }
1418 
1419       IfCb->IfCfg->UnregisterDataNotify (
1420                      IfCb->IfCfg,
1421                      Ip6ConfigDataTypeManualAddress,
1422                      MappedEvt
1423                      );
1424 
1425       if (EFI_ERROR (Status)) {
1426         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_MAN_HOST), gShellNetwork2HiiHandle, Status);
1427         ShellStatus = SHELL_ACCESS_DENIED;
1428         goto ON_EXIT;
1429       }
1430 
1431       //
1432       // Check whether the address is set successfully.
1433       //
1434       DataSize = 0;
1435 
1436       Status = IfCb->IfCfg->GetData (
1437                               IfCb->IfCfg,
1438                               Ip6ConfigDataTypeInterfaceInfo,
1439                               &DataSize,
1440                               NULL
1441                               );
1442 
1443       if (Status != EFI_BUFFER_TOO_SMALL) {
1444         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
1445         ShellStatus = SHELL_ACCESS_DENIED;
1446         goto ON_EXIT;
1447       }
1448 
1449       IfInfo = AllocateZeroPool (DataSize);
1450 
1451       if (IfInfo == NULL) {
1452         ShellStatus = SHELL_OUT_OF_RESOURCES;
1453         goto ON_EXIT;
1454       }
1455 
1456       Status = IfCb->IfCfg->GetData (
1457                               IfCb->IfCfg,
1458                               Ip6ConfigDataTypeInterfaceInfo,
1459                               &DataSize,
1460                               IfInfo
1461                               );
1462 
1463       if (EFI_ERROR (Status)) {
1464         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status);
1465         ShellStatus = SHELL_ACCESS_DENIED;
1466         goto ON_EXIT;
1467       }
1468 
1469       for ( Index = 0; Index < (UINTN) (AddrSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); Index++) {
1470         IsAddressSet = FALSE;
1471         //
1472         // By default, the prefix length 0 is regarded as 64.
1473         //
1474         if (CfgManAddr[Index].PrefixLength == 0) {
1475           CfgManAddr[Index].PrefixLength = 64;
1476         }
1477 
1478         for (Index2 = 0; Index2 < IfInfo->AddressInfoCount; Index2++) {
1479           if (EFI_IP6_EQUAL (&IfInfo->AddressInfo[Index2].Address, &CfgManAddr[Index].Address) &&
1480               (IfInfo->AddressInfo[Index2].PrefixLength == CfgManAddr[Index].PrefixLength)) {
1481             IsAddressSet = TRUE;
1482             break;
1483           }
1484         }
1485 
1486         if (!IsAddressSet) {
1487           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_ADDRESS_FAILED), gShellNetwork2HiiHandle);
1488           IfConfig6PrintIpAddr (
1489             &CfgManAddr[Index].Address,
1490             &CfgManAddr[Index].PrefixLength
1491             );
1492         }
1493       }
1494 
1495     } else if (StrCmp (VarArg->Arg, L"gw") == 0) {
1496       //
1497       // Parse till the next tag or the end of command line.
1498       //
1499       VarArg = VarArg->Next;
1500       Status = IfConfig6ParseGwDnsAddressList (
1501                  &VarArg,
1502                  &CfgAddr,
1503                  &AddrSize
1504                  );
1505 
1506       if (EFI_ERROR (Status)) {
1507         if (Status == EFI_INVALID_PARAMETER) {
1508           ShellStatus = SHELL_INVALID_PARAMETER;
1509           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"gw");
1510           continue;
1511         } else {
1512           ShellStatus = SHELL_ACCESS_DENIED;
1513           goto ON_EXIT;
1514         }
1515       }
1516       //
1517       // Set static gateway ip6 address list.
1518       //
1519       Status = IfCb->IfCfg->SetData (
1520                               IfCb->IfCfg,
1521                               Ip6ConfigDataTypeGateway,
1522                               AddrSize,
1523                               CfgAddr
1524                               );
1525 
1526       if (EFI_ERROR (Status)) {
1527         ShellStatus = SHELL_ACCESS_DENIED;
1528         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_MAN_GW), gShellNetwork2HiiHandle, Status);
1529         goto ON_EXIT;
1530       }
1531 
1532     } else if (StrCmp (VarArg->Arg, L"dns") == 0) {
1533       //
1534       // Parse till the next tag or the end of command line.
1535       //
1536       VarArg = VarArg->Next;
1537       Status = IfConfig6ParseGwDnsAddressList (
1538                  &VarArg,
1539                  &CfgAddr,
1540                  &AddrSize
1541                  );
1542 
1543       if (EFI_ERROR (Status)) {
1544         if (Status == EFI_INVALID_PARAMETER) {
1545           ShellStatus = SHELL_INVALID_PARAMETER;
1546           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"dns");
1547           continue;
1548         } else {
1549           ShellStatus = SHELL_ACCESS_DENIED;
1550           goto ON_EXIT;
1551         }
1552       }
1553       //
1554       // Set static DNS server ip6 address list.
1555       //
1556       Status = IfCb->IfCfg->SetData (
1557                               IfCb->IfCfg,
1558                               Ip6ConfigDataTypeDnsServer,
1559                               AddrSize,
1560                               CfgAddr
1561                               );
1562 
1563       if (EFI_ERROR (Status)) {
1564         ShellStatus = SHELL_ACCESS_DENIED;
1565         goto ON_EXIT;
1566       }
1567 
1568     } else if (StrCmp (VarArg->Arg, L"id") == 0) {
1569       //
1570       // Parse till the next tag or the end of command line.
1571       //
1572       VarArg = VarArg->Next;
1573       Status = IfConfig6ParseInterfaceId (&VarArg, &InterfaceId);
1574 
1575       if (EFI_ERROR (Status)) {
1576         ShellStatus = SHELL_INVALID_PARAMETER;
1577         goto ON_EXIT;
1578       }
1579       //
1580       // Set alternative interface id.
1581       //
1582       Status = IfCb->IfCfg->SetData (
1583                               IfCb->IfCfg,
1584                               Ip6ConfigDataTypeAltInterfaceId,
1585                               sizeof (EFI_IP6_CONFIG_INTERFACE_ID),
1586                               InterfaceId
1587                               );
1588 
1589       if (EFI_ERROR (Status)) {
1590         ShellStatus = SHELL_ACCESS_DENIED;
1591         goto ON_EXIT;
1592       }
1593 
1594     } else if (StrCmp (VarArg->Arg, L"dad") == 0) {
1595       //
1596       // Parse till the next tag or the end of command line.
1597       //
1598       VarArg = VarArg->Next;
1599       Status = IfConfig6ParseDadXmits (&VarArg, &DadXmits);
1600 
1601       if (EFI_ERROR (Status)) {
1602         ShellStatus = SHELL_ACCESS_DENIED;
1603         goto ON_EXIT;
1604       }
1605       //
1606       // Set dad transmits count.
1607       //
1608       Status = IfCb->IfCfg->SetData (
1609                               IfCb->IfCfg,
1610                               Ip6ConfigDataTypeDupAddrDetectTransmits,
1611                               sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS),
1612                               &DadXmits
1613                               );
1614 
1615       if (EFI_ERROR(Status)) {
1616         ShellStatus = SHELL_ACCESS_DENIED;
1617         goto ON_EXIT;
1618       }
1619     }
1620   }
1621 
1622 ON_EXIT:
1623 
1624   if (CfgManAddr != NULL) {
1625     FreePool (CfgManAddr);
1626   }
1627 
1628   if (CfgAddr != NULL) {
1629     FreePool (CfgAddr);
1630   }
1631 
1632   if (MappedEvt != NULL) {
1633     gBS->CloseEvent (MappedEvt);
1634   }
1635 
1636   if (TimeOutEvt != NULL) {
1637     gBS->CloseEvent (TimeOutEvt);
1638   }
1639 
1640   if (IfInfo != NULL) {
1641     FreePool (IfInfo);
1642   }
1643 
1644   return ShellStatus;
1645 
1646 }
1647 
1648 /**
1649   The IfConfig6 main process.
1650 
1651   @param[in]   Private    The pointer of IFCONFIG6_PRIVATE_DATA.
1652 
1653   @retval SHELL_SUCCESS   IfConfig6 processed successfully.
1654   @retval others          The IfConfig6 process failed.
1655 
1656 **/
1657 SHELL_STATUS
IfConfig6(IN IFCONFIG6_PRIVATE_DATA * Private)1658 IfConfig6 (
1659   IN IFCONFIG6_PRIVATE_DATA    *Private
1660   )
1661 {
1662   EFI_STATUS    Status;
1663   SHELL_STATUS  ShellStatus;
1664 
1665   ShellStatus = SHELL_SUCCESS;
1666 
1667   //
1668   // Get configure information of all interfaces.
1669   //
1670   Status = IfConfig6GetInterfaceInfo (
1671              Private->ImageHandle,
1672              Private->IfName,
1673              &Private->IfList
1674              );
1675 
1676   if (EFI_ERROR (Status)) {
1677     ShellStatus = SHELL_NOT_FOUND;
1678     goto ON_EXIT;
1679   }
1680 
1681   switch (Private->OpCode) {
1682   case IfConfig6OpList:
1683     ShellStatus = IfConfig6ShowInterfaceInfo (&Private->IfList);
1684     break;
1685 
1686   case IfConfig6OpClear:
1687     ShellStatus = IfConfig6ClearInterfaceInfo (&Private->IfList, Private->IfName);
1688     break;
1689 
1690   case IfConfig6OpSet:
1691     ShellStatus = IfConfig6SetInterfaceInfo (&Private->IfList, Private->VarArg);
1692     break;
1693 
1694   default:
1695     ShellStatus = SHELL_UNSUPPORTED;
1696   }
1697 
1698 ON_EXIT:
1699 
1700   return ShellStatus;
1701 }
1702 
1703 /**
1704   The IfConfig6 cleanup process, free the allocated memory.
1705 
1706   @param[in]   Private    The pointer of  IFCONFIG6_PRIVATE_DATA.
1707 
1708 **/
1709 VOID
IfConfig6Cleanup(IN IFCONFIG6_PRIVATE_DATA * Private)1710 IfConfig6Cleanup (
1711   IN IFCONFIG6_PRIVATE_DATA    *Private
1712   )
1713 {
1714   LIST_ENTRY                *Entry;
1715   LIST_ENTRY                *NextEntry;
1716   IFCONFIG6_INTERFACE_CB    *IfCb;
1717 
1718   ASSERT (Private != NULL);
1719 
1720   //
1721   // Clean the list which save the set config Args.
1722   //
1723   if (Private->VarArg != NULL) {
1724     IfConfig6FreeArgList (Private->VarArg);
1725   }
1726 
1727   if (Private->IfName != NULL)
1728     FreePool (Private->IfName);
1729 
1730 
1731   //
1732   // Clean the IFCONFIG6_INTERFACE_CB list.
1733   //
1734   Entry     = Private->IfList.ForwardLink;
1735   NextEntry = Entry->ForwardLink;
1736 
1737   while (Entry != &Private->IfList) {
1738 
1739     IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link);
1740 
1741     RemoveEntryList (&IfCb->Link);
1742 
1743     if (IfCb->IfId != NULL) {
1744 
1745       FreePool (IfCb->IfId);
1746     }
1747 
1748     if (IfCb->IfInfo != NULL) {
1749 
1750       FreePool (IfCb->IfInfo);
1751     }
1752 
1753     FreePool (IfCb);
1754 
1755     Entry     = NextEntry;
1756     NextEntry = Entry->ForwardLink;
1757   }
1758 
1759   FreePool (Private);
1760 }
1761 
1762 /**
1763   Function for 'ifconfig6' command.
1764 
1765   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
1766   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
1767 
1768   @retval SHELL_SUCCESS   ifconfig6 command processed successfully.
1769   @retval others          The ifconfig6 command process failed.
1770 
1771 **/
1772 SHELL_STATUS
1773 EFIAPI
ShellCommandRunIfconfig6(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1774 ShellCommandRunIfconfig6 (
1775   IN EFI_HANDLE        ImageHandle,
1776   IN EFI_SYSTEM_TABLE  *SystemTable
1777   )
1778 {
1779   EFI_STATUS                Status;
1780   SHELL_STATUS              ShellStatus;
1781   IFCONFIG6_PRIVATE_DATA    *Private;
1782   LIST_ENTRY                *ParamPackage;
1783   CONST CHAR16              *ValueStr;
1784   ARG_LIST                  *ArgList;
1785   CHAR16                    *ProblemParam;
1786   CHAR16                    *Str;
1787 
1788   Private = NULL;
1789   Status = EFI_INVALID_PARAMETER;
1790   ShellStatus = SHELL_SUCCESS;
1791 
1792   Status = ShellCommandLineParseEx (mIfConfig6CheckList, &ParamPackage, &ProblemParam, TRUE, FALSE);
1793   if (EFI_ERROR (Status)) {
1794     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_COMMAND), gShellNetwork2HiiHandle, L"ifconfig6", ProblemParam);
1795     ShellStatus = SHELL_INVALID_PARAMETER;
1796     goto ON_EXIT;
1797   }
1798 
1799   //
1800   // To handle no option.
1801   //
1802   if (!ShellCommandLineGetFlag (ParamPackage, L"-r") && !ShellCommandLineGetFlag (ParamPackage, L"-s") &&
1803       !ShellCommandLineGetFlag (ParamPackage, L"-?") && !ShellCommandLineGetFlag (ParamPackage, L"-l")) {
1804     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_LACK_OPTION), gShellNetwork2HiiHandle);
1805     ShellStatus = SHELL_INVALID_PARAMETER;
1806     goto ON_EXIT;
1807   }
1808   //
1809   // To handle conflict options.
1810   //
1811   if (((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-s"))) ||
1812       ((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) ||
1813       ((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-?"))) ||
1814       ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) ||
1815       ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-?"))) ||
1816       ((ShellCommandLineGetFlag (ParamPackage, L"-l")) && (ShellCommandLineGetFlag (ParamPackage, L"-?")))) {
1817     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_CONFLICT_OPTIONS), gShellNetwork2HiiHandle);
1818     ShellStatus = SHELL_INVALID_PARAMETER;
1819     goto ON_EXIT;
1820   }
1821 
1822   Private = AllocateZeroPool (sizeof (IFCONFIG6_PRIVATE_DATA));
1823 
1824   if (Private == NULL) {
1825     ShellStatus = SHELL_OUT_OF_RESOURCES;
1826     goto ON_EXIT;
1827   }
1828 
1829   InitializeListHead (&Private->IfList);
1830 
1831   //
1832   // To get interface name for the list option.
1833   //
1834   if (ShellCommandLineGetFlag (ParamPackage, L"-l")) {
1835     Private->OpCode = IfConfig6OpList;
1836     ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");
1837     if (ValueStr != NULL) {
1838       Str = AllocateCopyPool (StrSize (ValueStr), ValueStr);
1839       if (Str == NULL) {
1840         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"ifconfig6");
1841         ShellStatus = SHELL_OUT_OF_RESOURCES;
1842         goto ON_EXIT;
1843       }
1844       Private->IfName = Str;
1845     }
1846   }
1847   //
1848   // To get interface name for the clear option.
1849   //
1850   if (ShellCommandLineGetFlag (ParamPackage, L"-r")) {
1851     Private->OpCode = IfConfig6OpClear;
1852     ValueStr = ShellCommandLineGetValue (ParamPackage, L"-r");
1853     if (ValueStr != NULL) {
1854       Str = AllocateCopyPool (StrSize (ValueStr), ValueStr);
1855       if (Str == NULL) {
1856         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"ifconfig6");
1857         ShellStatus = SHELL_OUT_OF_RESOURCES;
1858         goto ON_EXIT;
1859       }
1860       Private->IfName = Str;
1861     }
1862   }
1863   //
1864   // To get interface name and corresponding Args for the set option.
1865   //
1866   if (ShellCommandLineGetFlag (ParamPackage, L"-s")) {
1867 
1868     ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");
1869     if (ValueStr == NULL) {
1870       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_INTERFACE), gShellNetwork2HiiHandle);
1871       ShellStatus = SHELL_INVALID_PARAMETER;
1872       goto ON_EXIT;
1873     }
1874     //
1875     // To split the configuration into multi-section.
1876     //
1877     ArgList = IfConfig6SplitStrToList (ValueStr, L' ');
1878     if (ArgList == NULL) {
1879       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"ifconfig6");
1880       ShellStatus = SHELL_OUT_OF_RESOURCES;
1881       goto ON_EXIT;
1882     }
1883 
1884     Private->OpCode = IfConfig6OpSet;
1885     Private->IfName = ArgList->Arg;
1886 
1887     Private->VarArg = ArgList->Next;
1888 
1889     if (Private->IfName == NULL || Private->VarArg == NULL) {
1890       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_COMMAND), gShellNetwork2HiiHandle);
1891       ShellStatus = SHELL_INVALID_PARAMETER;
1892       goto ON_EXIT;
1893     }
1894   }
1895   //
1896   // Main process of ifconfig6.
1897   //
1898   ShellStatus = IfConfig6 (Private);
1899 
1900 ON_EXIT:
1901 
1902   ShellCommandLineFreeVarList (ParamPackage);
1903   if (Private != NULL) {
1904     IfConfig6Cleanup (Private);
1905   }
1906   return ShellStatus;
1907 
1908 }
1909 
1910