]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/IScsiDxe/IScsiDhcp6.c
NetworkPkg: Clean up source files
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiDhcp6.c
CommitLineData
4c5a5e0c 1/** @file\r
2 iSCSI DHCP6 related configuration routines.\r
3\r
f75a7f56 4Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
4c5a5e0c 5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "IScsiImpl.h"\r
16\r
17\r
18/**\r
19 Extract the Root Path option and get the required target information from\r
20 Boot File Uniform Resource Locator (URL) Option.\r
21\r
22 @param[in] RootPath The RootPath string.\r
23 @param[in] Length Length of the RootPath option payload.\r
24 @param[in, out] ConfigData The iSCSI session configuration data read from\r
25 nonvolatile device.\r
26\r
27 @retval EFI_SUCCESS All required information is extracted from the\r
28 RootPath option.\r
29 @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.\r
30 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
31 @retval EFI_INVALID_PARAMETER The RootPath is malformatted.\r
32\r
33**/\r
34EFI_STATUS\r
35IScsiDhcp6ExtractRootPath (\r
36 IN CHAR8 *RootPath,\r
37 IN UINT16 Length,\r
38 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
39 )\r
40{\r
41 EFI_STATUS Status;\r
42 UINT16 IScsiRootPathIdLen;\r
43 CHAR8 *TmpStr;\r
44 ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];\r
45 ISCSI_ROOT_PATH_FIELD *Field;\r
46 UINT32 FieldIndex;\r
47 UINT8 Index;\r
48 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
49 EFI_IP_ADDRESS Ip;\r
f75a7f56 50 UINT8 IpMode;\r
4c5a5e0c 51\r
52 ConfigNvData = &ConfigData->SessionConfigData;\r
91cdd20f 53 ConfigNvData->DnsMode = FALSE;\r
4c5a5e0c 54 //\r
55 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>\r
56 //\r
57 IScsiRootPathIdLen = (UINT16) AsciiStrLen (ISCSI_ROOT_PATH_ID);\r
58\r
59 if ((Length <= IScsiRootPathIdLen) ||\r
60 (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {\r
61 return EFI_NOT_FOUND;\r
62 }\r
63 //\r
64 // Skip the iSCSI RootPath ID "iscsi:".\r
65 //\r
66 RootPath = RootPath + IScsiRootPathIdLen;\r
67 Length = (UINT16) (Length - IScsiRootPathIdLen);\r
68\r
69 TmpStr = (CHAR8 *) AllocatePool (Length + 1);\r
70 if (TmpStr == NULL) {\r
71 return EFI_OUT_OF_RESOURCES;\r
72 }\r
73\r
74 CopyMem (TmpStr, RootPath, Length);\r
75 TmpStr[Length] = '\0';\r
76\r
77 Index = 0;\r
78 FieldIndex = 0;\r
79 ZeroMem (&Fields[0], sizeof (Fields));\r
80\r
81 //\r
82 // Extract SERVERNAME field in the Root Path option.\r
83 //\r
84 if (TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_START_DELIMITER) {\r
91cdd20f
ZL
85 //\r
86 // The servername is expressed as domain name.\r
87 //\r
88 ConfigNvData->DnsMode = TRUE;\r
4c5a5e0c 89 } else {\r
90 Index++;\r
91 }\r
92\r
93 Fields[RP_FIELD_IDX_SERVERNAME].Str = &TmpStr[Index];\r
94\r
91cdd20f
ZL
95 if (!ConfigNvData->DnsMode) {\r
96 while ((TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_END_DELIMITER)&& (Index < Length)) {\r
97 Index++;\r
98 }\r
4c5a5e0c 99\r
91cdd20f
ZL
100 //\r
101 // Skip ']' and ':'.\r
102 //\r
103 TmpStr[Index] = '\0';\r
104 Index += 2;\r
105 } else {\r
106 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
107 Index++;\r
108 }\r
109 //\r
110 // Skip ':'.\r
111 //\r
112 TmpStr[Index] = '\0';\r
113 Index += 1;\r
114 }\r
4c5a5e0c 115\r
116 Fields[RP_FIELD_IDX_SERVERNAME].Len = (UINT8) AsciiStrLen (Fields[RP_FIELD_IDX_SERVERNAME].Str);\r
117\r
118 //\r
119 // Extract others fields in the Root Path option string.\r
120 //\r
121 for (FieldIndex = 1; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {\r
122\r
123 if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
124 Fields[FieldIndex].Str = &TmpStr[Index];\r
125 }\r
126\r
127 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
128 Index++;\r
129 }\r
130\r
131 if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
132 if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {\r
133 TmpStr[Index] = '\0';\r
134 Index++;\r
135 }\r
136\r
137 if (Fields[FieldIndex].Str != NULL) {\r
138 Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);\r
139 }\r
140 }\r
141 }\r
142\r
143 if (FieldIndex != RP_FIELD_IDX_MAX) {\r
144 Status = EFI_INVALID_PARAMETER;\r
145 goto ON_EXIT;\r
146 }\r
147\r
148 if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||\r
149 (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||\r
150 (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)\r
151 ) {\r
152\r
153 Status = EFI_INVALID_PARAMETER;\r
154 goto ON_EXIT;\r
155 }\r
156 //\r
157 // Get the IP address of the target.\r
158 //\r
f75a7f56 159 Field = &Fields[RP_FIELD_IDX_SERVERNAME];\r
4c5a5e0c 160 if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {\r
161 IpMode = ConfigNvData->IpMode;\r
162 } else {\r
163 IpMode = ConfigData->AutoConfigureMode;\r
164 }\r
165\r
eabc6e59
ZL
166 //\r
167 // Server name is expressed as domain name, just save it.\r
168 //\r
91cdd20f 169 if (ConfigNvData->DnsMode) {\r
eabc6e59
ZL
170 if (Field->Len > sizeof (ConfigNvData->TargetUrl)) {\r
171 return EFI_INVALID_PARAMETER;\r
172 }\r
173 CopyMem (&ConfigNvData->TargetUrl, Field->Str, Field->Len);\r
174 ConfigNvData->TargetUrl[Field->Len + 1] = '\0';\r
175 } else {\r
176 ZeroMem(&ConfigNvData->TargetUrl, sizeof (ConfigNvData->TargetUrl));\r
177 Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);\r
178 CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));\r
4c5a5e0c 179\r
eabc6e59
ZL
180 if (EFI_ERROR (Status)) {\r
181 goto ON_EXIT;\r
182 }\r
4c5a5e0c 183 }\r
eabc6e59 184\r
4c5a5e0c 185 //\r
186 // Check the protocol type.\r
187 //\r
188 Field = &Fields[RP_FIELD_IDX_PROTOCOL];\r
189 if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {\r
190 Status = EFI_INVALID_PARAMETER;\r
191 goto ON_EXIT;\r
192 }\r
193 //\r
194 // Get the port of the iSCSI target.\r
195 //\r
196 Field = &Fields[RP_FIELD_IDX_PORT];\r
197 if (Field->Str != NULL) {\r
198 ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);\r
199 } else {\r
200 ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
201 }\r
202 //\r
203 // Get the LUN.\r
204 //\r
205 Field = &Fields[RP_FIELD_IDX_LUN];\r
206 if (Field->Str != NULL) {\r
207 Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);\r
208 if (EFI_ERROR (Status)) {\r
209 goto ON_EXIT;\r
210 }\r
211 } else {\r
212 ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));\r
213 }\r
214 //\r
215 // Get the target iSCSI Name.\r
216 //\r
217 Field = &Fields[RP_FIELD_IDX_TARGETNAME];\r
218\r
219 if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {\r
220 Status = EFI_INVALID_PARAMETER;\r
221 goto ON_EXIT;\r
222 }\r
223 //\r
224 // Validate the iSCSI name.\r
225 //\r
226 Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));\r
227 if (EFI_ERROR (Status)) {\r
228 goto ON_EXIT;\r
229 }\r
230\r
c960bdc2 231 AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);\r
4c5a5e0c 232\r
233ON_EXIT:\r
234\r
235 FreePool (TmpStr);\r
236\r
237 return Status;\r
238}\r
239\r
240/**\r
f75a7f56 241 EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol\r
4c5a5e0c 242 instance to intercept events that occurs in the DHCPv6 Information Request\r
243 exchange process.\r
244\r
f75a7f56 245 @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance that\r
4c5a5e0c 246 is used to configure this callback function.\r
247 @param[in] Context Pointer to the context that is initialized in\r
248 the EFI_DHCP6_PROTOCOL.InfoRequest().\r
249 @param[in] Packet Pointer to Reply packet that has been received.\r
250 The EFI DHCPv6 Protocol instance is responsible\r
251 for freeing the buffer.\r
252\r
253 @retval EFI_SUCCESS Tell the EFI DHCPv6 Protocol instance to finish\r
254 Information Request exchange process.\r
255 @retval EFI_NOT_READY Tell the EFI DHCPv6 Protocol instance to continue\r
256 Information Request exchange process.\r
257 @retval EFI_ABORTED Tell the EFI DHCPv6 Protocol instance to abort\r
258 the Information Request exchange process.\r
259 @retval EFI_UNSUPPORTED Tell the EFI DHCPv6 Protocol instance to finish\r
260 the Information Request exchange process because some\r
261 request information are not received.\r
262\r
263**/\r
264EFI_STATUS\r
265EFIAPI\r
266IScsiDhcp6ParseReply (\r
267 IN EFI_DHCP6_PROTOCOL *This,\r
268 IN VOID *Context,\r
269 IN EFI_DHCP6_PACKET *Packet\r
270 )\r
271{\r
272 EFI_STATUS Status;\r
273 UINT32 Index;\r
274 UINT32 OptionCount;\r
275 EFI_DHCP6_PACKET_OPTION *BootFileOpt;\r
276 EFI_DHCP6_PACKET_OPTION **OptionList;\r
277 ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData;\r
216f7970 278 UINT16 ParaLen;\r
f75a7f56 279\r
4c5a5e0c 280 OptionCount = 0;\r
281 BootFileOpt = NULL;\r
f75a7f56 282\r
4c5a5e0c 283 Status = This->Parse (This, Packet, &OptionCount, NULL);\r
284 if (Status != EFI_BUFFER_TOO_SMALL) {\r
285 return EFI_NOT_READY;\r
286 }\r
287\r
288 OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));\r
289 if (OptionList == NULL) {\r
290 return EFI_NOT_READY;\r
291 }\r
292\r
293 Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
294 if (EFI_ERROR (Status)) {\r
295 Status = EFI_NOT_READY;\r
296 goto Exit;\r
297 }\r
298\r
299 ConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) Context;\r
300\r
301 for (Index = 0; Index < OptionCount; Index++) {\r
302 OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);\r
303 OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);\r
304\r
305 //\r
306 // Get DNS server addresses from this reply packet.\r
307 //\r
308 if (OptionList[Index]->OpCode == DHCP6_OPT_DNS_SERVERS) {\r
309\r
310 if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {\r
216f7970 311 Status = EFI_UNSUPPORTED;\r
4c5a5e0c 312 goto Exit;\r
313 }\r
314 //\r
315 // Primary DNS server address.\r
316 //\r
317 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv6_ADDRESS));\r
318\r
319 if (OptionList[Index]->OpLen > 16) {\r
320 //\r
321 // Secondary DNS server address\r
322 //\r
323 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[16], sizeof (EFI_IPv6_ADDRESS));\r
324 }\r
325\r
326 } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_URL) {\r
327 //\r
328 // The server sends this option to inform the client about an URL to a boot file.\r
329 //\r
330 BootFileOpt = OptionList[Index];\r
142c00c3 331 } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_PARAM) {\r
216f7970 332 //\r
333 // The server sends this option to inform the client about DHCP6 server address.\r
334 //\r
335 if (OptionList[Index]->OpLen < 18) {\r
336 Status = EFI_UNSUPPORTED;\r
337 goto Exit;\r
338 }\r
339 //\r
340 // Check param-len 1, should be 16 bytes.\r
341 //\r
342 CopyMem (&ParaLen, &OptionList[Index]->Data[0], sizeof (UINT16));\r
343 if (NTOHS (ParaLen) != 16) {\r
344 Status = EFI_UNSUPPORTED;\r
345 goto Exit;\r
346 }\r
347\r
348 CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[2], sizeof (EFI_IPv6_ADDRESS));\r
4c5a5e0c 349 }\r
350 }\r
351\r
352 if (BootFileOpt == NULL) {\r
353 Status = EFI_UNSUPPORTED;\r
354 goto Exit;\r
355 }\r
f75a7f56 356\r
4c5a5e0c 357 //\r
358 // Get iSCSI root path from Boot File Uniform Resource Locator (URL) Option\r
359 //\r
360 Status = IScsiDhcp6ExtractRootPath (\r
361 (CHAR8 *) BootFileOpt->Data,\r
362 BootFileOpt->OpLen,\r
363 ConfigData\r
364 );\r
365\r
366Exit:\r
367\r
368 FreePool (OptionList);\r
369 return Status;\r
370}\r
371\r
372\r
373/**\r
374 Parse the DHCP ACK to get the address configuration and DNS information.\r
375\r
376 @param[in] Image The handle of the driver image.\r
377 @param[in] Controller The handle of the controller;\r
378 @param[in, out] ConfigData The attempt configuration data.\r
379\r
380 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
381 @retval EFI_NO_MAPPING DHCP failed to acquire address and other\r
382 information.\r
383 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.\r
384 @retval EFI_DEVICE_ERROR Some unexpected error occurred.\r
385 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to finish the\r
386 operation.\r
387 @retval EFI_NO_MEDIA There was a media error.\r
388\r
389**/\r
390EFI_STATUS\r
391IScsiDoDhcp6 (\r
392 IN EFI_HANDLE Image,\r
393 IN EFI_HANDLE Controller,\r
394 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData\r
395 )\r
396{\r
397 EFI_HANDLE Dhcp6Handle;\r
398 EFI_DHCP6_PROTOCOL *Dhcp6;\r
399 EFI_STATUS Status;\r
400 EFI_STATUS TimerStatus;\r
401 EFI_DHCP6_PACKET_OPTION *Oro;\r
402 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;\r
403 EFI_EVENT Timer;\r
152f2d5e 404 EFI_STATUS MediaStatus;\r
4c5a5e0c 405\r
406 //\r
407 // Check media status before doing DHCP.\r
408 //\r
152f2d5e 409 MediaStatus = EFI_SUCCESS;\r
410 NetLibDetectMediaWaitTimeout (Controller, ISCSI_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);\r
411 if (MediaStatus != EFI_SUCCESS) {\r
412 AsciiPrint ("\n Error: Could not detect network connection.\n");\r
4c5a5e0c 413 return EFI_NO_MEDIA;\r
414 }\r
415\r
416 //\r
417 // iSCSI will only request target info from DHCPv6 server.\r
418 //\r
419 if (!ConfigData->SessionConfigData.TargetInfoFromDhcp) {\r
420 return EFI_SUCCESS;\r
421 }\r
422\r
423 Dhcp6Handle = NULL;\r
424 Dhcp6 = NULL;\r
425 Oro = NULL;\r
426 Timer = NULL;\r
427\r
428 //\r
429 // Create a DHCP6 child instance and get the protocol.\r
430 //\r
431 Status = NetLibCreateServiceChild (\r
432 Controller,\r
433 Image,\r
434 &gEfiDhcp6ServiceBindingProtocolGuid,\r
435 &Dhcp6Handle\r
436 );\r
437 if (EFI_ERROR (Status)) {\r
438 return Status;\r
439 }\r
440\r
441 Status = gBS->OpenProtocol (\r
442 Dhcp6Handle,\r
443 &gEfiDhcp6ProtocolGuid,\r
444 (VOID **) &Dhcp6,\r
445 Image,\r
446 Controller,\r
447 EFI_OPEN_PROTOCOL_BY_DRIVER\r
448 );\r
449 if (EFI_ERROR (Status)) {\r
450 goto ON_EXIT;\r
451 }\r
452\r
216f7970 453 Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 5);\r
4c5a5e0c 454 if (Oro == NULL) {\r
455 Status = EFI_OUT_OF_RESOURCES;\r
456 goto ON_EXIT;\r
457 }\r
458\r
459 //\r
460 // Ask the server to reply with DNS and Boot File URL options by info request.\r
461 // All members in EFI_DHCP6_PACKET_OPTION are in network order.\r
462 //\r
142c00c3 463 Oro->OpCode = HTONS (DHCP6_OPT_ORO);\r
216f7970 464 Oro->OpLen = HTONS (2 * 3);\r
4c5a5e0c 465 Oro->Data[1] = DHCP6_OPT_DNS_SERVERS;\r
466 Oro->Data[3] = DHCP6_OPT_BOOT_FILE_URL;\r
142c00c3 467 Oro->Data[5] = DHCP6_OPT_BOOT_FILE_PARAM;\r
4c5a5e0c 468\r
469 InfoReqReXmit.Irt = 4;\r
470 InfoReqReXmit.Mrc = 1;\r
471 InfoReqReXmit.Mrt = 10;\r
472 InfoReqReXmit.Mrd = 30;\r
473\r
474 Status = Dhcp6->InfoRequest (\r
475 Dhcp6,\r
476 TRUE,\r
477 Oro,\r
478 0,\r
479 NULL,\r
480 &InfoReqReXmit,\r
481 NULL,\r
482 IScsiDhcp6ParseReply,\r
483 ConfigData\r
484 );\r
485 if (Status == EFI_NO_MAPPING) {\r
486 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
487 if (EFI_ERROR (Status)) {\r
488 goto ON_EXIT;\r
489 }\r
490\r
491 Status = gBS->SetTimer (\r
492 Timer,\r
493 TimerRelative,\r
494 ISCSI_GET_MAPPING_TIMEOUT\r
495 );\r
496\r
497 if (EFI_ERROR (Status)) {\r
498 goto ON_EXIT;\r
499 }\r
500\r
501 do {\r
502\r
503 TimerStatus = gBS->CheckEvent (Timer);\r
504\r
505 if (!EFI_ERROR (TimerStatus)) {\r
506 Status = Dhcp6->InfoRequest (\r
507 Dhcp6,\r
508 TRUE,\r
509 Oro,\r
510 0,\r
511 NULL,\r
512 &InfoReqReXmit,\r
513 NULL,\r
514 IScsiDhcp6ParseReply,\r
515 ConfigData\r
516 );\r
517 }\r
518\r
519 } while (TimerStatus == EFI_NOT_READY);\r
520\r
521 }\r
522\r
523ON_EXIT:\r
524\r
525 if (Oro != NULL) {\r
526 FreePool (Oro);\r
f75a7f56 527 }\r
4c5a5e0c 528\r
529 if (Timer != NULL) {\r
530 gBS->CloseEvent (Timer);\r
531 }\r
532\r
533 if (Dhcp6 != NULL) {\r
534 gBS->CloseProtocol (\r
535 Dhcp6Handle,\r
536 &gEfiDhcp6ProtocolGuid,\r
537 Image,\r
538 Controller\r
539 );\r
540 }\r
541\r
542 NetLibDestroyServiceChild (\r
543 Controller,\r
544 Image,\r
545 &gEfiDhcp6ServiceBindingProtocolGuid,\r
546 Dhcp6Handle\r
547 );\r
548\r
549 return Status;\r
550}\r
551\r