1 | /** @file
|
---|
2 | Implementation of EFI_IP6_PROTOCOL protocol interfaces.
|
---|
3 |
|
---|
4 | (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
|
---|
5 | Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
|
---|
6 |
|
---|
7 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
8 |
|
---|
9 | **/
|
---|
10 |
|
---|
11 | #include "Ip6Impl.h"
|
---|
12 |
|
---|
13 | EFI_IPSEC2_PROTOCOL *mIpSec = NULL;
|
---|
14 |
|
---|
15 | EFI_IP6_PROTOCOL mEfiIp6ProtocolTemplete = {
|
---|
16 | EfiIp6GetModeData,
|
---|
17 | EfiIp6Configure,
|
---|
18 | EfiIp6Groups,
|
---|
19 | EfiIp6Routes,
|
---|
20 | EfiIp6Neighbors,
|
---|
21 | EfiIp6Transmit,
|
---|
22 | EfiIp6Receive,
|
---|
23 | EfiIp6Cancel,
|
---|
24 | EfiIp6Poll
|
---|
25 | };
|
---|
26 |
|
---|
27 | /**
|
---|
28 | Gets the current operational settings for this instance of the EFI IPv6 Protocol driver.
|
---|
29 |
|
---|
30 | The GetModeData() function returns the current operational mode data for this driver instance.
|
---|
31 | The data fields in EFI_IP6_MODE_DATA are read only. This function is used optionally to
|
---|
32 | retrieve the operational mode data of underlying networks or drivers.
|
---|
33 |
|
---|
34 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
35 | @param[out] Ip6ModeData Pointer to the EFI IPv6 Protocol mode data structure.
|
---|
36 | @param[out] MnpConfigData Pointer to the managed network configuration data structure.
|
---|
37 | @param[out] SnpModeData Pointer to the simple network mode data structure.
|
---|
38 |
|
---|
39 | @retval EFI_SUCCESS The operation completed successfully.
|
---|
40 | @retval EFI_INVALID_PARAMETER This is NULL.
|
---|
41 | @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
|
---|
42 |
|
---|
43 | **/
|
---|
44 | EFI_STATUS
|
---|
45 | EFIAPI
|
---|
46 | EfiIp6GetModeData (
|
---|
47 | IN EFI_IP6_PROTOCOL *This,
|
---|
48 | OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL,
|
---|
49 | OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
|
---|
50 | OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
|
---|
51 | )
|
---|
52 | {
|
---|
53 | IP6_PROTOCOL *IpInstance;
|
---|
54 | IP6_SERVICE *IpSb;
|
---|
55 | IP6_INTERFACE *IpIf;
|
---|
56 | EFI_IP6_CONFIG_DATA *Config;
|
---|
57 | EFI_STATUS Status;
|
---|
58 | EFI_TPL OldTpl;
|
---|
59 |
|
---|
60 | if (This == NULL) {
|
---|
61 | return EFI_INVALID_PARAMETER;
|
---|
62 | }
|
---|
63 |
|
---|
64 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
65 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
66 | IpSb = IpInstance->Service;
|
---|
67 | IpIf = IpInstance->Interface;
|
---|
68 |
|
---|
69 | if (IpSb->LinkLocalDadFail) {
|
---|
70 | return EFI_INVALID_PARAMETER;
|
---|
71 | }
|
---|
72 |
|
---|
73 | if (Ip6ModeData != NULL) {
|
---|
74 | //
|
---|
75 | // IsStarted is "whether the EfiIp6Configure has been called".
|
---|
76 | // IsConfigured is "whether the station address has been configured"
|
---|
77 | //
|
---|
78 | Ip6ModeData->IsStarted = (BOOLEAN)(IpInstance->State == IP6_STATE_CONFIGED);
|
---|
79 | Ip6ModeData->MaxPacketSize = IpSb->MaxPacketSize;
|
---|
80 | CopyMem (&Ip6ModeData->ConfigData, &IpInstance->ConfigData, sizeof (EFI_IP6_CONFIG_DATA));
|
---|
81 | Ip6ModeData->IsConfigured = FALSE;
|
---|
82 |
|
---|
83 | Ip6ModeData->AddressCount = 0;
|
---|
84 | Ip6ModeData->AddressList = NULL;
|
---|
85 |
|
---|
86 | Ip6ModeData->GroupCount = IpInstance->GroupCount;
|
---|
87 | Ip6ModeData->GroupTable = NULL;
|
---|
88 |
|
---|
89 | Ip6ModeData->RouteCount = 0;
|
---|
90 | Ip6ModeData->RouteTable = NULL;
|
---|
91 |
|
---|
92 | Ip6ModeData->NeighborCount = 0;
|
---|
93 | Ip6ModeData->NeighborCache = NULL;
|
---|
94 |
|
---|
95 | Ip6ModeData->PrefixCount = 0;
|
---|
96 | Ip6ModeData->PrefixTable = NULL;
|
---|
97 |
|
---|
98 | Ip6ModeData->IcmpTypeCount = 23;
|
---|
99 | Ip6ModeData->IcmpTypeList = AllocateCopyPool (
|
---|
100 | Ip6ModeData->IcmpTypeCount * sizeof (EFI_IP6_ICMP_TYPE),
|
---|
101 | mIp6SupportedIcmp
|
---|
102 | );
|
---|
103 | if (Ip6ModeData->IcmpTypeList == NULL) {
|
---|
104 | Status = EFI_OUT_OF_RESOURCES;
|
---|
105 | goto Error;
|
---|
106 | }
|
---|
107 |
|
---|
108 | //
|
---|
109 | // Return the currently configured IPv6 addresses and corresponding prefix lengths.
|
---|
110 | //
|
---|
111 | Status = Ip6BuildEfiAddressList (
|
---|
112 | IpSb,
|
---|
113 | &Ip6ModeData->AddressCount,
|
---|
114 | &Ip6ModeData->AddressList
|
---|
115 | );
|
---|
116 | if (EFI_ERROR (Status)) {
|
---|
117 | goto Error;
|
---|
118 | }
|
---|
119 |
|
---|
120 | //
|
---|
121 | // Return the current station address for this IP child.
|
---|
122 | // If UseAnyStationAddress is set to TRUE, IP6 driver will
|
---|
123 | // select a source address from its address list. Otherwise use the
|
---|
124 | // StationAddress in config data.
|
---|
125 | //
|
---|
126 | if (Ip6ModeData->IsStarted) {
|
---|
127 | Config = &Ip6ModeData->ConfigData;
|
---|
128 |
|
---|
129 | if (IpIf->Configured || NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
|
---|
130 | Ip6ModeData->IsConfigured = TRUE;
|
---|
131 | } else {
|
---|
132 | Ip6ModeData->IsConfigured = FALSE;
|
---|
133 | }
|
---|
134 |
|
---|
135 | //
|
---|
136 | // Build a EFI route table for user from the internal route table.
|
---|
137 | //
|
---|
138 | Status = Ip6BuildEfiRouteTable (
|
---|
139 | IpSb->RouteTable,
|
---|
140 | &Ip6ModeData->RouteCount,
|
---|
141 | &Ip6ModeData->RouteTable
|
---|
142 | );
|
---|
143 |
|
---|
144 | if (EFI_ERROR (Status)) {
|
---|
145 | goto Error;
|
---|
146 | }
|
---|
147 | }
|
---|
148 |
|
---|
149 | if (Ip6ModeData->IsConfigured) {
|
---|
150 | //
|
---|
151 | // Return the joined multicast group addresses.
|
---|
152 | //
|
---|
153 | if (IpInstance->GroupCount != 0) {
|
---|
154 | Ip6ModeData->GroupTable = AllocateCopyPool (
|
---|
155 | IpInstance->GroupCount * sizeof (EFI_IPv6_ADDRESS),
|
---|
156 | IpInstance->GroupList
|
---|
157 | );
|
---|
158 | if (Ip6ModeData->GroupTable == NULL) {
|
---|
159 | Status = EFI_OUT_OF_RESOURCES;
|
---|
160 | goto Error;
|
---|
161 | }
|
---|
162 | }
|
---|
163 |
|
---|
164 | //
|
---|
165 | // Return the neighbor cache entries
|
---|
166 | //
|
---|
167 | Status = Ip6BuildEfiNeighborCache (
|
---|
168 | IpInstance,
|
---|
169 | &Ip6ModeData->NeighborCount,
|
---|
170 | &Ip6ModeData->NeighborCache
|
---|
171 | );
|
---|
172 | if (EFI_ERROR (Status)) {
|
---|
173 | goto Error;
|
---|
174 | }
|
---|
175 |
|
---|
176 | //
|
---|
177 | // Return the prefix table entries
|
---|
178 | //
|
---|
179 | Status = Ip6BuildPrefixTable (
|
---|
180 | IpInstance,
|
---|
181 | &Ip6ModeData->PrefixCount,
|
---|
182 | &Ip6ModeData->PrefixTable
|
---|
183 | );
|
---|
184 | if (EFI_ERROR (Status)) {
|
---|
185 | goto Error;
|
---|
186 | }
|
---|
187 | }
|
---|
188 | }
|
---|
189 |
|
---|
190 | //
|
---|
191 | // Get fresh mode data from MNP, since underlying media status may change
|
---|
192 | //
|
---|
193 | Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);
|
---|
194 |
|
---|
195 | goto Exit;
|
---|
196 |
|
---|
197 | Error:
|
---|
198 | if (Ip6ModeData != NULL) {
|
---|
199 | if (Ip6ModeData->AddressList != NULL) {
|
---|
200 | FreePool (Ip6ModeData->AddressList);
|
---|
201 | }
|
---|
202 |
|
---|
203 | if (Ip6ModeData->GroupTable != NULL) {
|
---|
204 | FreePool (Ip6ModeData->GroupTable);
|
---|
205 | }
|
---|
206 |
|
---|
207 | if (Ip6ModeData->RouteTable != NULL) {
|
---|
208 | FreePool (Ip6ModeData->RouteTable);
|
---|
209 | }
|
---|
210 |
|
---|
211 | if (Ip6ModeData->NeighborCache != NULL) {
|
---|
212 | FreePool (Ip6ModeData->NeighborCache);
|
---|
213 | }
|
---|
214 |
|
---|
215 | if (Ip6ModeData->PrefixTable != NULL) {
|
---|
216 | FreePool (Ip6ModeData->PrefixTable);
|
---|
217 | }
|
---|
218 |
|
---|
219 | if (Ip6ModeData->IcmpTypeList != NULL) {
|
---|
220 | FreePool (Ip6ModeData->IcmpTypeList);
|
---|
221 | }
|
---|
222 | }
|
---|
223 |
|
---|
224 | Exit:
|
---|
225 | gBS->RestoreTPL (OldTpl);
|
---|
226 | return Status;
|
---|
227 | }
|
---|
228 |
|
---|
229 | /**
|
---|
230 | Validate that Ipv6 address is OK to be used as station address or next hop address/ neighbor.
|
---|
231 |
|
---|
232 | @param[in] IpSb The IP6 service instance.
|
---|
233 | @param[in] Ip The IPv6 address to validate.
|
---|
234 | @param[in] Flag If TRUE, validate if the address is OK to be used
|
---|
235 | as station address. If FALSE, validate if the
|
---|
236 | address is OK to be used as the next hop address/
|
---|
237 | neighbor.
|
---|
238 |
|
---|
239 | @retval TRUE The Ip address is valid and could be used.
|
---|
240 | @retval FALSE Invalid Ip address.
|
---|
241 |
|
---|
242 | **/
|
---|
243 | BOOLEAN
|
---|
244 | Ip6IsValidAddress (
|
---|
245 | IN IP6_SERVICE *IpSb,
|
---|
246 | IN EFI_IPv6_ADDRESS *Ip,
|
---|
247 | IN BOOLEAN Flag
|
---|
248 | )
|
---|
249 | {
|
---|
250 | if (!NetIp6IsUnspecifiedAddr (Ip)) {
|
---|
251 | if (!NetIp6IsValidUnicast (Ip)) {
|
---|
252 | return FALSE;
|
---|
253 | }
|
---|
254 |
|
---|
255 | if (Ip6IsOneOfSetAddress (IpSb, Ip, NULL, NULL)) {
|
---|
256 | return Flag;
|
---|
257 | }
|
---|
258 | } else {
|
---|
259 | return Flag;
|
---|
260 | }
|
---|
261 |
|
---|
262 | return (BOOLEAN) !Flag;
|
---|
263 | }
|
---|
264 |
|
---|
265 | /**
|
---|
266 | Validate whether the value of protocol is illegal or not. Protocol is the 'Next Header' field
|
---|
267 | in the last IPv6 extension header, or basic IPv6 header is there's no extension header.
|
---|
268 |
|
---|
269 | @param[in] Protocol Default value of 'Next Header'
|
---|
270 |
|
---|
271 | @retval TRUE The protocol is illegal.
|
---|
272 | @retval FALSE The protocol is legal.
|
---|
273 |
|
---|
274 | **/
|
---|
275 | BOOLEAN
|
---|
276 | Ip6IsIllegalProtocol (
|
---|
277 | IN UINT8 Protocol
|
---|
278 | )
|
---|
279 | {
|
---|
280 | if ((Protocol == IP6_HOP_BY_HOP) || (Protocol == EFI_IP_PROTO_ICMP) || (Protocol == IP4_PROTO_IGMP)) {
|
---|
281 | return TRUE;
|
---|
282 | }
|
---|
283 |
|
---|
284 | if ((Protocol == 41) || (Protocol == 43) || (Protocol == 44) || (Protocol == 59) || (Protocol == 60) || (Protocol == 124)) {
|
---|
285 | return TRUE;
|
---|
286 | }
|
---|
287 |
|
---|
288 | return FALSE;
|
---|
289 | }
|
---|
290 |
|
---|
291 | /**
|
---|
292 | Initialize the IP6_PROTOCOL structure to the unconfigured states.
|
---|
293 |
|
---|
294 | @param[in] IpSb The IP6 service instance.
|
---|
295 | @param[in, out] IpInstance The IP6 child instance.
|
---|
296 |
|
---|
297 | **/
|
---|
298 | VOID
|
---|
299 | Ip6InitProtocol (
|
---|
300 | IN IP6_SERVICE *IpSb,
|
---|
301 | IN OUT IP6_PROTOCOL *IpInstance
|
---|
302 | )
|
---|
303 | {
|
---|
304 | ASSERT ((IpSb != NULL) && (IpInstance != NULL));
|
---|
305 |
|
---|
306 | ZeroMem (IpInstance, sizeof (IP6_PROTOCOL));
|
---|
307 |
|
---|
308 | IpInstance->Signature = IP6_PROTOCOL_SIGNATURE;
|
---|
309 | IpInstance->State = IP6_STATE_UNCONFIGED;
|
---|
310 | IpInstance->Service = IpSb;
|
---|
311 | IpInstance->GroupList = NULL;
|
---|
312 | CopyMem (&IpInstance->Ip6Proto, &mEfiIp6ProtocolTemplete, sizeof (EFI_IP6_PROTOCOL));
|
---|
313 |
|
---|
314 | NetMapInit (&IpInstance->RxTokens);
|
---|
315 | NetMapInit (&IpInstance->TxTokens);
|
---|
316 | InitializeListHead (&IpInstance->Received);
|
---|
317 | InitializeListHead (&IpInstance->Delivered);
|
---|
318 |
|
---|
319 | EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
|
---|
320 | }
|
---|
321 |
|
---|
322 | /**
|
---|
323 | Configure the IP6 child. If the child is already configured,
|
---|
324 | change the configuration parameter. Otherwise, configure it
|
---|
325 | for the first time. The caller should validate the configuration
|
---|
326 | before deliver them to it. It also don't do configure NULL.
|
---|
327 |
|
---|
328 | @param[in, out] IpInstance The IP6 child to configure.
|
---|
329 | @param[in] Config The configure data.
|
---|
330 |
|
---|
331 | @retval EFI_SUCCESS The IP6 child is successfully configured.
|
---|
332 | @retval EFI_DEVICE_ERROR Failed to free the pending transive or to
|
---|
333 | configure underlying MNP, or other errors.
|
---|
334 | @retval EFI_NO_MAPPING The IP6 child is configured to use the default
|
---|
335 | address, but the default address hasn't been
|
---|
336 | configured. The IP6 child doesn't need to be
|
---|
337 | reconfigured when the default address is configured.
|
---|
338 | @retval EFI_OUT_OF_RESOURCES No more memory space is available.
|
---|
339 | @retval other Other error occurs.
|
---|
340 |
|
---|
341 | **/
|
---|
342 | EFI_STATUS
|
---|
343 | Ip6ConfigProtocol (
|
---|
344 | IN OUT IP6_PROTOCOL *IpInstance,
|
---|
345 | IN EFI_IP6_CONFIG_DATA *Config
|
---|
346 | )
|
---|
347 | {
|
---|
348 | IP6_SERVICE *IpSb;
|
---|
349 | IP6_INTERFACE *IpIf;
|
---|
350 | EFI_STATUS Status;
|
---|
351 | EFI_IP6_CONFIG_DATA *Current;
|
---|
352 | IP6_ADDRESS_INFO *AddressInfo;
|
---|
353 | BOOLEAN StationZero;
|
---|
354 | BOOLEAN DestZero;
|
---|
355 | EFI_IPv6_ADDRESS Source;
|
---|
356 | BOOLEAN AddrOk;
|
---|
357 |
|
---|
358 | IpSb = IpInstance->Service;
|
---|
359 | Current = &IpInstance->ConfigData;
|
---|
360 |
|
---|
361 | //
|
---|
362 | // User is changing packet filters. It must be stopped
|
---|
363 | // before the station address can be changed.
|
---|
364 | //
|
---|
365 | if (IpInstance->State == IP6_STATE_CONFIGED) {
|
---|
366 | //
|
---|
367 | // Cancel all the pending transmit/receive from upper layer
|
---|
368 | //
|
---|
369 | Status = Ip6Cancel (IpInstance, NULL);
|
---|
370 |
|
---|
371 | if (EFI_ERROR (Status)) {
|
---|
372 | return EFI_DEVICE_ERROR;
|
---|
373 | }
|
---|
374 |
|
---|
375 | CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
|
---|
376 | return EFI_SUCCESS;
|
---|
377 | }
|
---|
378 |
|
---|
379 | //
|
---|
380 | // Set up the interface.
|
---|
381 | //
|
---|
382 | StationZero = NetIp6IsUnspecifiedAddr (&Config->StationAddress);
|
---|
383 | DestZero = NetIp6IsUnspecifiedAddr (&Config->DestinationAddress);
|
---|
384 |
|
---|
385 | if (StationZero && DestZero) {
|
---|
386 | //
|
---|
387 | // StationAddress is still zero.
|
---|
388 | //
|
---|
389 |
|
---|
390 | NET_GET_REF (IpSb->DefaultInterface);
|
---|
391 | IpInstance->Interface = IpSb->DefaultInterface;
|
---|
392 | InsertTailList (&IpSb->DefaultInterface->IpInstances, &IpInstance->AddrLink);
|
---|
393 |
|
---|
394 | CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
|
---|
395 | IpInstance->State = IP6_STATE_CONFIGED;
|
---|
396 |
|
---|
397 | return EFI_SUCCESS;
|
---|
398 | }
|
---|
399 |
|
---|
400 | if (StationZero && !DestZero) {
|
---|
401 | Status = Ip6SelectSourceAddress (IpSb, &Config->DestinationAddress, &Source);
|
---|
402 | if (EFI_ERROR (Status)) {
|
---|
403 | return Status;
|
---|
404 | }
|
---|
405 | } else {
|
---|
406 | IP6_COPY_ADDRESS (&Source, &Config->StationAddress);
|
---|
407 | }
|
---|
408 |
|
---|
409 | AddrOk = Ip6IsOneOfSetAddress (IpSb, &Source, &IpIf, &AddressInfo);
|
---|
410 | if (AddrOk) {
|
---|
411 | if (AddressInfo != NULL) {
|
---|
412 | IpInstance->PrefixLength = AddressInfo->PrefixLength;
|
---|
413 | } else {
|
---|
414 | IpInstance->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
|
---|
415 | }
|
---|
416 | } else {
|
---|
417 | //
|
---|
418 | // The specified source address is not one of the addresses IPv6 maintains.
|
---|
419 | //
|
---|
420 | return EFI_INVALID_PARAMETER;
|
---|
421 | }
|
---|
422 |
|
---|
423 | NET_GET_REF (IpIf);
|
---|
424 | IpInstance->Interface = IpIf;
|
---|
425 | InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
|
---|
426 |
|
---|
427 | CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
|
---|
428 | IP6_COPY_ADDRESS (&Current->StationAddress, &Source);
|
---|
429 | IpInstance->State = IP6_STATE_CONFIGED;
|
---|
430 |
|
---|
431 | return EFI_SUCCESS;
|
---|
432 | }
|
---|
433 |
|
---|
434 | /**
|
---|
435 | Clean up the IP6 child, and release all the resources used by it.
|
---|
436 |
|
---|
437 | @param[in, out] IpInstance The IP6 child to clean up.
|
---|
438 |
|
---|
439 | @retval EFI_SUCCESS The IP6 child is cleaned up.
|
---|
440 | @retval EFI_DEVICE_ERROR Some resources failed to be released.
|
---|
441 |
|
---|
442 | **/
|
---|
443 | EFI_STATUS
|
---|
444 | Ip6CleanProtocol (
|
---|
445 | IN OUT IP6_PROTOCOL *IpInstance
|
---|
446 | )
|
---|
447 | {
|
---|
448 | if (EFI_ERROR (Ip6Cancel (IpInstance, NULL))) {
|
---|
449 | return EFI_DEVICE_ERROR;
|
---|
450 | }
|
---|
451 |
|
---|
452 | if (EFI_ERROR (Ip6Groups (IpInstance, FALSE, NULL))) {
|
---|
453 | return EFI_DEVICE_ERROR;
|
---|
454 | }
|
---|
455 |
|
---|
456 | //
|
---|
457 | // Some packets haven't been recycled. It is because either the
|
---|
458 | // user forgets to recycle the packets, or because the callback
|
---|
459 | // hasn't been called. Just leave it alone.
|
---|
460 | //
|
---|
461 | if (!IsListEmpty (&IpInstance->Delivered)) {
|
---|
462 | }
|
---|
463 |
|
---|
464 | if (IpInstance->Interface != NULL) {
|
---|
465 | RemoveEntryList (&IpInstance->AddrLink);
|
---|
466 | Ip6CleanInterface (IpInstance->Interface, IpInstance);
|
---|
467 | IpInstance->Interface = NULL;
|
---|
468 | }
|
---|
469 |
|
---|
470 | if (IpInstance->GroupList != NULL) {
|
---|
471 | FreePool (IpInstance->GroupList);
|
---|
472 | IpInstance->GroupList = NULL;
|
---|
473 | IpInstance->GroupCount = 0;
|
---|
474 | }
|
---|
475 |
|
---|
476 | NetMapClean (&IpInstance->TxTokens);
|
---|
477 |
|
---|
478 | NetMapClean (&IpInstance->RxTokens);
|
---|
479 |
|
---|
480 | return EFI_SUCCESS;
|
---|
481 | }
|
---|
482 |
|
---|
483 | /**
|
---|
484 | Configure the MNP parameter used by IP. The IP driver uses one MNP
|
---|
485 | child to transmit/receive frames. By default, it configures MNP
|
---|
486 | to receive unicast/multicast/broadcast. Also, it will enable/disable
|
---|
487 | the promiscuous receive according to whether there is IP child
|
---|
488 | enable that or not. If Force is FALSE, it will iterate through
|
---|
489 | all the IP children to check whether the promiscuous receive
|
---|
490 | setting has been changed. If it hasn't been changed, it won't
|
---|
491 | reconfigure the MNP. If Force is TRUE, the MNP is configured
|
---|
492 | whether that is changed or not.
|
---|
493 |
|
---|
494 | @param[in] IpSb The IP6 service instance that is to be changed.
|
---|
495 | @param[in] Force Force the configuration or not.
|
---|
496 |
|
---|
497 | @retval EFI_SUCCESS The MNP successfully configured/reconfigured.
|
---|
498 | @retval Others Configuration failed.
|
---|
499 |
|
---|
500 | **/
|
---|
501 | EFI_STATUS
|
---|
502 | Ip6ServiceConfigMnp (
|
---|
503 | IN IP6_SERVICE *IpSb,
|
---|
504 | IN BOOLEAN Force
|
---|
505 | )
|
---|
506 | {
|
---|
507 | LIST_ENTRY *Entry;
|
---|
508 | LIST_ENTRY *ProtoEntry;
|
---|
509 | IP6_INTERFACE *IpIf;
|
---|
510 | IP6_PROTOCOL *IpInstance;
|
---|
511 | BOOLEAN Reconfig;
|
---|
512 | BOOLEAN PromiscReceive;
|
---|
513 | EFI_STATUS Status;
|
---|
514 |
|
---|
515 | Reconfig = FALSE;
|
---|
516 | PromiscReceive = FALSE;
|
---|
517 |
|
---|
518 | if (!Force) {
|
---|
519 | //
|
---|
520 | // Iterate through the IP children to check whether promiscuous
|
---|
521 | // receive setting has been changed. Update the interface's receive
|
---|
522 | // filter also.
|
---|
523 | //
|
---|
524 | NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
|
---|
525 | IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
|
---|
526 | IpIf->PromiscRecv = FALSE;
|
---|
527 |
|
---|
528 | NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
|
---|
529 | IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP6_PROTOCOL, AddrLink);
|
---|
530 |
|
---|
531 | if (IpInstance->ConfigData.AcceptPromiscuous) {
|
---|
532 | IpIf->PromiscRecv = TRUE;
|
---|
533 | PromiscReceive = TRUE;
|
---|
534 | }
|
---|
535 | }
|
---|
536 | }
|
---|
537 |
|
---|
538 | //
|
---|
539 | // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
|
---|
540 | //
|
---|
541 | if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
|
---|
542 | return EFI_SUCCESS;
|
---|
543 | }
|
---|
544 |
|
---|
545 | Reconfig = TRUE;
|
---|
546 | IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
|
---|
547 | }
|
---|
548 |
|
---|
549 | Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
|
---|
550 |
|
---|
551 | //
|
---|
552 | // recover the original configuration if failed to set the configure.
|
---|
553 | //
|
---|
554 | if (EFI_ERROR (Status) && Reconfig) {
|
---|
555 | IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
|
---|
556 | }
|
---|
557 |
|
---|
558 | return Status;
|
---|
559 | }
|
---|
560 |
|
---|
561 | /**
|
---|
562 | Assigns an IPv6 address and subnet mask to this EFI IPv6 Protocol driver instance.
|
---|
563 |
|
---|
564 | The Configure() function is used to set, change, or reset the operational parameters and filter
|
---|
565 | settings for this EFI IPv6 Protocol instance. Until these parameters have been set, no network traffic
|
---|
566 | can be sent or received by this instance. Once the parameters have been reset (by calling this
|
---|
567 | function with Ip6ConfigData set to NULL), no more traffic can be sent or received until these
|
---|
568 | parameters have been set again. Each EFI IPv6 Protocol instance can be started and stopped
|
---|
569 | independently of each other by enabling or disabling their receive filter settings with the
|
---|
570 | Configure() function.
|
---|
571 |
|
---|
572 | If Ip6ConfigData.StationAddress is a valid non-zero IPv6 unicast address, it is required
|
---|
573 | to be one of the currently configured IPv6 addresses listed in the EFI IPv6 drivers, or else
|
---|
574 | EFI_INVALID_PARAMETER will be returned. If Ip6ConfigData.StationAddress is
|
---|
575 | unspecified, the IPv6 driver will bind a source address according to the source address selection
|
---|
576 | algorithm. Clients could frequently call GetModeData() to check get currently configured IPv6
|
---|
577 | address list in the EFI IPv6 driver. If both Ip6ConfigData.StationAddress and
|
---|
578 | Ip6ConfigData.Destination are unspecified, when transmitting the packet afterwards, the
|
---|
579 | source address filled in each outgoing IPv6 packet is decided based on the destination of this packet.
|
---|
580 |
|
---|
581 | If operational parameters are reset or changed, any pending transmit and receive requests will be
|
---|
582 | cancelled. Their completion token status will be set to EFI_ABORTED and their events will be
|
---|
583 | signaled.
|
---|
584 |
|
---|
585 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
586 | @param[in] Ip6ConfigData Pointer to the EFI IPv6 Protocol configuration data structure.
|
---|
587 | If NULL, reset the configuration data.
|
---|
588 |
|
---|
589 | @retval EFI_SUCCESS The driver instance was successfully opened.
|
---|
590 | @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
|
---|
591 | - This is NULL.
|
---|
592 | - Ip6ConfigData.StationAddress is neither zero nor
|
---|
593 | a unicast IPv6 address.
|
---|
594 | - Ip6ConfigData.StationAddress is neither zero nor
|
---|
595 | one of the configured IP addresses in the EFI IPv6 driver.
|
---|
596 | - Ip6ConfigData.DefaultProtocol is illegal.
|
---|
597 | @retval EFI_OUT_OF_RESOURCES The EFI IPv6 Protocol driver instance data could not be allocated.
|
---|
598 | @retval EFI_NO_MAPPING The IPv6 driver was responsible for choosing a source address for
|
---|
599 | this instance, but no source address was available for use.
|
---|
600 | @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the IPv6
|
---|
601 | address or prefix length can be changed.
|
---|
602 | @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv6
|
---|
603 | Protocol driver instance was not opened.
|
---|
604 | @retval EFI_UNSUPPORTED Default protocol specified through
|
---|
605 | Ip6ConfigData.DefaultProtocol isn't supported.
|
---|
606 |
|
---|
607 | **/
|
---|
608 | EFI_STATUS
|
---|
609 | EFIAPI
|
---|
610 | EfiIp6Configure (
|
---|
611 | IN EFI_IP6_PROTOCOL *This,
|
---|
612 | IN EFI_IP6_CONFIG_DATA *Ip6ConfigData OPTIONAL
|
---|
613 | )
|
---|
614 | {
|
---|
615 | IP6_PROTOCOL *IpInstance;
|
---|
616 | EFI_IP6_CONFIG_DATA *Current;
|
---|
617 | EFI_TPL OldTpl;
|
---|
618 | EFI_STATUS Status;
|
---|
619 | IP6_SERVICE *IpSb;
|
---|
620 |
|
---|
621 | //
|
---|
622 | // First, validate the parameters
|
---|
623 | //
|
---|
624 | if (This == NULL) {
|
---|
625 | return EFI_INVALID_PARAMETER;
|
---|
626 | }
|
---|
627 |
|
---|
628 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
629 | IpSb = IpInstance->Service;
|
---|
630 |
|
---|
631 | if (IpSb->LinkLocalDadFail && (Ip6ConfigData != NULL)) {
|
---|
632 | return EFI_DEVICE_ERROR;
|
---|
633 | }
|
---|
634 |
|
---|
635 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
636 |
|
---|
637 | Status = EFI_INVALID_PARAMETER;
|
---|
638 |
|
---|
639 | //
|
---|
640 | // Validate the configuration first.
|
---|
641 | //
|
---|
642 | if (Ip6ConfigData != NULL) {
|
---|
643 | //
|
---|
644 | // Check whether the station address is valid.
|
---|
645 | //
|
---|
646 | if (!Ip6IsValidAddress (IpSb, &Ip6ConfigData->StationAddress, TRUE)) {
|
---|
647 | goto Exit;
|
---|
648 | }
|
---|
649 |
|
---|
650 | //
|
---|
651 | // Check whether the default protocol is valid.
|
---|
652 | //
|
---|
653 | if (Ip6IsIllegalProtocol (Ip6ConfigData->DefaultProtocol)) {
|
---|
654 | goto Exit;
|
---|
655 | }
|
---|
656 |
|
---|
657 | //
|
---|
658 | // User can only update packet filters when already configured.
|
---|
659 | // If it wants to change the station address, it must configure(NULL)
|
---|
660 | // the instance firstly.
|
---|
661 | //
|
---|
662 | if (IpInstance->State == IP6_STATE_CONFIGED) {
|
---|
663 | Current = &IpInstance->ConfigData;
|
---|
664 |
|
---|
665 | if (!EFI_IP6_EQUAL (&Current->StationAddress, &Ip6ConfigData->StationAddress)) {
|
---|
666 | Status = EFI_ALREADY_STARTED;
|
---|
667 | goto Exit;
|
---|
668 | }
|
---|
669 |
|
---|
670 | if (NetIp6IsUnspecifiedAddr (&Current->StationAddress) && IP6_NO_MAPPING (IpInstance)) {
|
---|
671 | Status = EFI_NO_MAPPING;
|
---|
672 | goto Exit;
|
---|
673 | }
|
---|
674 | }
|
---|
675 | }
|
---|
676 |
|
---|
677 | //
|
---|
678 | // Configure the instance or clean it up.
|
---|
679 | //
|
---|
680 | if (Ip6ConfigData != NULL) {
|
---|
681 | Status = Ip6ConfigProtocol (IpInstance, Ip6ConfigData);
|
---|
682 | } else {
|
---|
683 | Status = Ip6CleanProtocol (IpInstance);
|
---|
684 |
|
---|
685 | //
|
---|
686 | // Don't change the state if it is DESTROY, consider the following
|
---|
687 | // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
|
---|
688 | // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
|
---|
689 | // the unload fails miserably.
|
---|
690 | //
|
---|
691 | if (IpInstance->State == IP6_STATE_CONFIGED) {
|
---|
692 | IpInstance->State = IP6_STATE_UNCONFIGED;
|
---|
693 | }
|
---|
694 | }
|
---|
695 |
|
---|
696 | //
|
---|
697 | // Update the MNP's configure data. Ip6ServiceConfigMnp will check
|
---|
698 | // whether it is necessary to reconfigure the MNP.
|
---|
699 | //
|
---|
700 | Ip6ServiceConfigMnp (IpInstance->Service, FALSE);
|
---|
701 |
|
---|
702 | Exit:
|
---|
703 | gBS->RestoreTPL (OldTpl);
|
---|
704 | return Status;
|
---|
705 | }
|
---|
706 |
|
---|
707 | /**
|
---|
708 | Joins and leaves multicast groups.
|
---|
709 |
|
---|
710 | The Groups() function is used to join and leave multicast group sessions. Joining a group will
|
---|
711 | enable reception of matching multicast packets. Leaving a group will disable reception of matching
|
---|
712 | multicast packets. Source-Specific Multicast isn't required to be supported.
|
---|
713 |
|
---|
714 | If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
|
---|
715 |
|
---|
716 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
717 | @param[in] JoinFlag Set to TRUE to join the multicast group session, and FALSE to leave.
|
---|
718 | @param[in] GroupAddress Pointer to the IPv6 multicast address.
|
---|
719 | This is an optional parameter that may be NULL.
|
---|
720 |
|
---|
721 | @retval EFI_SUCCESS The operation completed successfully.
|
---|
722 | @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
|
---|
723 | - This is NULL.
|
---|
724 | - JoinFlag is TRUE and GroupAddress is NULL.
|
---|
725 | - GroupAddress is not NULL and *GroupAddress is
|
---|
726 | not a multicast IPv6 address.
|
---|
727 | - GroupAddress is not NULL and *GroupAddress is in the
|
---|
728 | range of SSM destination address.
|
---|
729 | @retval EFI_NOT_STARTED This instance has not been started.
|
---|
730 | @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
|
---|
731 | @retval EFI_UNSUPPORTED This EFI IPv6 Protocol implementation does not support multicast groups.
|
---|
732 | @retval EFI_ALREADY_STARTED The group address is already in the group table (when
|
---|
733 | JoinFlag is TRUE).
|
---|
734 | @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
|
---|
735 | @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
|
---|
736 |
|
---|
737 | **/
|
---|
738 | EFI_STATUS
|
---|
739 | EFIAPI
|
---|
740 | EfiIp6Groups (
|
---|
741 | IN EFI_IP6_PROTOCOL *This,
|
---|
742 | IN BOOLEAN JoinFlag,
|
---|
743 | IN EFI_IPv6_ADDRESS *GroupAddress OPTIONAL
|
---|
744 | )
|
---|
745 | {
|
---|
746 | EFI_TPL OldTpl;
|
---|
747 | EFI_STATUS Status;
|
---|
748 | IP6_PROTOCOL *IpInstance;
|
---|
749 | IP6_SERVICE *IpSb;
|
---|
750 |
|
---|
751 | if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
|
---|
752 | return EFI_INVALID_PARAMETER;
|
---|
753 | }
|
---|
754 |
|
---|
755 | if ((GroupAddress != NULL) && !IP6_IS_MULTICAST (GroupAddress)) {
|
---|
756 | return EFI_INVALID_PARAMETER;
|
---|
757 | }
|
---|
758 |
|
---|
759 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
760 | IpSb = IpInstance->Service;
|
---|
761 |
|
---|
762 | if (IpSb->LinkLocalDadFail) {
|
---|
763 | return EFI_DEVICE_ERROR;
|
---|
764 | }
|
---|
765 |
|
---|
766 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
767 |
|
---|
768 | if (IpInstance->State != IP6_STATE_CONFIGED) {
|
---|
769 | Status = EFI_NOT_STARTED;
|
---|
770 | goto ON_EXIT;
|
---|
771 | }
|
---|
772 |
|
---|
773 | Status = Ip6Groups (IpInstance, JoinFlag, GroupAddress);
|
---|
774 |
|
---|
775 | ON_EXIT:
|
---|
776 | gBS->RestoreTPL (OldTpl);
|
---|
777 | return Status;
|
---|
778 | }
|
---|
779 |
|
---|
780 | /**
|
---|
781 | Adds and deletes routing table entries.
|
---|
782 |
|
---|
783 | The Routes() function adds a route to, or deletes a route from, the routing table.
|
---|
784 |
|
---|
785 | Routes are determined by comparing the leftmost PrefixLength bits of Destination with
|
---|
786 | the destination IPv6 address arithmetically. The gateway address must be on the same subnet as the
|
---|
787 | configured station address.
|
---|
788 |
|
---|
789 | The default route is added with Destination and PrefixLength both set to all zeros. The
|
---|
790 | default route matches all destination IPv6 addresses that do not match any other routes.
|
---|
791 |
|
---|
792 | All EFI IPv6 Protocol instances share a routing table.
|
---|
793 |
|
---|
794 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
795 | @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
|
---|
796 | FALSE to add this route to the routing table. Destination,
|
---|
797 | PrefixLength and Gateway are used as the key to each
|
---|
798 | route entry.
|
---|
799 | @param[in] Destination The address prefix of the subnet that needs to be routed.
|
---|
800 | This is an optional parameter that may be NULL.
|
---|
801 | @param[in] PrefixLength The prefix length of Destination. Ignored if Destination
|
---|
802 | is NULL.
|
---|
803 | @param[in] GatewayAddress The unicast gateway IPv6 address for this route.
|
---|
804 | This is an optional parameter that may be NULL.
|
---|
805 |
|
---|
806 | @retval EFI_SUCCESS The operation completed successfully.
|
---|
807 | @retval EFI_NOT_STARTED The driver instance has not been started.
|
---|
808 | @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
|
---|
809 | - This is NULL.
|
---|
810 | - When DeleteRoute is TRUE, both Destination and
|
---|
811 | GatewayAddress are NULL.
|
---|
812 | - When DeleteRoute is FALSE, either Destination or
|
---|
813 | GatewayAddress is NULL.
|
---|
814 | - *GatewayAddress is not a valid unicast IPv6 address.
|
---|
815 | - *GatewayAddress is one of the local configured IPv6
|
---|
816 | addresses.
|
---|
817 | @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
|
---|
818 | @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
|
---|
819 | @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
|
---|
820 | DeleteRoute is FALSE).
|
---|
821 |
|
---|
822 | **/
|
---|
823 | EFI_STATUS
|
---|
824 | EFIAPI
|
---|
825 | EfiIp6Routes (
|
---|
826 | IN EFI_IP6_PROTOCOL *This,
|
---|
827 | IN BOOLEAN DeleteRoute,
|
---|
828 | IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
|
---|
829 | IN UINT8 PrefixLength,
|
---|
830 | IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL
|
---|
831 | )
|
---|
832 | {
|
---|
833 | IP6_PROTOCOL *IpInstance;
|
---|
834 | EFI_STATUS Status;
|
---|
835 | EFI_TPL OldTpl;
|
---|
836 | IP6_SERVICE *IpSb;
|
---|
837 |
|
---|
838 | if ((This == NULL) || (PrefixLength > IP6_PREFIX_MAX)) {
|
---|
839 | return EFI_INVALID_PARAMETER;
|
---|
840 | }
|
---|
841 |
|
---|
842 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
843 | IpSb = IpInstance->Service;
|
---|
844 |
|
---|
845 | if (IpSb->LinkLocalDadFail) {
|
---|
846 | return EFI_DEVICE_ERROR;
|
---|
847 | }
|
---|
848 |
|
---|
849 | if (IpInstance->State != IP6_STATE_CONFIGED) {
|
---|
850 | return EFI_NOT_STARTED;
|
---|
851 | }
|
---|
852 |
|
---|
853 | if (DeleteRoute && (Destination == NULL) && (GatewayAddress == NULL)) {
|
---|
854 | return EFI_INVALID_PARAMETER;
|
---|
855 | }
|
---|
856 |
|
---|
857 | if (!DeleteRoute && ((Destination == NULL) || (GatewayAddress == NULL))) {
|
---|
858 | return EFI_INVALID_PARAMETER;
|
---|
859 | }
|
---|
860 |
|
---|
861 | if (GatewayAddress != NULL) {
|
---|
862 | if (!Ip6IsValidAddress (IpSb, GatewayAddress, FALSE)) {
|
---|
863 | return EFI_INVALID_PARAMETER;
|
---|
864 | }
|
---|
865 |
|
---|
866 | if (!NetIp6IsUnspecifiedAddr (GatewayAddress) &&
|
---|
867 | !NetIp6IsNetEqual (GatewayAddress, &IpInstance->ConfigData.StationAddress, PrefixLength)
|
---|
868 | )
|
---|
869 | {
|
---|
870 | return EFI_INVALID_PARAMETER;
|
---|
871 | }
|
---|
872 | }
|
---|
873 |
|
---|
874 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
875 |
|
---|
876 | //
|
---|
877 | // Update the route table
|
---|
878 | //
|
---|
879 | if (DeleteRoute) {
|
---|
880 | Status = Ip6DelRoute (IpSb->RouteTable, Destination, PrefixLength, GatewayAddress);
|
---|
881 | } else {
|
---|
882 | Status = Ip6AddRoute (IpSb->RouteTable, Destination, PrefixLength, GatewayAddress);
|
---|
883 | }
|
---|
884 |
|
---|
885 | gBS->RestoreTPL (OldTpl);
|
---|
886 | return Status;
|
---|
887 | }
|
---|
888 |
|
---|
889 | /**
|
---|
890 | Add or delete Neighbor cache entries.
|
---|
891 |
|
---|
892 | The Neighbors() function is used to add, update, or delete an entry from neighbor cache.
|
---|
893 | IPv6 neighbor cache entries are typically inserted and updated by the network protocol driver as
|
---|
894 | network traffic is processed. Most neighbor cache entries will timeout and be deleted if the network
|
---|
895 | traffic stops. Neighbor cache entries that were inserted by Neighbors() may be static (will not
|
---|
896 | timeout) or dynamic (will timeout).
|
---|
897 |
|
---|
898 | The implementation should follow the neighbor cache timeout mechanism which is defined in
|
---|
899 | RFC4861. The default neighbor cache timeout value should be tuned for the expected network
|
---|
900 | environment
|
---|
901 |
|
---|
902 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
903 | @param[in] DeleteFlag Set to TRUE to delete the specified cache entry, set to FALSE to
|
---|
904 | add (or update, if it already exists and Override is TRUE) the
|
---|
905 | specified cache entry. TargetIp6Address is used as the key
|
---|
906 | to find the requested cache entry.
|
---|
907 | @param[in] TargetIp6Address Pointer to the Target IPv6 address.
|
---|
908 | @param[in] TargetLinkAddress Pointer to the link-layer address of the target. Ignored if NULL.
|
---|
909 | @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
|
---|
910 | cache, it will be deleted after Timeout. A value of zero means that
|
---|
911 | the entry is permanent. A non-zero value means that the entry is
|
---|
912 | dynamic.
|
---|
913 | @param[in] Override If TRUE, the cached link-layer address of the matching entry will
|
---|
914 | be overridden and updated; if FALSE, EFI_ACCESS_DENIED
|
---|
915 | will be returned if a corresponding cache entry already existed.
|
---|
916 |
|
---|
917 | @retval EFI_SUCCESS The data has been queued for transmission.
|
---|
918 | @retval EFI_NOT_STARTED This instance has not been started.
|
---|
919 | @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
|
---|
920 | - This is NULL.
|
---|
921 | - TargetIpAddress is NULL.
|
---|
922 | - *TargetLinkAddress is invalid when not NULL.
|
---|
923 | - *TargetIpAddress is not a valid unicast IPv6 address.
|
---|
924 | - *TargetIpAddress is one of the local configured IPv6
|
---|
925 | addresses.
|
---|
926 | @retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache.
|
---|
927 | @retval EFI_NOT_FOUND This entry is not in the neighbor cache (when DeleteFlag is
|
---|
928 | TRUE or when DeleteFlag is FALSE while
|
---|
929 | TargetLinkAddress is NULL.).
|
---|
930 | @retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
|
---|
931 | and that entry is tagged as un-overridden (when Override
|
---|
932 | is FALSE).
|
---|
933 |
|
---|
934 | **/
|
---|
935 | EFI_STATUS
|
---|
936 | EFIAPI
|
---|
937 | EfiIp6Neighbors (
|
---|
938 | IN EFI_IP6_PROTOCOL *This,
|
---|
939 | IN BOOLEAN DeleteFlag,
|
---|
940 | IN EFI_IPv6_ADDRESS *TargetIp6Address,
|
---|
941 | IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
|
---|
942 | IN UINT32 Timeout,
|
---|
943 | IN BOOLEAN Override
|
---|
944 | )
|
---|
945 | {
|
---|
946 | EFI_TPL OldTpl;
|
---|
947 | EFI_STATUS Status;
|
---|
948 | IP6_PROTOCOL *IpInstance;
|
---|
949 | IP6_SERVICE *IpSb;
|
---|
950 |
|
---|
951 | if ((This == NULL) || (TargetIp6Address == NULL)) {
|
---|
952 | return EFI_INVALID_PARAMETER;
|
---|
953 | }
|
---|
954 |
|
---|
955 | if (NetIp6IsUnspecifiedAddr (TargetIp6Address)) {
|
---|
956 | return EFI_INVALID_PARAMETER;
|
---|
957 | }
|
---|
958 |
|
---|
959 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
960 | IpSb = IpInstance->Service;
|
---|
961 |
|
---|
962 | if (IpSb->LinkLocalDadFail) {
|
---|
963 | return EFI_DEVICE_ERROR;
|
---|
964 | }
|
---|
965 |
|
---|
966 | if (!Ip6IsValidAddress (IpSb, TargetIp6Address, FALSE)) {
|
---|
967 | return EFI_INVALID_PARAMETER;
|
---|
968 | }
|
---|
969 |
|
---|
970 | if (TargetLinkAddress != NULL) {
|
---|
971 | if (!Ip6IsValidLinkAddress (IpSb, TargetLinkAddress)) {
|
---|
972 | return EFI_INVALID_PARAMETER;
|
---|
973 | }
|
---|
974 | }
|
---|
975 |
|
---|
976 | if (Ip6IsOneOfSetAddress (IpSb, TargetIp6Address, NULL, NULL)) {
|
---|
977 | return EFI_INVALID_PARAMETER;
|
---|
978 | }
|
---|
979 |
|
---|
980 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
981 | if (IpInstance->State != IP6_STATE_CONFIGED) {
|
---|
982 | Status = EFI_NOT_STARTED;
|
---|
983 | goto Exit;
|
---|
984 | }
|
---|
985 |
|
---|
986 | if (DeleteFlag) {
|
---|
987 | Status = Ip6DelNeighbor (IpInstance->Service, TargetIp6Address, TargetLinkAddress, Timeout, Override);
|
---|
988 | } else {
|
---|
989 | Status = Ip6AddNeighbor (IpInstance->Service, TargetIp6Address, TargetLinkAddress, Timeout, Override);
|
---|
990 | }
|
---|
991 |
|
---|
992 | Exit:
|
---|
993 | gBS->RestoreTPL (OldTpl);
|
---|
994 | return Status;
|
---|
995 | }
|
---|
996 |
|
---|
997 | /**
|
---|
998 | Check whether the user's token or event has already
|
---|
999 | been enqueue on IP6's list.
|
---|
1000 |
|
---|
1001 | @param[in] Map The container of either user's transmit or receive
|
---|
1002 | token.
|
---|
1003 | @param[in] Item Current item to check against.
|
---|
1004 | @param[in] Context The Token to check against.
|
---|
1005 |
|
---|
1006 | @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
|
---|
1007 | @retval EFI_SUCCESS The current item isn't the same token/event as the
|
---|
1008 | context.
|
---|
1009 |
|
---|
1010 | **/
|
---|
1011 | EFI_STATUS
|
---|
1012 | EFIAPI
|
---|
1013 | Ip6TokenExist (
|
---|
1014 | IN NET_MAP *Map,
|
---|
1015 | IN NET_MAP_ITEM *Item,
|
---|
1016 | IN VOID *Context
|
---|
1017 | )
|
---|
1018 | {
|
---|
1019 | EFI_IP6_COMPLETION_TOKEN *Token;
|
---|
1020 | EFI_IP6_COMPLETION_TOKEN *TokenInItem;
|
---|
1021 |
|
---|
1022 | Token = (EFI_IP6_COMPLETION_TOKEN *)Context;
|
---|
1023 | TokenInItem = (EFI_IP6_COMPLETION_TOKEN *)Item->Key;
|
---|
1024 |
|
---|
1025 | if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
|
---|
1026 | return EFI_ACCESS_DENIED;
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | return EFI_SUCCESS;
|
---|
1030 | }
|
---|
1031 |
|
---|
1032 | /**
|
---|
1033 | Validate the user's token against the current station address.
|
---|
1034 |
|
---|
1035 | @param[in] Token User's token to validate.
|
---|
1036 |
|
---|
1037 | @retval EFI_INVALID_PARAMETER Some parameters are invalid.
|
---|
1038 | @retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.
|
---|
1039 | @retval EFI_SUCCESS The token is OK.
|
---|
1040 |
|
---|
1041 | **/
|
---|
1042 | EFI_STATUS
|
---|
1043 | Ip6TxTokenValid (
|
---|
1044 | IN EFI_IP6_COMPLETION_TOKEN *Token
|
---|
1045 | )
|
---|
1046 | {
|
---|
1047 | EFI_IP6_TRANSMIT_DATA *TxData;
|
---|
1048 | UINT32 Index;
|
---|
1049 | UINT32 DataLength;
|
---|
1050 |
|
---|
1051 | if ((Token == NULL) || (Token->Event == NULL)) {
|
---|
1052 | return EFI_INVALID_PARAMETER;
|
---|
1053 | }
|
---|
1054 |
|
---|
1055 | TxData = Token->Packet.TxData;
|
---|
1056 |
|
---|
1057 | if ((TxData == NULL) || ((TxData->ExtHdrsLength != 0) && (TxData->ExtHdrs == NULL))) {
|
---|
1058 | return EFI_INVALID_PARAMETER;
|
---|
1059 | }
|
---|
1060 |
|
---|
1061 | if ((TxData->FragmentCount == 0) || (TxData->DataLength == 0)) {
|
---|
1062 | return EFI_INVALID_PARAMETER;
|
---|
1063 | }
|
---|
1064 |
|
---|
1065 | for (DataLength = 0, Index = 0; Index < TxData->FragmentCount; Index++) {
|
---|
1066 | if ((TxData->FragmentTable[Index].FragmentLength == 0) || (TxData->FragmentTable[Index].FragmentBuffer == NULL)) {
|
---|
1067 | return EFI_INVALID_PARAMETER;
|
---|
1068 | }
|
---|
1069 |
|
---|
1070 | DataLength += TxData->FragmentTable[Index].FragmentLength;
|
---|
1071 | }
|
---|
1072 |
|
---|
1073 | if (TxData->DataLength != DataLength) {
|
---|
1074 | return EFI_INVALID_PARAMETER;
|
---|
1075 | }
|
---|
1076 |
|
---|
1077 | //
|
---|
1078 | // TODO: Token.Packet.TxData.DataLength is too short to transmit.
|
---|
1079 | // return EFI_BUFFER_TOO_SMALL;
|
---|
1080 | //
|
---|
1081 |
|
---|
1082 | //
|
---|
1083 | // If Token.Packet.TxData.DataLength is beyond the maximum that which can be
|
---|
1084 | // described through the Fragment Offset field in Fragment header when performing
|
---|
1085 | // fragmentation.
|
---|
1086 | //
|
---|
1087 | if (TxData->DataLength > 64 * 1024) {
|
---|
1088 | return EFI_BAD_BUFFER_SIZE;
|
---|
1089 | }
|
---|
1090 |
|
---|
1091 | return EFI_SUCCESS;
|
---|
1092 | }
|
---|
1093 |
|
---|
1094 | /**
|
---|
1095 | The callback function for the net buffer which wraps the user's
|
---|
1096 | transmit token. Although this function seems simple, there
|
---|
1097 | are some subtle aspects.
|
---|
1098 | When user requests the IP to transmit a packet by passing it a
|
---|
1099 | token, the token is wrapped in an IP6_TXTOKEN_WRAP and the data
|
---|
1100 | is wrapped in an net buffer. The net buffer's Free function is
|
---|
1101 | set to Ip6FreeTxToken. The Token and token wrap are added to the
|
---|
1102 | IP child's TxToken map. Then the buffer is passed to Ip6Output for
|
---|
1103 | transmission. If an error happened before that, the buffer
|
---|
1104 | is freed, which in turn frees the token wrap. The wrap may
|
---|
1105 | have been added to the TxToken map or not, and the user's event
|
---|
1106 | shouldn't be fired because we are still in the EfiIp6Transmit. If
|
---|
1107 | the buffer has been sent by Ip6Output, it should be removed from
|
---|
1108 | the TxToken map and user's event signaled. The token wrap and buffer
|
---|
1109 | are bound together. Check the comments in Ip6Output for information
|
---|
1110 | about IP fragmentation.
|
---|
1111 |
|
---|
1112 | @param[in] Context The token's wrap.
|
---|
1113 |
|
---|
1114 | **/
|
---|
1115 | VOID
|
---|
1116 | EFIAPI
|
---|
1117 | Ip6FreeTxToken (
|
---|
1118 | IN VOID *Context
|
---|
1119 | )
|
---|
1120 | {
|
---|
1121 | IP6_TXTOKEN_WRAP *Wrap;
|
---|
1122 | NET_MAP_ITEM *Item;
|
---|
1123 |
|
---|
1124 | Wrap = (IP6_TXTOKEN_WRAP *)Context;
|
---|
1125 |
|
---|
1126 | //
|
---|
1127 | // Signal IpSecRecycleEvent to inform IPsec free the memory
|
---|
1128 | //
|
---|
1129 | if (Wrap->IpSecRecycleSignal != NULL) {
|
---|
1130 | gBS->SignalEvent (Wrap->IpSecRecycleSignal);
|
---|
1131 | }
|
---|
1132 |
|
---|
1133 | //
|
---|
1134 | // Find the token in the instance's map. EfiIp6Transmit put the
|
---|
1135 | // token to the map. If that failed, NetMapFindKey will return NULL.
|
---|
1136 | //
|
---|
1137 | Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
|
---|
1138 |
|
---|
1139 | if (Item != NULL) {
|
---|
1140 | NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | if (Wrap->Sent) {
|
---|
1144 | gBS->SignalEvent (Wrap->Token->Event);
|
---|
1145 |
|
---|
1146 | //
|
---|
1147 | // Dispatch the DPC queued by the NotifyFunction of Token->Event.
|
---|
1148 | //
|
---|
1149 | DispatchDpc ();
|
---|
1150 | }
|
---|
1151 |
|
---|
1152 | FreePool (Wrap);
|
---|
1153 | }
|
---|
1154 |
|
---|
1155 | /**
|
---|
1156 | The callback function to Ip6Output to update the transmit status.
|
---|
1157 |
|
---|
1158 | @param[in] Packet The user's transmit packet.
|
---|
1159 | @param[in] IoStatus The result of the transmission.
|
---|
1160 | @param[in] Flag Not used during transmission.
|
---|
1161 | @param[in] Context The token's wrap.
|
---|
1162 |
|
---|
1163 | **/
|
---|
1164 | VOID
|
---|
1165 | Ip6OnPacketSent (
|
---|
1166 | IN NET_BUF *Packet,
|
---|
1167 | IN EFI_STATUS IoStatus,
|
---|
1168 | IN UINT32 Flag,
|
---|
1169 | IN VOID *Context
|
---|
1170 | )
|
---|
1171 | {
|
---|
1172 | IP6_TXTOKEN_WRAP *Wrap;
|
---|
1173 |
|
---|
1174 | //
|
---|
1175 | // This is the transmission request from upper layer,
|
---|
1176 | // not the IP6 driver itself.
|
---|
1177 | //
|
---|
1178 | Wrap = (IP6_TXTOKEN_WRAP *)Context;
|
---|
1179 | Wrap->Token->Status = IoStatus;
|
---|
1180 |
|
---|
1181 | NetbufFree (Wrap->Packet);
|
---|
1182 | }
|
---|
1183 |
|
---|
1184 | /**
|
---|
1185 | Places outgoing data packets into the transmit queue.
|
---|
1186 |
|
---|
1187 | The Transmit() function places a sending request in the transmit queue of this
|
---|
1188 | EFI IPv6 Protocol instance. Whenever the packet in the token is sent out or some
|
---|
1189 | errors occur, the event in the token will be signaled, and the status is updated.
|
---|
1190 |
|
---|
1191 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
1192 | @param[in] Token Pointer to the transmit token.
|
---|
1193 |
|
---|
1194 | @retval EFI_SUCCESS The data has been queued for transmission.
|
---|
1195 | @retval EFI_NOT_STARTED This instance has not been started.
|
---|
1196 | @retval EFI_NO_MAPPING The IPv6 driver was responsible for choosing
|
---|
1197 | a source address for this transmission,
|
---|
1198 | but no source address was available for use.
|
---|
1199 | @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
|
---|
1200 | - This is NULL.
|
---|
1201 | - Token is NULL.
|
---|
1202 | - Token.Event is NULL.
|
---|
1203 | - Token.Packet.TxData is NULL.
|
---|
1204 | - Token.Packet.ExtHdrsLength is not zero and
|
---|
1205 | Token.Packet.ExtHdrs is NULL.
|
---|
1206 | - Token.Packet.FragmentCount is zero.
|
---|
1207 | - One or more of the Token.Packet.TxData.
|
---|
1208 | FragmentTable[].FragmentLength fields is zero.
|
---|
1209 | - One or more of the Token.Packet.TxData.
|
---|
1210 | FragmentTable[].FragmentBuffer fields is NULL.
|
---|
1211 | - Token.Packet.TxData.DataLength is zero or not
|
---|
1212 | equal to the sum of fragment lengths.
|
---|
1213 | - Token.Packet.TxData.DestinationAddress is non
|
---|
1214 | zero when DestinationAddress is configured as
|
---|
1215 | non-zero when doing Configure() for this
|
---|
1216 | EFI IPv6 protocol instance.
|
---|
1217 | - Token.Packet.TxData.DestinationAddress is
|
---|
1218 | unspecified when DestinationAddress is unspecified
|
---|
1219 | when doing Configure() for this EFI IPv6 protocol
|
---|
1220 | instance.
|
---|
1221 | @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.
|
---|
1222 | Event was already in the transmit queue.
|
---|
1223 | @retval EFI_NOT_READY The completion token could not be queued because
|
---|
1224 | the transmit queue is full.
|
---|
1225 | @retval EFI_NOT_FOUND Not route is found to destination address.
|
---|
1226 | @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
|
---|
1227 | @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
|
---|
1228 | short to transmit.
|
---|
1229 | @retval EFI_BAD_BUFFER_SIZE If Token.Packet.TxData.DataLength is beyond the
|
---|
1230 | maximum that which can be described through the
|
---|
1231 | Fragment Offset field in Fragment header when
|
---|
1232 | performing fragmentation.
|
---|
1233 | @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
|
---|
1234 |
|
---|
1235 | **/
|
---|
1236 | EFI_STATUS
|
---|
1237 | EFIAPI
|
---|
1238 | EfiIp6Transmit (
|
---|
1239 | IN EFI_IP6_PROTOCOL *This,
|
---|
1240 | IN EFI_IP6_COMPLETION_TOKEN *Token
|
---|
1241 | )
|
---|
1242 | {
|
---|
1243 | IP6_SERVICE *IpSb;
|
---|
1244 | IP6_PROTOCOL *IpInstance;
|
---|
1245 | EFI_IP6_CONFIG_DATA *Config;
|
---|
1246 | EFI_STATUS Status;
|
---|
1247 | EFI_TPL OldTpl;
|
---|
1248 | EFI_IP6_HEADER Head;
|
---|
1249 | EFI_IP6_TRANSMIT_DATA *TxData;
|
---|
1250 | EFI_IP6_OVERRIDE_DATA *Override;
|
---|
1251 | IP6_TXTOKEN_WRAP *Wrap;
|
---|
1252 | UINT8 *ExtHdrs;
|
---|
1253 |
|
---|
1254 | //
|
---|
1255 | // Check input parameters.
|
---|
1256 | //
|
---|
1257 | if (This == NULL) {
|
---|
1258 | return EFI_INVALID_PARAMETER;
|
---|
1259 | }
|
---|
1260 |
|
---|
1261 | ExtHdrs = NULL;
|
---|
1262 |
|
---|
1263 | Status = Ip6TxTokenValid (Token);
|
---|
1264 | if (EFI_ERROR (Status)) {
|
---|
1265 | return Status;
|
---|
1266 | }
|
---|
1267 |
|
---|
1268 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
1269 | IpSb = IpInstance->Service;
|
---|
1270 |
|
---|
1271 | if (IpSb->LinkLocalDadFail) {
|
---|
1272 | return EFI_DEVICE_ERROR;
|
---|
1273 | }
|
---|
1274 |
|
---|
1275 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
1276 |
|
---|
1277 | if (IpInstance->State != IP6_STATE_CONFIGED) {
|
---|
1278 | Status = EFI_NOT_STARTED;
|
---|
1279 | goto Exit;
|
---|
1280 | }
|
---|
1281 |
|
---|
1282 | Config = &IpInstance->ConfigData;
|
---|
1283 |
|
---|
1284 | //
|
---|
1285 | // Check whether the token or signal already existed.
|
---|
1286 | //
|
---|
1287 | if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip6TokenExist, Token))) {
|
---|
1288 | Status = EFI_ACCESS_DENIED;
|
---|
1289 | goto Exit;
|
---|
1290 | }
|
---|
1291 |
|
---|
1292 | //
|
---|
1293 | // Build the IP header, fill in the information from ConfigData or OverrideData
|
---|
1294 | //
|
---|
1295 | ZeroMem (&Head, sizeof (EFI_IP6_HEADER));
|
---|
1296 | TxData = Token->Packet.TxData;
|
---|
1297 | IP6_COPY_ADDRESS (&Head.SourceAddress, &Config->StationAddress);
|
---|
1298 | IP6_COPY_ADDRESS (&Head.DestinationAddress, &Config->DestinationAddress);
|
---|
1299 |
|
---|
1300 | Status = EFI_INVALID_PARAMETER;
|
---|
1301 |
|
---|
1302 | if (NetIp6IsUnspecifiedAddr (&TxData->DestinationAddress)) {
|
---|
1303 | if (NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
|
---|
1304 | goto Exit;
|
---|
1305 | }
|
---|
1306 |
|
---|
1307 | ASSERT (!NetIp6IsUnspecifiedAddr (&Config->StationAddress));
|
---|
1308 | } else {
|
---|
1309 | //
|
---|
1310 | // StationAddress is unspecified only when ConfigData.Dest is unspecified.
|
---|
1311 | // Use TxData.Dest to override the DestinationAddress.
|
---|
1312 | //
|
---|
1313 | if (!NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
|
---|
1314 | goto Exit;
|
---|
1315 | }
|
---|
1316 |
|
---|
1317 | if (NetIp6IsUnspecifiedAddr (&Config->StationAddress)) {
|
---|
1318 | Status = Ip6SelectSourceAddress (
|
---|
1319 | IpSb,
|
---|
1320 | &TxData->DestinationAddress,
|
---|
1321 | &Head.SourceAddress
|
---|
1322 | );
|
---|
1323 | if (EFI_ERROR (Status)) {
|
---|
1324 | goto Exit;
|
---|
1325 | }
|
---|
1326 | }
|
---|
1327 |
|
---|
1328 | IP6_COPY_ADDRESS (&Head.DestinationAddress, &TxData->DestinationAddress);
|
---|
1329 | }
|
---|
1330 |
|
---|
1331 | //
|
---|
1332 | // Fill in Head infos.
|
---|
1333 | //
|
---|
1334 | Head.NextHeader = Config->DefaultProtocol;
|
---|
1335 | if (TxData->ExtHdrsLength != 0) {
|
---|
1336 | Head.NextHeader = TxData->NextHeader;
|
---|
1337 | }
|
---|
1338 |
|
---|
1339 | if (TxData->OverrideData != NULL) {
|
---|
1340 | Override = TxData->OverrideData;
|
---|
1341 | Head.NextHeader = Override->Protocol;
|
---|
1342 | Head.HopLimit = Override->HopLimit;
|
---|
1343 | Head.FlowLabelL = HTONS ((UINT16)Override->FlowLabel);
|
---|
1344 | Head.FlowLabelH = (UINT8)((Override->FlowLabel >> 16) & 0x0F);
|
---|
1345 | } else {
|
---|
1346 | Head.HopLimit = Config->HopLimit;
|
---|
1347 | Head.FlowLabelL = HTONS ((UINT16)Config->FlowLabel);
|
---|
1348 | Head.FlowLabelH = (UINT8)((Config->FlowLabel >> 16) & 0x0F);
|
---|
1349 | }
|
---|
1350 |
|
---|
1351 | Head.PayloadLength = HTONS ((UINT16)(TxData->ExtHdrsLength + TxData->DataLength));
|
---|
1352 |
|
---|
1353 | //
|
---|
1354 | // OK, it survives all the validation check. Wrap the token in
|
---|
1355 | // a IP6_TXTOKEN_WRAP and the data in a netbuf
|
---|
1356 | //
|
---|
1357 | Status = EFI_OUT_OF_RESOURCES;
|
---|
1358 | Wrap = AllocateZeroPool (sizeof (IP6_TXTOKEN_WRAP));
|
---|
1359 | if (Wrap == NULL) {
|
---|
1360 | goto Exit;
|
---|
1361 | }
|
---|
1362 |
|
---|
1363 | Wrap->IpInstance = IpInstance;
|
---|
1364 | Wrap->Token = Token;
|
---|
1365 | Wrap->Sent = FALSE;
|
---|
1366 | Wrap->Life = IP6_US_TO_SEC (Config->TransmitTimeout);
|
---|
1367 | Wrap->Packet = NetbufFromExt (
|
---|
1368 | (NET_FRAGMENT *)TxData->FragmentTable,
|
---|
1369 | TxData->FragmentCount,
|
---|
1370 | IP6_MAX_HEADLEN,
|
---|
1371 | 0,
|
---|
1372 | Ip6FreeTxToken,
|
---|
1373 | Wrap
|
---|
1374 | );
|
---|
1375 |
|
---|
1376 | if (Wrap->Packet == NULL) {
|
---|
1377 | FreePool (Wrap);
|
---|
1378 | goto Exit;
|
---|
1379 | }
|
---|
1380 |
|
---|
1381 | Token->Status = EFI_NOT_READY;
|
---|
1382 |
|
---|
1383 | Status = NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap);
|
---|
1384 | if (EFI_ERROR (Status)) {
|
---|
1385 | //
|
---|
1386 | // NetbufFree will call Ip6FreeTxToken, which in turn will
|
---|
1387 | // free the IP6_TXTOKEN_WRAP. Now, the token wrap hasn't been
|
---|
1388 | // enqueued.
|
---|
1389 | //
|
---|
1390 | NetbufFree (Wrap->Packet);
|
---|
1391 | goto Exit;
|
---|
1392 | }
|
---|
1393 |
|
---|
1394 | //
|
---|
1395 | // Allocate a new buffer to store IPv6 extension headers to avoid updating
|
---|
1396 | // the original data in EFI_IP6_COMPLETION_TOKEN.
|
---|
1397 | //
|
---|
1398 | if ((TxData->ExtHdrsLength != 0) && (TxData->ExtHdrs != NULL)) {
|
---|
1399 | ExtHdrs = (UINT8 *)AllocateCopyPool (TxData->ExtHdrsLength, TxData->ExtHdrs);
|
---|
1400 | if (ExtHdrs == NULL) {
|
---|
1401 | Status = EFI_OUT_OF_RESOURCES;
|
---|
1402 | goto Exit;
|
---|
1403 | }
|
---|
1404 | }
|
---|
1405 |
|
---|
1406 | //
|
---|
1407 | // Mark the packet sent before output it. Mark it not sent again if the
|
---|
1408 | // returned status is not EFI_SUCCESS;
|
---|
1409 | //
|
---|
1410 | Wrap->Sent = TRUE;
|
---|
1411 |
|
---|
1412 | Status = Ip6Output (
|
---|
1413 | IpSb,
|
---|
1414 | NULL,
|
---|
1415 | IpInstance,
|
---|
1416 | Wrap->Packet,
|
---|
1417 | &Head,
|
---|
1418 | ExtHdrs,
|
---|
1419 | TxData->ExtHdrsLength,
|
---|
1420 | Ip6OnPacketSent,
|
---|
1421 | Wrap
|
---|
1422 | );
|
---|
1423 | if (EFI_ERROR (Status)) {
|
---|
1424 | Wrap->Sent = FALSE;
|
---|
1425 | NetbufFree (Wrap->Packet);
|
---|
1426 | }
|
---|
1427 |
|
---|
1428 | Exit:
|
---|
1429 | gBS->RestoreTPL (OldTpl);
|
---|
1430 |
|
---|
1431 | if (ExtHdrs != NULL) {
|
---|
1432 | FreePool (ExtHdrs);
|
---|
1433 | }
|
---|
1434 |
|
---|
1435 | return Status;
|
---|
1436 | }
|
---|
1437 |
|
---|
1438 | /**
|
---|
1439 | Places a receiving request into the receiving queue.
|
---|
1440 |
|
---|
1441 | The Receive() function places a completion token into the receive packet queue.
|
---|
1442 | This function is always asynchronous.
|
---|
1443 |
|
---|
1444 | The Token.Event field in the completion token must be filled in by the caller
|
---|
1445 | and cannot be NULL. When the receive operation completes, the EFI IPv6 Protocol
|
---|
1446 | driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
|
---|
1447 | is signaled.
|
---|
1448 |
|
---|
1449 | Current Udp implementation creates an IP child for each Udp child.
|
---|
1450 | It initiates a asynchronous receive immediately no matter whether
|
---|
1451 | there is no mapping or not. Therefore, disable the returning EFI_NO_MAPPING for now.
|
---|
1452 | To enable it, the following check must be performed:
|
---|
1453 |
|
---|
1454 | if (NetIp6IsUnspecifiedAddr (&Config->StationAddress) && IP6_NO_MAPPING (IpInstance)) {
|
---|
1455 | Status = EFI_NO_MAPPING;
|
---|
1456 | goto Exit;
|
---|
1457 | }
|
---|
1458 |
|
---|
1459 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
1460 | @param[in] Token Pointer to a token that is associated with the receive data descriptor.
|
---|
1461 |
|
---|
1462 | @retval EFI_SUCCESS The receive completion token was cached.
|
---|
1463 | @retval EFI_NOT_STARTED This EFI IPv6 Protocol instance has not been started.
|
---|
1464 | @retval EFI_NO_MAPPING When IP6 driver responsible for binding source address to this instance,
|
---|
1465 | while no source address is available for use.
|
---|
1466 | @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
|
---|
1467 | - This is NULL.
|
---|
1468 | - Token is NULL.
|
---|
1469 | - Token.Event is NULL.
|
---|
1470 | @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
|
---|
1471 | resources (usually memory).
|
---|
1472 | @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
|
---|
1473 | The EFI IPv6 Protocol instance has been reset to startup defaults.
|
---|
1474 | @retval EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
|
---|
1475 | in the receive queue.
|
---|
1476 | @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
|
---|
1477 |
|
---|
1478 | **/
|
---|
1479 | EFI_STATUS
|
---|
1480 | EFIAPI
|
---|
1481 | EfiIp6Receive (
|
---|
1482 | IN EFI_IP6_PROTOCOL *This,
|
---|
1483 | IN EFI_IP6_COMPLETION_TOKEN *Token
|
---|
1484 | )
|
---|
1485 | {
|
---|
1486 | IP6_PROTOCOL *IpInstance;
|
---|
1487 | EFI_STATUS Status;
|
---|
1488 | EFI_TPL OldTpl;
|
---|
1489 | IP6_SERVICE *IpSb;
|
---|
1490 |
|
---|
1491 | if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
|
---|
1492 | return EFI_INVALID_PARAMETER;
|
---|
1493 | }
|
---|
1494 |
|
---|
1495 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
1496 | IpSb = IpInstance->Service;
|
---|
1497 |
|
---|
1498 | if (IpSb->LinkLocalDadFail) {
|
---|
1499 | return EFI_DEVICE_ERROR;
|
---|
1500 | }
|
---|
1501 |
|
---|
1502 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
1503 |
|
---|
1504 | if (IpInstance->State != IP6_STATE_CONFIGED) {
|
---|
1505 | Status = EFI_NOT_STARTED;
|
---|
1506 | goto Exit;
|
---|
1507 | }
|
---|
1508 |
|
---|
1509 | //
|
---|
1510 | // Check whether the toke is already on the receive queue.
|
---|
1511 | //
|
---|
1512 | Status = NetMapIterate (&IpInstance->RxTokens, Ip6TokenExist, Token);
|
---|
1513 |
|
---|
1514 | if (EFI_ERROR (Status)) {
|
---|
1515 | Status = EFI_ACCESS_DENIED;
|
---|
1516 | goto Exit;
|
---|
1517 | }
|
---|
1518 |
|
---|
1519 | //
|
---|
1520 | // Queue the token then check whether there is pending received packet.
|
---|
1521 | //
|
---|
1522 | Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
|
---|
1523 |
|
---|
1524 | if (EFI_ERROR (Status)) {
|
---|
1525 | goto Exit;
|
---|
1526 | }
|
---|
1527 |
|
---|
1528 | Status = Ip6InstanceDeliverPacket (IpInstance);
|
---|
1529 |
|
---|
1530 | //
|
---|
1531 | // Dispatch the DPC queued by the NotifyFunction of this instane's receive
|
---|
1532 | // event.
|
---|
1533 | //
|
---|
1534 | DispatchDpc ();
|
---|
1535 |
|
---|
1536 | Exit:
|
---|
1537 | gBS->RestoreTPL (OldTpl);
|
---|
1538 | return Status;
|
---|
1539 | }
|
---|
1540 |
|
---|
1541 | /**
|
---|
1542 | Cancel the transmitted but not recycled packet. If a matching
|
---|
1543 | token is found, it will call Ip6CancelPacket to cancel the
|
---|
1544 | packet. Ip6CancelPacket cancels all the fragments of the
|
---|
1545 | packet. When all the fragments are freed, the IP6_TXTOKEN_WRAP
|
---|
1546 | is deleted from the Map, and user's event is signalled.
|
---|
1547 | Because Ip6CancelPacket and other functions are all called in
|
---|
1548 | line, after Ip6CancelPacket returns, the Item has been freed.
|
---|
1549 |
|
---|
1550 | @param[in] Map The IP6 child's transmit queue.
|
---|
1551 | @param[in] Item The current transmitted packet to test.
|
---|
1552 | @param[in] Context The user's token to cancel.
|
---|
1553 |
|
---|
1554 | @retval EFI_SUCCESS Continue to check the next Item.
|
---|
1555 | @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.
|
---|
1556 |
|
---|
1557 | **/
|
---|
1558 | EFI_STATUS
|
---|
1559 | EFIAPI
|
---|
1560 | Ip6CancelTxTokens (
|
---|
1561 | IN NET_MAP *Map,
|
---|
1562 | IN NET_MAP_ITEM *Item,
|
---|
1563 | IN VOID *Context
|
---|
1564 | )
|
---|
1565 | {
|
---|
1566 | EFI_IP6_COMPLETION_TOKEN *Token;
|
---|
1567 | IP6_TXTOKEN_WRAP *Wrap;
|
---|
1568 |
|
---|
1569 | Token = (EFI_IP6_COMPLETION_TOKEN *)Context;
|
---|
1570 |
|
---|
1571 | //
|
---|
1572 | // Return EFI_SUCCESS to check the next item in the map if
|
---|
1573 | // this one doesn't match.
|
---|
1574 | //
|
---|
1575 | if ((Token != NULL) && (Token != Item->Key)) {
|
---|
1576 | return EFI_SUCCESS;
|
---|
1577 | }
|
---|
1578 |
|
---|
1579 | Wrap = (IP6_TXTOKEN_WRAP *)Item->Value;
|
---|
1580 | ASSERT (Wrap != NULL);
|
---|
1581 |
|
---|
1582 | //
|
---|
1583 | // Don't access the Item, Wrap and Token's members after this point.
|
---|
1584 | // Item and wrap has been freed. And we no longer own the Token.
|
---|
1585 | //
|
---|
1586 | Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
|
---|
1587 |
|
---|
1588 | //
|
---|
1589 | // If only one item is to be cancel, return EFI_ABORTED to stop
|
---|
1590 | // iterating the map any more.
|
---|
1591 | //
|
---|
1592 | if (Token != NULL) {
|
---|
1593 | return EFI_ABORTED;
|
---|
1594 | }
|
---|
1595 |
|
---|
1596 | return EFI_SUCCESS;
|
---|
1597 | }
|
---|
1598 |
|
---|
1599 | /**
|
---|
1600 | Cancel the receive request. This is simple, because
|
---|
1601 | it is only enqueued in our local receive map.
|
---|
1602 |
|
---|
1603 | @param[in] Map The IP6 child's receive queue.
|
---|
1604 | @param[in] Item Current receive request to cancel.
|
---|
1605 | @param[in] Context The user's token to cancel.
|
---|
1606 |
|
---|
1607 |
|
---|
1608 | @retval EFI_SUCCESS Continue to check the next receive request on the
|
---|
1609 | queue.
|
---|
1610 | @retval EFI_ABORTED The user's token (token != NULL) has been
|
---|
1611 | cancelled.
|
---|
1612 |
|
---|
1613 | **/
|
---|
1614 | EFI_STATUS
|
---|
1615 | EFIAPI
|
---|
1616 | Ip6CancelRxTokens (
|
---|
1617 | IN NET_MAP *Map,
|
---|
1618 | IN NET_MAP_ITEM *Item,
|
---|
1619 | IN VOID *Context
|
---|
1620 | )
|
---|
1621 | {
|
---|
1622 | EFI_IP6_COMPLETION_TOKEN *Token;
|
---|
1623 | EFI_IP6_COMPLETION_TOKEN *This;
|
---|
1624 |
|
---|
1625 | Token = (EFI_IP6_COMPLETION_TOKEN *)Context;
|
---|
1626 | This = Item->Key;
|
---|
1627 |
|
---|
1628 | if ((Token != NULL) && (Token != This)) {
|
---|
1629 | return EFI_SUCCESS;
|
---|
1630 | }
|
---|
1631 |
|
---|
1632 | NetMapRemoveItem (Map, Item, NULL);
|
---|
1633 |
|
---|
1634 | This->Status = EFI_ABORTED;
|
---|
1635 | This->Packet.RxData = NULL;
|
---|
1636 | gBS->SignalEvent (This->Event);
|
---|
1637 |
|
---|
1638 | if (Token != NULL) {
|
---|
1639 | return EFI_ABORTED;
|
---|
1640 | }
|
---|
1641 |
|
---|
1642 | return EFI_SUCCESS;
|
---|
1643 | }
|
---|
1644 |
|
---|
1645 | /**
|
---|
1646 | Cancel the user's receive/transmit request. It is the worker function of
|
---|
1647 | EfiIp6Cancel API.
|
---|
1648 |
|
---|
1649 | @param[in] IpInstance The IP6 child.
|
---|
1650 | @param[in] Token The token to cancel. If NULL, all token will be
|
---|
1651 | cancelled.
|
---|
1652 |
|
---|
1653 | @retval EFI_SUCCESS The token is cancelled.
|
---|
1654 | @retval EFI_NOT_FOUND The token isn't found on either the
|
---|
1655 | transmit/receive queue.
|
---|
1656 | @retval EFI_DEVICE_ERROR Not all tokens are cancelled when Token is NULL.
|
---|
1657 |
|
---|
1658 | **/
|
---|
1659 | EFI_STATUS
|
---|
1660 | Ip6Cancel (
|
---|
1661 | IN IP6_PROTOCOL *IpInstance,
|
---|
1662 | IN EFI_IP6_COMPLETION_TOKEN *Token OPTIONAL
|
---|
1663 | )
|
---|
1664 | {
|
---|
1665 | EFI_STATUS Status;
|
---|
1666 |
|
---|
1667 | //
|
---|
1668 | // First check the transmitted packet. Ip6CancelTxTokens returns
|
---|
1669 | // EFI_ABORTED to mean that the token has been cancelled when
|
---|
1670 | // token != NULL. So, return EFI_SUCCESS for this condition.
|
---|
1671 | //
|
---|
1672 | Status = NetMapIterate (&IpInstance->TxTokens, Ip6CancelTxTokens, Token);
|
---|
1673 | if (EFI_ERROR (Status)) {
|
---|
1674 | if ((Token != NULL) && (Status == EFI_ABORTED)) {
|
---|
1675 | return EFI_SUCCESS;
|
---|
1676 | }
|
---|
1677 |
|
---|
1678 | return Status;
|
---|
1679 | }
|
---|
1680 |
|
---|
1681 | //
|
---|
1682 | // Check the receive queue. Ip6CancelRxTokens also returns EFI_ABORT
|
---|
1683 | // for Token!=NULL and it is cancelled.
|
---|
1684 | //
|
---|
1685 | Status = NetMapIterate (&IpInstance->RxTokens, Ip6CancelRxTokens, Token);
|
---|
1686 | //
|
---|
1687 | // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
|
---|
1688 | // events.
|
---|
1689 | //
|
---|
1690 | DispatchDpc ();
|
---|
1691 | if (EFI_ERROR (Status)) {
|
---|
1692 | if ((Token != NULL) && (Status == EFI_ABORTED)) {
|
---|
1693 | return EFI_SUCCESS;
|
---|
1694 | }
|
---|
1695 |
|
---|
1696 | return Status;
|
---|
1697 | }
|
---|
1698 |
|
---|
1699 | //
|
---|
1700 | // OK, if the Token is found when Token != NULL, the NetMapIterate
|
---|
1701 | // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
|
---|
1702 | //
|
---|
1703 | if (Token != NULL) {
|
---|
1704 | return EFI_NOT_FOUND;
|
---|
1705 | }
|
---|
1706 |
|
---|
1707 | //
|
---|
1708 | // If Token == NULL, cancel all the tokens. return error if not
|
---|
1709 | // all of them are cancelled.
|
---|
1710 | //
|
---|
1711 | if (!NetMapIsEmpty (&IpInstance->TxTokens) || !NetMapIsEmpty (&IpInstance->RxTokens)) {
|
---|
1712 | return EFI_DEVICE_ERROR;
|
---|
1713 | }
|
---|
1714 |
|
---|
1715 | return EFI_SUCCESS;
|
---|
1716 | }
|
---|
1717 |
|
---|
1718 | /**
|
---|
1719 | Abort an asynchronous transmit or receive request.
|
---|
1720 |
|
---|
1721 | The Cancel() function is used to abort a pending transmit or receive request.
|
---|
1722 | If the token is in the transmit or receive request queues, after calling this
|
---|
1723 | function, Token->Status will be set to EFI_ABORTED, and then Token->Event will
|
---|
1724 | be signaled. If the token is not in one of the queues, which usually means the
|
---|
1725 | asynchronous operation has completed, this function will not signal the token,
|
---|
1726 | and EFI_NOT_FOUND is returned.
|
---|
1727 |
|
---|
1728 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
1729 | @param[in] Token Pointer to a token that has been issued by
|
---|
1730 | EFI_IP6_PROTOCOL.Transmit() or
|
---|
1731 | EFI_IP6_PROTOCOL.Receive(). If NULL, all pending
|
---|
1732 | tokens are aborted. Type EFI_IP6_COMPLETION_TOKEN is
|
---|
1733 | defined in EFI_IP6_PROTOCOL.Transmit().
|
---|
1734 |
|
---|
1735 | @retval EFI_SUCCESS The asynchronous I/O request was aborted and
|
---|
1736 | Token->Event was signaled. When Token is NULL, all
|
---|
1737 | pending requests were aborted, and their events were signaled.
|
---|
1738 | @retval EFI_INVALID_PARAMETER This is NULL.
|
---|
1739 | @retval EFI_NOT_STARTED This instance has not been started.
|
---|
1740 | @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
|
---|
1741 | not found in the transmit or receive queue. It has either completed
|
---|
1742 | or was not issued by Transmit() and Receive().
|
---|
1743 | @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
|
---|
1744 |
|
---|
1745 | **/
|
---|
1746 | EFI_STATUS
|
---|
1747 | EFIAPI
|
---|
1748 | EfiIp6Cancel (
|
---|
1749 | IN EFI_IP6_PROTOCOL *This,
|
---|
1750 | IN EFI_IP6_COMPLETION_TOKEN *Token OPTIONAL
|
---|
1751 | )
|
---|
1752 | {
|
---|
1753 | IP6_PROTOCOL *IpInstance;
|
---|
1754 | EFI_STATUS Status;
|
---|
1755 | EFI_TPL OldTpl;
|
---|
1756 |
|
---|
1757 | if (This == NULL) {
|
---|
1758 | return EFI_INVALID_PARAMETER;
|
---|
1759 | }
|
---|
1760 |
|
---|
1761 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
1762 |
|
---|
1763 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
---|
1764 |
|
---|
1765 | if (IpInstance->State != IP6_STATE_CONFIGED) {
|
---|
1766 | Status = EFI_NOT_STARTED;
|
---|
1767 | goto Exit;
|
---|
1768 | }
|
---|
1769 |
|
---|
1770 | Status = Ip6Cancel (IpInstance, Token);
|
---|
1771 |
|
---|
1772 | Exit:
|
---|
1773 | gBS->RestoreTPL (OldTpl);
|
---|
1774 | return Status;
|
---|
1775 | }
|
---|
1776 |
|
---|
1777 | /**
|
---|
1778 | Polls for incoming data packets, and processes outgoing data packets.
|
---|
1779 |
|
---|
1780 | The Poll() function polls for incoming data packets and processes outgoing data
|
---|
1781 | packets. Network drivers and applications can call the EFI_IP6_PROTOCOL.Poll()
|
---|
1782 | function to increase the rate that data packets are moved between the communications
|
---|
1783 | device and the transmit and receive queues.
|
---|
1784 |
|
---|
1785 | In some systems the periodic timer event may not poll the underlying communications
|
---|
1786 | device fast enough to transmit and/or receive all data packets without missing
|
---|
1787 | incoming packets or dropping outgoing packets. Drivers and applications that are
|
---|
1788 | experiencing packet loss should try calling the EFI_IP6_PROTOCOL.Poll() function
|
---|
1789 | more often.
|
---|
1790 |
|
---|
1791 | @param[in] This Pointer to the EFI_IP6_PROTOCOL instance.
|
---|
1792 |
|
---|
1793 | @retval EFI_SUCCESS Incoming or outgoing data was processed.
|
---|
1794 | @retval EFI_NOT_STARTED This EFI IPv6 Protocol instance has not been started.
|
---|
1795 | @retval EFI_INVALID_PARAMETER This is NULL.
|
---|
1796 | @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
|
---|
1797 | @retval EFI_NOT_READY No incoming or outgoing data was processed.
|
---|
1798 | @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
|
---|
1799 | Consider increasing the polling rate.
|
---|
1800 |
|
---|
1801 | **/
|
---|
1802 | EFI_STATUS
|
---|
1803 | EFIAPI
|
---|
1804 | EfiIp6Poll (
|
---|
1805 | IN EFI_IP6_PROTOCOL *This
|
---|
1806 | )
|
---|
1807 | {
|
---|
1808 | IP6_PROTOCOL *IpInstance;
|
---|
1809 | IP6_SERVICE *IpSb;
|
---|
1810 | EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
|
---|
1811 |
|
---|
1812 | if (This == NULL) {
|
---|
1813 | return EFI_INVALID_PARAMETER;
|
---|
1814 | }
|
---|
1815 |
|
---|
1816 | IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
|
---|
1817 | IpSb = IpInstance->Service;
|
---|
1818 |
|
---|
1819 | if (IpSb->LinkLocalDadFail) {
|
---|
1820 | return EFI_DEVICE_ERROR;
|
---|
1821 | }
|
---|
1822 |
|
---|
1823 | if (IpInstance->State == IP6_STATE_UNCONFIGED) {
|
---|
1824 | return EFI_NOT_STARTED;
|
---|
1825 | }
|
---|
1826 |
|
---|
1827 | Mnp = IpInstance->Service->Mnp;
|
---|
1828 |
|
---|
1829 | //
|
---|
1830 | // Don't lock the Poll function to enable the deliver of
|
---|
1831 | // the packet polled up.
|
---|
1832 | //
|
---|
1833 | return Mnp->Poll (Mnp);
|
---|
1834 | }
|
---|