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