]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
fa84a9b1ca7b09b7782419b9adf4cf465a19251e
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Impl.c
1 /** @file
2
3 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 **/
13
14 #include "Ip4Impl.h"
15
16 EFI_IPSEC2_PROTOCOL *mIpSec = NULL;
17
18 /**
19 Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
20
21 The GetModeData() function returns the current operational mode data for this
22 driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
23 function is used optionally to retrieve the operational mode data of underlying
24 networks or drivers.
25
26 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
27 @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure.
28 @param[out] MnpConfigData Pointer to the managed network configuration data structure.
29 @param[out] SnpModeData Pointer to the simple network mode data structure.
30
31 @retval EFI_SUCCESS The operation completed successfully.
32 @retval EFI_INVALID_PARAMETER This is NULL.
33 @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
34
35 **/
36 EFI_STATUS
37 EFIAPI
38 EfiIp4GetModeData (
39 IN CONST EFI_IP4_PROTOCOL *This,
40 OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
41 OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
42 OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
43 );
44
45 /**
46 Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
47
48 The Configure() function is used to set, change, or reset the operational
49 parameters and filter settings for this EFI IPv4 Protocol instance. Until these
50 parameters have been set, no network traffic can be sent or received by this
51 instance. Once the parameters have been reset (by calling this function with
52 IpConfigData set to NULL), no more traffic can be sent or received until these
53 parameters have been set again. Each EFI IPv4 Protocol instance can be started
54 and stopped independently of each other by enabling or disabling their receive
55 filter settings with the Configure() function.
56
57 When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
58 be appended as an alias address into the addresses list in the EFI IPv4 Protocol
59 driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
60 to retrieve the default IPv4 address if it is not available yet. Clients could
61 frequently call GetModeData() to check the status to ensure that the default IPv4
62 address is ready.
63
64 If operational parameters are reset or changed, any pending transmit and receive
65 requests will be cancelled. Their completion token status will be set to EFI_ABORTED
66 and their events will be signaled.
67
68 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
69 @param[in] IpConfigData Pointer to the EFI IPv4 Protocol configuration data structure.
70
71 @retval EFI_SUCCESS The driver instance was successfully opened.
72 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
73 RARP, etc.) is not finished yet.
74 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
75 @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE:
76 A configuration protocol (DHCP, BOOTP, RARP, etc.) could
77 not be located when clients choose to use the default IPv4
78 address. This EFI IPv4 Protocol implementation does not
79 support this requested filter or timeout setting.
80 @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated.
81 @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the
82 IPv4 address or subnet mask can be changed. The interface must
83 also be stopped when switching to/from raw packet mode.
84 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4
85 Protocol driver instance is not opened.
86
87 **/
88 EFI_STATUS
89 EFIAPI
90 EfiIp4Configure (
91 IN EFI_IP4_PROTOCOL *This,
92 IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
93 );
94
95 /**
96 Joins and leaves multicast groups.
97
98 The Groups() function is used to join and leave multicast group sessions. Joining
99 a group will enable reception of matching multicast packets. Leaving a group will
100 disable the multicast packet reception.
101
102 If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
103
104 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
105 @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
106 @param[in] GroupAddress Pointer to the IPv4 multicast address.
107
108 @retval EFI_SUCCESS The operation completed successfully.
109 @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
110 - This is NULL.
111 - JoinFlag is TRUE and GroupAddress is NULL.
112 - GroupAddress is not NULL and *GroupAddress is
113 not a multicast IPv4 address.
114 @retval EFI_NOT_STARTED This instance has not been started.
115 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
116 RARP, etc.) is not finished yet.
117 @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
118 @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups.
119 @retval EFI_ALREADY_STARTED The group address is already in the group table (when
120 JoinFlag is TRUE).
121 @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
122 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
123
124 **/
125 EFI_STATUS
126 EFIAPI
127 EfiIp4Groups (
128 IN EFI_IP4_PROTOCOL *This,
129 IN BOOLEAN JoinFlag,
130 IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
131 );
132
133 /**
134 Adds and deletes routing table entries.
135
136 The Routes() function adds a route to or deletes a route from the routing table.
137
138 Routes are determined by comparing the SubnetAddress with the destination IPv4
139 address arithmetically AND-ed with the SubnetMask. The gateway address must be
140 on the same subnet as the configured station address.
141
142 The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
143 The default route matches all destination IPv4 addresses that do not match any
144 other routes.
145
146 A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
147 IP address if it can be found in the ARP cache or on the local subnet. One automatic
148 nonroute entry will be inserted into the routing table for outgoing packets that
149 are addressed to a local subnet (gateway address of 0.0.0.0).
150
151 Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
152 IPv4 Protocol instances that use the default IPv4 address will also have copies
153 of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
154 copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
155 instances. As a result, client modification to the routing table will be lost.
156
157 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
158 @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
159 FALSE to add this route to the routing table. SubnetAddress
160 and SubnetMask are used as the key to each route entry.
161 @param[in] SubnetAddress The address of the subnet that needs to be routed.
162 @param[in] SubnetMask The subnet mask of SubnetAddress.
163 @param[in] GatewayAddress The unicast gateway IPv4 address for this route.
164
165 @retval EFI_SUCCESS The operation completed successfully.
166 @retval EFI_NOT_STARTED The driver instance has not been started.
167 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
168 RARP, etc.) is not finished yet.
169 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
170 - This is NULL.
171 - SubnetAddress is NULL.
172 - SubnetMask is NULL.
173 - GatewayAddress is NULL.
174 - *SubnetAddress is not a valid subnet address.
175 - *SubnetMask is not a valid subnet mask.
176 - *GatewayAddress is not a valid unicast IPv4 address.
177 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
178 @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
179 @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
180 DeleteRoute is FALSE).
181
182 **/
183 EFI_STATUS
184 EFIAPI
185 EfiIp4Routes (
186 IN EFI_IP4_PROTOCOL *This,
187 IN BOOLEAN DeleteRoute,
188 IN EFI_IPv4_ADDRESS *SubnetAddress,
189 IN EFI_IPv4_ADDRESS *SubnetMask,
190 IN EFI_IPv4_ADDRESS *GatewayAddress
191 );
192
193 /**
194 Places outgoing data packets into the transmit queue.
195
196 The Transmit() function places a sending request in the transmit queue of this
197 EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
198 errors occur, the event in the token will be signaled and the status is updated.
199
200 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
201 @param[in] Token Pointer to the transmit token.
202
203 @retval EFI_SUCCESS The data has been queued for transmission.
204 @retval EFI_NOT_STARTED This instance has not been started.
205 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
206 RARP, etc.) is not finished yet.
207 @retval EFI_INVALID_PARAMETER One or more pameters are invalid.
208 @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event
209 was already in the transmit queue.
210 @retval EFI_NOT_READY The completion token could not be queued because the transmit
211 queue is full.
212 @retval EFI_NOT_FOUND Not route is found to destination address.
213 @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
214 @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
215 short to transmit.
216 @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is
217 greater than MTU (or greater than the maximum packet size if
218 Token.Packet.TxData.OverrideData.
219 DoNotFragment is TRUE.)
220
221 **/
222 EFI_STATUS
223 EFIAPI
224 EfiIp4Transmit (
225 IN EFI_IP4_PROTOCOL *This,
226 IN EFI_IP4_COMPLETION_TOKEN *Token
227 );
228
229 /**
230 Places a receiving request into the receiving queue.
231
232 The Receive() function places a completion token into the receive packet queue.
233 This function is always asynchronous.
234
235 The Token.Event field in the completion token must be filled in by the caller
236 and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
237 driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
238 is signaled.
239
240 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
241 @param[in] Token Pointer to a token that is associated with the receive data descriptor.
242
243 @retval EFI_SUCCESS The receive completion token was cached.
244 @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
245 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
246 is not finished yet.
247 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
248 - This is NULL.
249 - Token is NULL.
250 - Token.Event is NULL.
251 @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
252 resources (usually memory).
253 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
254 The EFI IPv4 Protocol instance has been reset to startup defaults.
255 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
256 in the receive queue.
257 @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
258 @retval EFI_ICMP_ERROR An ICMP error packet was received.
259
260 **/
261 EFI_STATUS
262 EFIAPI
263 EfiIp4Receive (
264 IN EFI_IP4_PROTOCOL *This,
265 IN EFI_IP4_COMPLETION_TOKEN *Token
266 );
267
268 /**
269 Abort an asynchronous transmit or receive request.
270
271 The Cancel() function is used to abort a pending transmit or receive request.
272 If the token is in the transmit or receive request queues, after calling this
273 function, Token->Status will be set to EFI_ABORTED and then Token->Event will
274 be signaled. If the token is not in one of the queues, which usually means the
275 asynchronous operation has completed, this function will not signal the token
276 and EFI_NOT_FOUND is returned.
277
278 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
279 @param[in] Token Pointer to a token that has been issued by
280 EFI_IP4_PROTOCOL.Transmit() or
281 EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
282 tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
283 defined in EFI_IP4_PROTOCOL.Transmit().
284
285 @retval EFI_SUCCESS The asynchronous I/O request was aborted and
286 Token.->Event was signaled. When Token is NULL, all
287 pending requests were aborted and their events were signaled.
288 @retval EFI_INVALID_PARAMETER This is NULL.
289 @retval EFI_NOT_STARTED This instance has not been started.
290 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
291 RARP, etc.) is not finished yet.
292 @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
293 not found in the transmit or receive queue. It has either completed
294 or was not issued by Transmit() and Receive().
295
296 **/
297 EFI_STATUS
298 EFIAPI
299 EfiIp4Cancel (
300 IN EFI_IP4_PROTOCOL *This,
301 IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
302 );
303
304 /**
305 Polls for incoming data packets and processes outgoing data packets.
306
307 The Poll() function polls for incoming data packets and processes outgoing data
308 packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
309 function to increase the rate that data packets are moved between the communications
310 device and the transmit and receive queues.
311
312 In some systems the periodic timer event may not poll the underlying communications
313 device fast enough to transmit and/or receive all data packets without missing
314 incoming packets or dropping outgoing packets. Drivers and applications that are
315 experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
316 more often.
317
318 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
319
320 @retval EFI_SUCCESS Incoming or outgoing data was processed.
321 @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
322 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
323 RARP, etc.) is not finished yet.
324 @retval EFI_INVALID_PARAMETER This is NULL.
325 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
326 @retval EFI_NOT_READY No incoming or outgoing data is processed.
327 @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
328 Consider increasing the polling rate.
329
330 **/
331 EFI_STATUS
332 EFIAPI
333 EfiIp4Poll (
334 IN EFI_IP4_PROTOCOL *This
335 );
336
337 EFI_IP4_PROTOCOL
338 mEfiIp4ProtocolTemplete = {
339 EfiIp4GetModeData,
340 EfiIp4Configure,
341 EfiIp4Groups,
342 EfiIp4Routes,
343 EfiIp4Transmit,
344 EfiIp4Receive,
345 EfiIp4Cancel,
346 EfiIp4Poll
347 };
348
349 /**
350 Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
351
352 The GetModeData() function returns the current operational mode data for this
353 driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
354 function is used optionally to retrieve the operational mode data of underlying
355 networks or drivers.
356
357 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
358 @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure.
359 @param[out] MnpConfigData Pointer to the managed network configuration data structure.
360 @param[out] SnpModeData Pointer to the simple network mode data structure.
361
362 @retval EFI_SUCCESS The operation completed successfully.
363 @retval EFI_INVALID_PARAMETER This is NULL.
364 @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
365
366 **/
367 EFI_STATUS
368 EFIAPI
369 EfiIp4GetModeData (
370 IN CONST EFI_IP4_PROTOCOL *This,
371 OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
372 OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
373 OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
374 )
375 {
376 IP4_PROTOCOL *IpInstance;
377 IP4_SERVICE *IpSb;
378 EFI_IP4_CONFIG_DATA *Config;
379 EFI_STATUS Status;
380 EFI_TPL OldTpl;
381 IP4_ADDR Ip;
382
383 if (This == NULL) {
384 return EFI_INVALID_PARAMETER;
385 }
386
387 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
388 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
389 IpSb = IpInstance->Service;
390
391 if (Ip4ModeData != NULL) {
392 //
393 // IsStarted is "whether the EfiIp4Configure has been called".
394 // IsConfigured is "whether the station address has been configured"
395 //
396 Ip4ModeData->IsStarted = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);
397 CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));
398 Ip4ModeData->IsConfigured = FALSE;
399
400 Ip4ModeData->GroupCount = IpInstance->GroupCount;
401 Ip4ModeData->GroupTable = (EFI_IPv4_ADDRESS *) IpInstance->Groups;
402
403 Ip4ModeData->IcmpTypeCount = 23;
404 Ip4ModeData->IcmpTypeList = mIp4SupportedIcmp;
405
406 Ip4ModeData->RouteTable = NULL;
407 Ip4ModeData->RouteCount = 0;
408
409 Ip4ModeData->MaxPacketSize = IpSb->MaxPacketSize;
410
411 //
412 // return the current station address for this IP child. So,
413 // the user can get the default address through this. Some
414 // application wants to know it station address even it is
415 // using the default one, such as a ftp server.
416 //
417 if (Ip4ModeData->IsStarted) {
418 Config = &Ip4ModeData->ConfigData;
419
420 Ip = HTONL (IpInstance->Interface->Ip);
421 CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
422
423 Ip = HTONL (IpInstance->Interface->SubnetMask);
424 CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
425
426 Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;
427
428 //
429 // Build a EFI route table for user from the internal route table.
430 //
431 Status = Ip4BuildEfiRouteTable (IpInstance);
432
433 if (EFI_ERROR (Status)) {
434 gBS->RestoreTPL (OldTpl);
435 return Status;
436 }
437
438 Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;
439 Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;
440 }
441 }
442
443 //
444 // Get fresh mode data from MNP, since underlying media status may change
445 //
446 Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);
447
448 gBS->RestoreTPL (OldTpl);
449 return Status;
450 }
451
452
453 /**
454 Config the MNP parameter used by IP. The IP driver use one MNP
455 child to transmit/receive frames. By default, it configures MNP
456 to receive unicast/multicast/broadcast. And it will enable/disable
457 the promiscous receive according to whether there is IP child
458 enable that or not. If Force is FALSE, it will iterate through
459 all the IP children to check whether the promiscuous receive
460 setting has been changed. If it hasn't been changed, it won't
461 reconfigure the MNP. If Force is TRUE, the MNP is configured no
462 matter whether that is changed or not.
463
464 @param[in] IpSb The IP4 service instance that is to be changed.
465 @param[in] Force Force the configuration or not.
466
467 @retval EFI_SUCCESS The MNP is successfully configured/reconfigured.
468 @retval Others Configuration failed.
469
470 **/
471 EFI_STATUS
472 Ip4ServiceConfigMnp (
473 IN IP4_SERVICE *IpSb,
474 IN BOOLEAN Force
475 )
476 {
477 LIST_ENTRY *Entry;
478 LIST_ENTRY *ProtoEntry;
479 IP4_INTERFACE *IpIf;
480 IP4_PROTOCOL *IpInstance;
481 BOOLEAN Reconfig;
482 BOOLEAN PromiscReceive;
483 EFI_STATUS Status;
484
485 Reconfig = FALSE;
486 PromiscReceive = FALSE;
487
488 if (!Force) {
489 //
490 // Iterate through the IP children to check whether promiscuous
491 // receive setting has been changed. Update the interface's receive
492 // filter also.
493 //
494 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
495
496 IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
497 IpIf->PromiscRecv = FALSE;
498
499 NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
500 IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);
501
502 if (IpInstance->ConfigData.AcceptPromiscuous) {
503 IpIf->PromiscRecv = TRUE;
504 PromiscReceive = TRUE;
505 }
506 }
507 }
508
509 //
510 // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
511 //
512 if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
513 return EFI_SUCCESS;
514 }
515
516 Reconfig = TRUE;
517 IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
518 }
519
520 Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
521
522 //
523 // recover the original configuration if failed to set the configure.
524 //
525 if (EFI_ERROR (Status) && Reconfig) {
526 IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
527 }
528
529 return Status;
530 }
531
532
533 /**
534 Intiialize the IP4_PROTOCOL structure to the unconfigured states.
535
536 @param IpSb The IP4 service instance.
537 @param IpInstance The IP4 child instance.
538
539 **/
540 VOID
541 Ip4InitProtocol (
542 IN IP4_SERVICE *IpSb,
543 IN OUT IP4_PROTOCOL *IpInstance
544 )
545 {
546 ASSERT ((IpSb != NULL) && (IpInstance != NULL));
547
548 ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));
549
550 IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;
551 CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));
552 IpInstance->State = IP4_STATE_UNCONFIGED;
553 IpInstance->InDestroy = FALSE;
554 IpInstance->Service = IpSb;
555
556 InitializeListHead (&IpInstance->Link);
557 NetMapInit (&IpInstance->RxTokens);
558 NetMapInit (&IpInstance->TxTokens);
559 InitializeListHead (&IpInstance->Received);
560 InitializeListHead (&IpInstance->Delivered);
561 InitializeListHead (&IpInstance->AddrLink);
562
563 EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
564 }
565
566
567 /**
568 Configure the IP4 child. If the child is already configured,
569 change the configuration parameter. Otherwise configure it
570 for the first time. The caller should validate the configuration
571 before deliver them to it. It also don't do configure NULL.
572
573 @param[in, out] IpInstance The IP4 child to configure.
574 @param[in] Config The configure data.
575
576 @retval EFI_SUCCESS The IP4 child is successfully configured.
577 @retval EFI_DEVICE_ERROR Failed to free the pending transive or to
578 configure underlying MNP or other errors.
579 @retval EFI_NO_MAPPING The IP4 child is configured to use default
580 address, but the default address hasn't been
581 configured. The IP4 child doesn't need to be
582 reconfigured when default address is configured.
583 @retval EFI_OUT_OF_RESOURCES No more memory space is available.
584 @retval other Other error occurs.
585
586 **/
587 EFI_STATUS
588 Ip4ConfigProtocol (
589 IN OUT IP4_PROTOCOL *IpInstance,
590 IN EFI_IP4_CONFIG_DATA *Config
591 )
592 {
593 IP4_SERVICE *IpSb;
594 IP4_INTERFACE *IpIf;
595 EFI_STATUS Status;
596 IP4_ADDR Ip;
597 IP4_ADDR Netmask;
598 EFI_ARP_PROTOCOL *Arp;
599 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
600 EFI_IP4_CONFIG2_POLICY Policy;
601
602 IpSb = IpInstance->Service;
603
604 Ip4Config2 = NULL;
605
606 //
607 // User is changing packet filters. It must be stopped
608 // before the station address can be changed.
609 //
610 if (IpInstance->State == IP4_STATE_CONFIGED) {
611 //
612 // Cancel all the pending transmit/receive from upper layer
613 //
614 Status = Ip4Cancel (IpInstance, NULL);
615
616 if (EFI_ERROR (Status)) {
617 return EFI_DEVICE_ERROR;
618 }
619
620 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
621 return EFI_SUCCESS;
622 }
623
624 //
625 // Configure a fresh IP4 protocol instance. Create a route table.
626 // Each IP child has its own route table, which may point to the
627 // default table if it is using default address.
628 //
629 Status = EFI_OUT_OF_RESOURCES;
630 IpInstance->RouteTable = Ip4CreateRouteTable ();
631
632 if (IpInstance->RouteTable == NULL) {
633 return Status;
634 }
635
636 //
637 // Set up the interface.
638 //
639 CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
640 CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
641
642 Ip = NTOHL (Ip);
643 Netmask = NTOHL (Netmask);
644
645 if (!Config->UseDefaultAddress) {
646 //
647 // Find whether there is already an interface with the same
648 // station address. All the instances with the same station
649 // address shares one interface.
650 //
651 IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
652
653 if (IpIf != NULL) {
654 NET_GET_REF (IpIf);
655
656 } else {
657 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
658
659 if (IpIf == NULL) {
660 goto ON_ERROR;
661 }
662
663 Status = Ip4SetAddress (IpIf, Ip, Netmask);
664
665 if (EFI_ERROR (Status)) {
666 Status = EFI_DEVICE_ERROR;
667 Ip4FreeInterface (IpIf, IpInstance);
668 goto ON_ERROR;
669 }
670
671 InsertTailList (&IpSb->Interfaces, &IpIf->Link);
672 }
673
674 //
675 // Add a route to this connected network in the route table
676 //
677 Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
678
679 } else {
680 //
681 // Use the default address. Check the state.
682 //
683 if (IpSb->State == IP4_SERVICE_UNSTARTED) {
684 //
685 // Trigger the EFI_IP4_CONFIG2_PROTOCOL to retrieve the
686 // default IPv4 address if it is not available yet.
687 //
688 Policy = IpSb->Ip4Config2Instance.Policy;
689 if (Policy != Ip4Config2PolicyDhcp) {
690 Ip4Config2 = &IpSb->Ip4Config2Instance.Ip4Config2;
691 Policy = Ip4Config2PolicyDhcp;
692 Status= Ip4Config2->SetData (
693 Ip4Config2,
694 Ip4Config2DataTypePolicy,
695 sizeof (EFI_IP4_CONFIG2_POLICY),
696 &Policy
697 );
698 if (EFI_ERROR (Status)) {
699 goto ON_ERROR;
700 }
701 }
702 }
703
704 IpIf = IpSb->DefaultInterface;
705 NET_GET_REF (IpSb->DefaultInterface);
706
707 //
708 // If default address is used, so is the default route table.
709 // Any route set by the instance has the precedence over the
710 // routes in the default route table. Link the default table
711 // after the instance's table. Routing will search the local
712 // table first.
713 //
714 NET_GET_REF (IpSb->DefaultRouteTable);
715 IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
716 }
717
718 IpInstance->Interface = IpIf;
719 if (IpIf->Arp != NULL) {
720 Arp = NULL;
721 Status = gBS->OpenProtocol (
722 IpIf->ArpHandle,
723 &gEfiArpProtocolGuid,
724 (VOID **) &Arp,
725 gIp4DriverBinding.DriverBindingHandle,
726 IpInstance->Handle,
727 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
728 );
729 if (EFI_ERROR (Status)) {
730 Ip4FreeInterface (IpIf, IpInstance);
731 goto ON_ERROR;
732 }
733 }
734 InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
735
736 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
737 IpInstance->State = IP4_STATE_CONFIGED;
738
739 //
740 // Although EFI_NO_MAPPING is an error code, the IP child has been
741 // successfully configured and doesn't need reconfiguration when
742 // default address is acquired.
743 //
744 if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
745 return EFI_NO_MAPPING;
746 }
747
748 return EFI_SUCCESS;
749
750 ON_ERROR:
751 Ip4FreeRouteTable (IpInstance->RouteTable);
752 IpInstance->RouteTable = NULL;
753 return Status;
754 }
755
756
757 /**
758 Clean up the IP4 child, release all the resources used by it.
759
760 @param[in] IpInstance The IP4 child to clean up.
761
762 @retval EFI_SUCCESS The IP4 child is cleaned up.
763 @retval EFI_DEVICE_ERROR Some resources failed to be released.
764
765 **/
766 EFI_STATUS
767 Ip4CleanProtocol (
768 IN IP4_PROTOCOL *IpInstance
769 )
770 {
771 if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
772 return EFI_DEVICE_ERROR;
773 }
774
775 if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
776 return EFI_DEVICE_ERROR;
777 }
778
779 //
780 // Some packets haven't been recycled. It is because either the
781 // user forgets to recycle the packets, or because the callback
782 // hasn't been called. Just leave it alone.
783 //
784 if (!IsListEmpty (&IpInstance->Delivered)) {
785 ;
786 }
787
788 if (IpInstance->Interface != NULL) {
789 RemoveEntryList (&IpInstance->AddrLink);
790 if (IpInstance->Interface->Arp != NULL) {
791 gBS->CloseProtocol (
792 IpInstance->Interface->ArpHandle,
793 &gEfiArpProtocolGuid,
794 gIp4DriverBinding.DriverBindingHandle,
795 IpInstance->Handle
796 );
797 }
798 Ip4FreeInterface (IpInstance->Interface, IpInstance);
799 IpInstance->Interface = NULL;
800 }
801
802 if (IpInstance->RouteTable != NULL) {
803 if (IpInstance->RouteTable->Next != NULL) {
804 Ip4FreeRouteTable (IpInstance->RouteTable->Next);
805 }
806
807 Ip4FreeRouteTable (IpInstance->RouteTable);
808 IpInstance->RouteTable = NULL;
809 }
810
811 if (IpInstance->EfiRouteTable != NULL) {
812 FreePool (IpInstance->EfiRouteTable);
813 IpInstance->EfiRouteTable = NULL;
814 IpInstance->EfiRouteCount = 0;
815 }
816
817 if (IpInstance->Groups != NULL) {
818 FreePool (IpInstance->Groups);
819 IpInstance->Groups = NULL;
820 IpInstance->GroupCount = 0;
821 }
822
823 NetMapClean (&IpInstance->TxTokens);
824
825 NetMapClean (&IpInstance->RxTokens);
826
827 return EFI_SUCCESS;
828 }
829
830
831 /**
832 Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
833
834 The Configure() function is used to set, change, or reset the operational
835 parameters and filter settings for this EFI IPv4 Protocol instance. Until these
836 parameters have been set, no network traffic can be sent or received by this
837 instance. Once the parameters have been reset (by calling this function with
838 IpConfigData set to NULL), no more traffic can be sent or received until these
839 parameters have been set again. Each EFI IPv4 Protocol instance can be started
840 and stopped independently of each other by enabling or disabling their receive
841 filter settings with the Configure() function.
842
843 When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
844 be appended as an alias address into the addresses list in the EFI IPv4 Protocol
845 driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
846 to retrieve the default IPv4 address if it is not available yet. Clients could
847 frequently call GetModeData() to check the status to ensure that the default IPv4
848 address is ready.
849
850 If operational parameters are reset or changed, any pending transmit and receive
851 requests will be cancelled. Their completion token status will be set to EFI_ABORTED
852 and their events will be signaled.
853
854 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
855 @param[in] IpConfigData Pointer to the EFI IPv4 Protocol configuration data structure.
856
857 @retval EFI_SUCCESS The driver instance was successfully opened.
858 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
859 RARP, etc.) is not finished yet.
860 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
861 @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE:
862 A configuration protocol (DHCP, BOOTP, RARP, etc.) could
863 not be located when clients choose to use the default IPv4
864 address. This EFI IPv4 Protocol implementation does not
865 support this requested filter or timeout setting.
866 @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated.
867 @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the
868 IPv4 address or subnet mask can be changed. The interface must
869 also be stopped when switching to/from raw packet mode.
870 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4
871 Protocol driver instance is not opened.
872
873 **/
874 EFI_STATUS
875 EFIAPI
876 EfiIp4Configure (
877 IN EFI_IP4_PROTOCOL *This,
878 IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
879 )
880 {
881 IP4_PROTOCOL *IpInstance;
882 EFI_IP4_CONFIG_DATA *Current;
883 EFI_TPL OldTpl;
884 EFI_STATUS Status;
885 BOOLEAN AddrOk;
886 IP4_ADDR IpAddress;
887 IP4_ADDR SubnetMask;
888
889 //
890 // First, validate the parameters
891 //
892 if (This == NULL) {
893 return EFI_INVALID_PARAMETER;
894 }
895
896 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
897 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
898
899 //
900 // Validate the configuration first.
901 //
902 if (IpConfigData != NULL) {
903
904 CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
905 CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
906
907 IpAddress = NTOHL (IpAddress);
908 SubnetMask = NTOHL (SubnetMask);
909
910 //
911 // Check whether the station address is a valid unicast address
912 //
913 if (!IpConfigData->UseDefaultAddress) {
914 AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
915
916 if (!AddrOk) {
917 Status = EFI_INVALID_PARAMETER;
918 goto ON_EXIT;
919 }
920 }
921
922 //
923 // User can only update packet filters when already configured.
924 // If it wants to change the station address, it must configure(NULL)
925 // the instance first.
926 //
927 if (IpInstance->State == IP4_STATE_CONFIGED) {
928 Current = &IpInstance->ConfigData;
929
930 if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
931 Status = EFI_ALREADY_STARTED;
932 goto ON_EXIT;
933 }
934
935 if (!Current->UseDefaultAddress &&
936 (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
937 !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
938 Status = EFI_ALREADY_STARTED;
939 goto ON_EXIT;
940 }
941
942 if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
943 Status = EFI_NO_MAPPING;
944 goto ON_EXIT;
945 }
946 }
947 }
948
949 //
950 // Configure the instance or clean it up.
951 //
952 if (IpConfigData != NULL) {
953 Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
954 } else {
955 Status = Ip4CleanProtocol (IpInstance);
956
957 //
958 // Consider the following valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
959 // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
960 // the unload fails miserably.
961 //
962 if (IpInstance->State == IP4_STATE_CONFIGED) {
963 IpInstance->State = IP4_STATE_UNCONFIGED;
964 }
965 }
966
967 //
968 // Update the MNP's configure data. Ip4ServiceConfigMnp will check
969 // whether it is necessary to reconfigure the MNP.
970 //
971 Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
972
973 ON_EXIT:
974 gBS->RestoreTPL (OldTpl);
975 return Status;
976
977 }
978
979
980 /**
981 Change the IP4 child's multicast setting. The caller
982 should make sure that the parameters is valid.
983
984 @param[in] IpInstance The IP4 child to change the setting.
985 @param[in] JoinFlag TRUE to join the group, otherwise leave it.
986 @param[in] GroupAddress The target group address.
987
988 @retval EFI_ALREADY_STARTED Want to join the group, but already a member of it.
989 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
990 @retval EFI_DEVICE_ERROR Failed to set the group configuraton.
991 @retval EFI_SUCCESS Successfully updated the group setting.
992 @retval EFI_NOT_FOUND Try to leave the group which it isn't a member.
993
994 **/
995 EFI_STATUS
996 Ip4Groups (
997 IN IP4_PROTOCOL *IpInstance,
998 IN BOOLEAN JoinFlag,
999 IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
1000 )
1001 {
1002 IP4_ADDR *Members;
1003 IP4_ADDR Group;
1004 UINT32 Index;
1005
1006 //
1007 // Add it to the instance's Groups, and join the group by IGMP.
1008 // IpInstance->Groups is in network byte order. IGMP operates in
1009 // host byte order
1010 //
1011 if (JoinFlag) {
1012 //
1013 // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.
1014 //
1015 ASSERT (GroupAddress != NULL);
1016 CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
1017
1018 for (Index = 0; Index < IpInstance->GroupCount; Index++) {
1019 if (IpInstance->Groups[Index] == Group) {
1020 return EFI_ALREADY_STARTED;
1021 }
1022 }
1023
1024 Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
1025
1026 if (Members == NULL) {
1027 return EFI_OUT_OF_RESOURCES;
1028 }
1029
1030 if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
1031 FreePool (Members);
1032 return EFI_DEVICE_ERROR;
1033 }
1034
1035 if (IpInstance->Groups != NULL) {
1036 FreePool (IpInstance->Groups);
1037 }
1038
1039 IpInstance->Groups = Members;
1040 IpInstance->GroupCount++;
1041
1042 return EFI_SUCCESS;
1043 }
1044
1045 //
1046 // Leave the group. Leave all the groups if GroupAddress is NULL.
1047 // Must iterate from the end to the beginning because the GroupCount
1048 // is decreamented each time an address is removed..
1049 //
1050 for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
1051 Group = 0;
1052 if(IpInstance->Groups != NULL) {
1053 Group = IpInstance->Groups[Index - 1];
1054 }
1055
1056 if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
1057 if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
1058 return EFI_DEVICE_ERROR;
1059 }
1060
1061 Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
1062 IpInstance->GroupCount--;
1063
1064 if (IpInstance->GroupCount == 0) {
1065 ASSERT (Index == 1);
1066
1067 FreePool (IpInstance->Groups);
1068 IpInstance->Groups = NULL;
1069 }
1070
1071 if (GroupAddress != NULL) {
1072 return EFI_SUCCESS;
1073 }
1074 }
1075 }
1076
1077 return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
1078 }
1079
1080
1081 /**
1082 Joins and leaves multicast groups.
1083
1084 The Groups() function is used to join and leave multicast group sessions. Joining
1085 a group will enable reception of matching multicast packets. Leaving a group will
1086 disable the multicast packet reception.
1087
1088 If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
1089
1090 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1091 @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
1092 @param[in] GroupAddress Pointer to the IPv4 multicast address.
1093
1094 @retval EFI_SUCCESS The operation completed successfully.
1095 @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
1096 - This is NULL.
1097 - JoinFlag is TRUE and GroupAddress is NULL.
1098 - GroupAddress is not NULL and *GroupAddress is
1099 not a multicast IPv4 address.
1100 @retval EFI_NOT_STARTED This instance has not been started.
1101 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
1102 RARP, etc.) is not finished yet.
1103 @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
1104 @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups.
1105 @retval EFI_ALREADY_STARTED The group address is already in the group table (when
1106 JoinFlag is TRUE).
1107 @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
1108 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
1109
1110 **/
1111 EFI_STATUS
1112 EFIAPI
1113 EfiIp4Groups (
1114 IN EFI_IP4_PROTOCOL *This,
1115 IN BOOLEAN JoinFlag,
1116 IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
1117 )
1118 {
1119 IP4_PROTOCOL *IpInstance;
1120 EFI_STATUS Status;
1121 EFI_TPL OldTpl;
1122 IP4_ADDR McastIp;
1123
1124 if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
1125 return EFI_INVALID_PARAMETER;
1126 }
1127
1128 if (GroupAddress != NULL) {
1129 CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
1130
1131 if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
1132 return EFI_INVALID_PARAMETER;
1133 }
1134 }
1135
1136 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1137 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1138
1139 if (IpInstance->State != IP4_STATE_CONFIGED) {
1140 Status = EFI_NOT_STARTED;
1141 goto ON_EXIT;
1142 }
1143
1144 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1145 Status = EFI_NO_MAPPING;
1146 goto ON_EXIT;
1147 }
1148
1149 Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
1150
1151 ON_EXIT:
1152 gBS->RestoreTPL (OldTpl);
1153 return Status;
1154 }
1155
1156
1157 /**
1158 Adds and deletes routing table entries.
1159
1160 The Routes() function adds a route to or deletes a route from the routing table.
1161
1162 Routes are determined by comparing the SubnetAddress with the destination IPv4
1163 address arithmetically AND-ed with the SubnetMask. The gateway address must be
1164 on the same subnet as the configured station address.
1165
1166 The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
1167 The default route matches all destination IPv4 addresses that do not match any
1168 other routes.
1169
1170 A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
1171 IP address if it can be found in the ARP cache or on the local subnet. One automatic
1172 nonroute entry will be inserted into the routing table for outgoing packets that
1173 are addressed to a local subnet (gateway address of 0.0.0.0).
1174
1175 Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
1176 IPv4 Protocol instances that use the default IPv4 address will also have copies
1177 of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
1178 copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
1179 instances. As a result, client modification to the routing table will be lost.
1180
1181 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1182 @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
1183 FALSE to add this route to the routing table. SubnetAddress
1184 and SubnetMask are used as the key to each route entry.
1185 @param[in] SubnetAddress The address of the subnet that needs to be routed.
1186 @param[in] SubnetMask The subnet mask of SubnetAddress.
1187 @param[in] GatewayAddress The unicast gateway IPv4 address for this route.
1188
1189 @retval EFI_SUCCESS The operation completed successfully.
1190 @retval EFI_NOT_STARTED The driver instance has not been started.
1191 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
1192 RARP, etc.) is not finished yet.
1193 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
1194 - This is NULL.
1195 - SubnetAddress is NULL.
1196 - SubnetMask is NULL.
1197 - GatewayAddress is NULL.
1198 - *SubnetAddress is not a valid subnet address.
1199 - *SubnetMask is not a valid subnet mask.
1200 - *GatewayAddress is not a valid unicast IPv4 address.
1201 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
1202 @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
1203 @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
1204 DeleteRoute is FALSE).
1205
1206 **/
1207 EFI_STATUS
1208 EFIAPI
1209 EfiIp4Routes (
1210 IN EFI_IP4_PROTOCOL *This,
1211 IN BOOLEAN DeleteRoute,
1212 IN EFI_IPv4_ADDRESS *SubnetAddress,
1213 IN EFI_IPv4_ADDRESS *SubnetMask,
1214 IN EFI_IPv4_ADDRESS *GatewayAddress
1215 )
1216 {
1217 IP4_PROTOCOL *IpInstance;
1218 IP4_INTERFACE *IpIf;
1219 IP4_ADDR Dest;
1220 IP4_ADDR Netmask;
1221 IP4_ADDR Nexthop;
1222 EFI_STATUS Status;
1223 EFI_TPL OldTpl;
1224
1225 //
1226 // First, validate the parameters
1227 //
1228 if ((This == NULL) || (SubnetAddress == NULL) ||
1229 (SubnetMask == NULL) || (GatewayAddress == NULL)) {
1230 return EFI_INVALID_PARAMETER;
1231 }
1232
1233 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1234 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1235
1236 if (IpInstance->State != IP4_STATE_CONFIGED) {
1237 Status = EFI_NOT_STARTED;
1238 goto ON_EXIT;
1239 }
1240
1241 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1242 Status = EFI_NO_MAPPING;
1243 goto ON_EXIT;
1244 }
1245
1246 CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
1247 CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
1248 CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
1249
1250 Dest = NTOHL (Dest);
1251 Netmask = NTOHL (Netmask);
1252 Nexthop = NTOHL (Nexthop);
1253
1254 IpIf = IpInstance->Interface;
1255
1256 if (!IP4_IS_VALID_NETMASK (Netmask)) {
1257 Status = EFI_INVALID_PARAMETER;
1258 goto ON_EXIT;
1259 }
1260
1261 //
1262 // the gateway address must be a unicast on the connected network if not zero.
1263 //
1264 if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
1265 (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
1266 IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
1267
1268 Status = EFI_INVALID_PARAMETER;
1269 goto ON_EXIT;
1270 }
1271
1272 if (DeleteRoute) {
1273 Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1274 } else {
1275 Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1276 }
1277
1278 ON_EXIT:
1279 gBS->RestoreTPL (OldTpl);
1280 return Status;
1281 }
1282
1283
1284 /**
1285 Check whether the user's token or event has already
1286 been enqueued on IP4's list.
1287
1288 @param[in] Map The container of either user's transmit or receive
1289 token.
1290 @param[in] Item Current item to check against.
1291 @param[in] Context The Token to check againist.
1292
1293 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP.
1294 @retval EFI_SUCCESS The current item isn't the same token/event as the
1295 context.
1296
1297 **/
1298 EFI_STATUS
1299 EFIAPI
1300 Ip4TokenExist (
1301 IN NET_MAP *Map,
1302 IN NET_MAP_ITEM *Item,
1303 IN VOID *Context
1304 )
1305 {
1306 EFI_IP4_COMPLETION_TOKEN *Token;
1307 EFI_IP4_COMPLETION_TOKEN *TokenInItem;
1308
1309 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1310 TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
1311
1312 if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
1313 return EFI_ACCESS_DENIED;
1314 }
1315
1316 return EFI_SUCCESS;
1317 }
1318
1319 /**
1320 Validate the user's token against current station address.
1321
1322 @param[in] Token User's token to validate.
1323 @param[in] IpIf The IP4 child's interface.
1324 @param[in] RawData Set to TRUE to send unformatted packets.
1325
1326 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1327 @retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.
1328 @retval EFI_SUCCESS The token is valid.
1329
1330 **/
1331 EFI_STATUS
1332 Ip4TxTokenValid (
1333 IN EFI_IP4_COMPLETION_TOKEN *Token,
1334 IN IP4_INTERFACE *IpIf,
1335 IN BOOLEAN RawData
1336 )
1337 {
1338 EFI_IP4_TRANSMIT_DATA *TxData;
1339 EFI_IP4_OVERRIDE_DATA *Override;
1340 IP4_ADDR Src;
1341 IP4_ADDR Gateway;
1342 UINT32 Offset;
1343 UINT32 Index;
1344 UINT32 HeadLen;
1345
1346 if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
1347 return EFI_INVALID_PARAMETER;
1348 }
1349
1350 TxData = Token->Packet.TxData;
1351
1352 //
1353 // Check the fragment table: no empty fragment, and length isn't bogus.
1354 //
1355 if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
1356 return EFI_INVALID_PARAMETER;
1357 }
1358
1359 Offset = TxData->TotalDataLength;
1360
1361 if (Offset > IP4_MAX_PACKET_SIZE) {
1362 return EFI_BAD_BUFFER_SIZE;
1363 }
1364
1365 for (Index = 0; Index < TxData->FragmentCount; Index++) {
1366 if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
1367 (TxData->FragmentTable[Index].FragmentLength == 0)) {
1368
1369 return EFI_INVALID_PARAMETER;
1370 }
1371
1372 Offset -= TxData->FragmentTable[Index].FragmentLength;
1373 }
1374
1375 if (Offset != 0) {
1376 return EFI_INVALID_PARAMETER;
1377 }
1378
1379 //
1380 // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData
1381 // is TRUE.
1382 //
1383 if (RawData) {
1384 return EFI_SUCCESS;
1385 }
1386
1387 //
1388 // Check the IP options: no more than 40 bytes and format is OK
1389 //
1390 if (TxData->OptionsLength != 0) {
1391 if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
1392 return EFI_INVALID_PARAMETER;
1393 }
1394
1395 if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
1396 return EFI_INVALID_PARAMETER;
1397 }
1398 }
1399
1400 //
1401 // Check the source and gateway: they must be a valid unicast.
1402 // Gateway must also be on the connected network.
1403 //
1404 if (TxData->OverrideData != NULL) {
1405 Override = TxData->OverrideData;
1406
1407 CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1408 CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
1409
1410 Src = NTOHL (Src);
1411 Gateway = NTOHL (Gateway);
1412
1413 if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
1414 (Src == IP4_ALLONE_ADDRESS) ||
1415 IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
1416
1417 return EFI_INVALID_PARAMETER;
1418 }
1419
1420 //
1421 // If gateway isn't zero, it must be a unicast address, and
1422 // on the connected network.
1423 //
1424 if ((Gateway != IP4_ALLZERO_ADDRESS) &&
1425 ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
1426 !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
1427 IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
1428
1429 return EFI_INVALID_PARAMETER;
1430 }
1431 }
1432
1433 //
1434 // Check the packet length: Head length and packet length all has a limit
1435 //
1436 HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
1437
1438 if ((HeadLen > IP4_MAX_HEADLEN) ||
1439 (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
1440
1441 return EFI_BAD_BUFFER_SIZE;
1442 }
1443
1444 return EFI_SUCCESS;
1445 }
1446
1447
1448 /**
1449 The callback function for the net buffer which wraps the user's
1450 transmit token. Although it seems this function is pretty simple,
1451 there are some subtle things.
1452 When user requests the IP to transmit a packet by passing it a
1453 token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
1454 is wrapped in an net buffer. the net buffer's Free function is
1455 set to Ip4FreeTxToken. The Token and token wrap are added to the
1456 IP child's TxToken map. Then the buffer is passed to Ip4Output for
1457 transmission. If something error happened before that, the buffer
1458 is freed, which in turn will free the token wrap. The wrap may
1459 have been added to the TxToken map or not, and the user's event
1460 shouldn't be fired because we are still in the EfiIp4Transmit. If
1461 the buffer has been sent by Ip4Output, it should be removed from
1462 the TxToken map and user's event signaled. The token wrap and buffer
1463 are bound together. Check the comments in Ip4Output for information
1464 about IP fragmentation.
1465
1466 @param[in] Context The token's wrap.
1467
1468 **/
1469 VOID
1470 EFIAPI
1471 Ip4FreeTxToken (
1472 IN VOID *Context
1473 )
1474 {
1475 IP4_TXTOKEN_WRAP *Wrap;
1476 NET_MAP_ITEM *Item;
1477
1478 Wrap = (IP4_TXTOKEN_WRAP *) Context;
1479
1480 //
1481 // Signal IpSecRecycleEvent to inform IPsec free the memory
1482 //
1483 if (Wrap->IpSecRecycleSignal != NULL) {
1484 gBS->SignalEvent (Wrap->IpSecRecycleSignal);
1485 }
1486
1487 //
1488 // Find the token in the instance's map. EfiIp4Transmit put the
1489 // token to the map. If that failed, NetMapFindKey will return NULL.
1490 //
1491 Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
1492
1493 if (Item != NULL) {
1494 NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
1495 }
1496
1497 if (Wrap->Sent) {
1498 gBS->SignalEvent (Wrap->Token->Event);
1499
1500 //
1501 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
1502 //
1503 DispatchDpc ();
1504 }
1505
1506 FreePool (Wrap);
1507 }
1508
1509
1510 /**
1511 The callback function to Ip4Output to update the transmit status.
1512
1513 @param Ip4Instance The Ip4Instance that request the transmit.
1514 @param Packet The user's transmit request.
1515 @param IoStatus The result of the transmission.
1516 @param Flag Not used during transmission.
1517 @param Context The token's wrap.
1518
1519 **/
1520 VOID
1521 Ip4OnPacketSent (
1522 IP4_PROTOCOL *Ip4Instance,
1523 NET_BUF *Packet,
1524 EFI_STATUS IoStatus,
1525 UINT32 Flag,
1526 VOID *Context
1527 )
1528 {
1529 IP4_TXTOKEN_WRAP *Wrap;
1530
1531 //
1532 // This is the transmission request from upper layer,
1533 // not the IP4 driver itself.
1534 //
1535 ASSERT (Ip4Instance != NULL);
1536
1537 //
1538 // The first fragment of the packet has been sent. Update
1539 // the token's status. That is, if fragmented, the transmit's
1540 // status is the first fragment's status. The Wrap will be
1541 // release when all the fragments are release. Check the comments
1542 // in Ip4FreeTxToken and Ip4Output for information.
1543 //
1544 Wrap = (IP4_TXTOKEN_WRAP *) Context;
1545 Wrap->Token->Status = IoStatus;
1546
1547 NetbufFree (Wrap->Packet);
1548 }
1549
1550
1551 /**
1552 Places outgoing data packets into the transmit queue.
1553
1554 The Transmit() function places a sending request in the transmit queue of this
1555 EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
1556 errors occur, the event in the token will be signaled and the status is updated.
1557
1558 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1559 @param[in] Token Pointer to the transmit token.
1560
1561 @retval EFI_SUCCESS The data has been queued for transmission.
1562 @retval EFI_NOT_STARTED This instance has not been started.
1563 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
1564 RARP, etc.) is not finished yet.
1565 @retval EFI_INVALID_PARAMETER One or more pameters are invalid.
1566 @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event
1567 was already in the transmit queue.
1568 @retval EFI_NOT_READY The completion token could not be queued because the transmit
1569 queue is full.
1570 @retval EFI_NOT_FOUND Not route is found to destination address.
1571 @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
1572 @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
1573 short to transmit.
1574 @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is
1575 greater than MTU (or greater than the maximum packet size if
1576 Token.Packet.TxData.OverrideData.
1577 DoNotFragment is TRUE).
1578
1579 **/
1580 EFI_STATUS
1581 EFIAPI
1582 EfiIp4Transmit (
1583 IN EFI_IP4_PROTOCOL *This,
1584 IN EFI_IP4_COMPLETION_TOKEN *Token
1585 )
1586 {
1587 IP4_SERVICE *IpSb;
1588 IP4_PROTOCOL *IpInstance;
1589 IP4_INTERFACE *IpIf;
1590 IP4_TXTOKEN_WRAP *Wrap;
1591 EFI_IP4_TRANSMIT_DATA *TxData;
1592 EFI_IP4_CONFIG_DATA *Config;
1593 EFI_IP4_OVERRIDE_DATA *Override;
1594 IP4_HEAD Head;
1595 IP4_ADDR GateWay;
1596 EFI_STATUS Status;
1597 EFI_TPL OldTpl;
1598 BOOLEAN DontFragment;
1599 UINT32 HeadLen;
1600 UINT8 RawHdrLen;
1601 UINT32 OptionsLength;
1602 UINT8 *OptionsBuffer;
1603 VOID *FirstFragment;
1604
1605 if (This == NULL) {
1606 return EFI_INVALID_PARAMETER;
1607 }
1608
1609 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1610
1611 if (IpInstance->State != IP4_STATE_CONFIGED) {
1612 return EFI_NOT_STARTED;
1613 }
1614
1615 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1616
1617 IpSb = IpInstance->Service;
1618 IpIf = IpInstance->Interface;
1619 Config = &IpInstance->ConfigData;
1620
1621 if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1622 Status = EFI_NO_MAPPING;
1623 goto ON_EXIT;
1624 }
1625
1626 //
1627 // make sure that token is properly formated
1628 //
1629 Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);
1630
1631 if (EFI_ERROR (Status)) {
1632 goto ON_EXIT;
1633 }
1634
1635 //
1636 // Check whether the token or signal already existed.
1637 //
1638 if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
1639 Status = EFI_ACCESS_DENIED;
1640 goto ON_EXIT;
1641 }
1642
1643 //
1644 // Build the IP header, need to fill in the Tos, TotalLen, Id,
1645 // fragment, Ttl, protocol, Src, and Dst.
1646 //
1647 TxData = Token->Packet.TxData;
1648
1649 FirstFragment = NULL;
1650
1651 if (Config->RawData) {
1652 //
1653 // When RawData is TRUE, first buffer in FragmentTable points to a raw
1654 // IPv4 fragment including IPv4 header and options.
1655 //
1656 FirstFragment = TxData->FragmentTable[0].FragmentBuffer;
1657 CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));
1658
1659 RawHdrLen = (UINT8) (RawHdrLen & 0x0f);
1660 if (RawHdrLen < 5) {
1661 Status = EFI_INVALID_PARAMETER;
1662 goto ON_EXIT;
1663 }
1664
1665 RawHdrLen = (UINT8) (RawHdrLen << 2);
1666
1667 CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);
1668
1669 Ip4NtohHead (&Head);
1670 HeadLen = 0;
1671 DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);
1672
1673 if (!DontFragment) {
1674 Status = EFI_INVALID_PARAMETER;
1675 goto ON_EXIT;
1676 }
1677
1678 GateWay = IP4_ALLZERO_ADDRESS;
1679
1680 //
1681 // Get IPv4 options from first fragment.
1682 //
1683 if (RawHdrLen == IP4_MIN_HEADLEN) {
1684 OptionsLength = 0;
1685 OptionsBuffer = NULL;
1686 } else {
1687 OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;
1688 OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;
1689 }
1690
1691 //
1692 // Trim off IPv4 header and options from first fragment.
1693 //
1694 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;
1695 TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;
1696 } else {
1697 CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
1698 Head.Dst = NTOHL (Head.Dst);
1699
1700 if (TxData->OverrideData != NULL) {
1701 Override = TxData->OverrideData;
1702 Head.Protocol = Override->Protocol;
1703 Head.Tos = Override->TypeOfService;
1704 Head.Ttl = Override->TimeToLive;
1705 DontFragment = Override->DoNotFragment;
1706
1707 CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1708 CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
1709
1710 Head.Src = NTOHL (Head.Src);
1711 GateWay = NTOHL (GateWay);
1712 } else {
1713 Head.Src = IpIf->Ip;
1714 GateWay = IP4_ALLZERO_ADDRESS;
1715 Head.Protocol = Config->DefaultProtocol;
1716 Head.Tos = Config->TypeOfService;
1717 Head.Ttl = Config->TimeToLive;
1718 DontFragment = Config->DoNotFragment;
1719 }
1720
1721 Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
1722 HeadLen = (TxData->OptionsLength + 3) & (~0x03);
1723
1724 OptionsLength = TxData->OptionsLength;
1725 OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);
1726 }
1727
1728 //
1729 // If don't fragment and fragment needed, return error
1730 //
1731 if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {
1732 Status = EFI_BAD_BUFFER_SIZE;
1733 goto ON_EXIT;
1734 }
1735
1736 //
1737 // OK, it survives all the validation check. Wrap the token in
1738 // a IP4_TXTOKEN_WRAP and the data in a netbuf
1739 //
1740 Status = EFI_OUT_OF_RESOURCES;
1741 Wrap = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));
1742 if (Wrap == NULL) {
1743 goto ON_EXIT;
1744 }
1745
1746 Wrap->IpInstance = IpInstance;
1747 Wrap->Token = Token;
1748 Wrap->Sent = FALSE;
1749 Wrap->Life = IP4_US_TO_SEC (Config->TransmitTimeout);
1750 Wrap->Packet = NetbufFromExt (
1751 (NET_FRAGMENT *) TxData->FragmentTable,
1752 TxData->FragmentCount,
1753 IP4_MAX_HEADLEN,
1754 0,
1755 Ip4FreeTxToken,
1756 Wrap
1757 );
1758
1759 if (Wrap->Packet == NULL) {
1760 FreePool (Wrap);
1761 goto ON_EXIT;
1762 }
1763
1764 Token->Status = EFI_NOT_READY;
1765
1766 if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
1767 //
1768 // NetbufFree will call Ip4FreeTxToken, which in turn will
1769 // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
1770 // enqueued.
1771 //
1772 if (Config->RawData) {
1773 //
1774 // Restore pointer of first fragment in RawData mode.
1775 //
1776 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1777 }
1778
1779 NetbufFree (Wrap->Packet);
1780 goto ON_EXIT;
1781 }
1782
1783 //
1784 // Mark the packet sent before output it. Mark it not sent again if the
1785 // returned status is not EFI_SUCCESS;
1786 //
1787 Wrap->Sent = TRUE;
1788
1789 Status = Ip4Output (
1790 IpSb,
1791 IpInstance,
1792 Wrap->Packet,
1793 &Head,
1794 OptionsBuffer,
1795 OptionsLength,
1796 GateWay,
1797 Ip4OnPacketSent,
1798 Wrap
1799 );
1800
1801 if (EFI_ERROR (Status)) {
1802 Wrap->Sent = FALSE;
1803
1804 if (Config->RawData) {
1805 //
1806 // Restore pointer of first fragment in RawData mode.
1807 //
1808 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1809 }
1810
1811 NetbufFree (Wrap->Packet);
1812 }
1813
1814 if (Config->RawData) {
1815 //
1816 // Restore pointer of first fragment in RawData mode.
1817 //
1818 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1819 }
1820
1821 ON_EXIT:
1822 gBS->RestoreTPL (OldTpl);
1823 return Status;
1824 }
1825
1826
1827 /**
1828 Places a receiving request into the receiving queue.
1829
1830 The Receive() function places a completion token into the receive packet queue.
1831 This function is always asynchronous.
1832
1833 The Token.Event field in the completion token must be filled in by the caller
1834 and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
1835 driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
1836 is signaled.
1837
1838 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1839 @param[in] Token Pointer to a token that is associated with the receive data descriptor.
1840
1841 @retval EFI_SUCCESS The receive completion token was cached.
1842 @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
1843 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
1844 is not finished yet.
1845 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
1846 - This is NULL.
1847 - Token is NULL.
1848 - Token.Event is NULL.
1849 @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
1850 resources (usually memory).
1851 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
1852 The EFI IPv4 Protocol instance has been reset to startup defaults.
1853 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
1854 in the receive queue.
1855 @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
1856 @retval EFI_ICMP_ERROR An ICMP error packet was received.
1857
1858 **/
1859 EFI_STATUS
1860 EFIAPI
1861 EfiIp4Receive (
1862 IN EFI_IP4_PROTOCOL *This,
1863 IN EFI_IP4_COMPLETION_TOKEN *Token
1864 )
1865 {
1866 IP4_PROTOCOL *IpInstance;
1867 EFI_STATUS Status;
1868 EFI_TPL OldTpl;
1869
1870 //
1871 // First validate the parameters
1872 //
1873 if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
1874 return EFI_INVALID_PARAMETER;
1875 }
1876
1877 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1878
1879 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1880
1881 if (IpInstance->State != IP4_STATE_CONFIGED) {
1882 Status = EFI_NOT_STARTED;
1883 goto ON_EXIT;
1884 }
1885
1886 //
1887 // Check whether the toke is already on the receive queue.
1888 //
1889 Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
1890
1891 if (EFI_ERROR (Status)) {
1892 Status = EFI_ACCESS_DENIED;
1893 goto ON_EXIT;
1894 }
1895
1896 //
1897 // Queue the token then check whether there is pending received packet.
1898 //
1899 Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
1900
1901 if (EFI_ERROR (Status)) {
1902 goto ON_EXIT;
1903 }
1904
1905 Status = Ip4InstanceDeliverPacket (IpInstance);
1906
1907 //
1908 // Dispatch the DPC queued by the NotifyFunction of this instane's receive
1909 // event.
1910 //
1911 DispatchDpc ();
1912
1913 ON_EXIT:
1914 gBS->RestoreTPL (OldTpl);
1915 return Status;
1916 }
1917
1918
1919 /**
1920 Cancel the transmitted but not recycled packet. If a matching
1921 token is found, it will call Ip4CancelPacket to cancel the
1922 packet. Ip4CancelPacket will cancel all the fragments of the
1923 packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
1924 will be deleted from the Map, and user's event signalled.
1925 Because Ip4CancelPacket and other functions are all called in
1926 line, so, after Ip4CancelPacket returns, the Item has been freed.
1927
1928 @param[in] Map The IP4 child's transmit queue.
1929 @param[in] Item The current transmitted packet to test.
1930 @param[in] Context The user's token to cancel.
1931
1932 @retval EFI_SUCCESS Continue to check the next Item.
1933 @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.
1934
1935 **/
1936 EFI_STATUS
1937 EFIAPI
1938 Ip4CancelTxTokens (
1939 IN NET_MAP *Map,
1940 IN NET_MAP_ITEM *Item,
1941 IN VOID *Context
1942 )
1943 {
1944 EFI_IP4_COMPLETION_TOKEN *Token;
1945 IP4_TXTOKEN_WRAP *Wrap;
1946
1947 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1948
1949 //
1950 // Return EFI_SUCCESS to check the next item in the map if
1951 // this one doesn't match.
1952 //
1953 if ((Token != NULL) && (Token != Item->Key)) {
1954 return EFI_SUCCESS;
1955 }
1956
1957 Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
1958 ASSERT (Wrap != NULL);
1959
1960 //
1961 // Don't access the Item, Wrap and Token's members after this point.
1962 // Item and wrap has been freed. And we no longer own the Token.
1963 //
1964 Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
1965
1966 //
1967 // If only one item is to be cancel, return EFI_ABORTED to stop
1968 // iterating the map any more.
1969 //
1970 if (Token != NULL) {
1971 return EFI_ABORTED;
1972 }
1973
1974 return EFI_SUCCESS;
1975 }
1976
1977
1978 /**
1979 Cancel the receive request. This is quiet simple, because
1980 it is only enqueued in our local receive map.
1981
1982 @param[in] Map The IP4 child's receive queue.
1983 @param[in] Item Current receive request to cancel.
1984 @param[in] Context The user's token to cancel.
1985
1986 @retval EFI_SUCCESS Continue to check the next receive request on the
1987 queue.
1988 @retval EFI_ABORTED The user's token (token != NULL) has been
1989 cancelled.
1990
1991 **/
1992 EFI_STATUS
1993 EFIAPI
1994 Ip4CancelRxTokens (
1995 IN NET_MAP *Map,
1996 IN NET_MAP_ITEM *Item,
1997 IN VOID *Context
1998 )
1999 {
2000 EFI_IP4_COMPLETION_TOKEN *Token;
2001 EFI_IP4_COMPLETION_TOKEN *This;
2002
2003 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
2004 This = Item->Key;
2005
2006 if ((Token != NULL) && (Token != This)) {
2007 return EFI_SUCCESS;
2008 }
2009
2010 NetMapRemoveItem (Map, Item, NULL);
2011
2012 This->Status = EFI_ABORTED;
2013 This->Packet.RxData = NULL;
2014 gBS->SignalEvent (This->Event);
2015
2016 if (Token != NULL) {
2017 return EFI_ABORTED;
2018 }
2019
2020 return EFI_SUCCESS;
2021 }
2022
2023
2024 /**
2025 Cancel the user's receive/transmit request.
2026
2027 @param[in] IpInstance The IP4 child.
2028 @param[in] Token The token to cancel. If NULL, all token will be
2029 cancelled.
2030
2031 @retval EFI_SUCCESS The token is cancelled.
2032 @retval EFI_NOT_FOUND The token isn't found on either the
2033 transmit/receive queue.
2034 @retval EFI_DEVICE_ERROR Not all token is cancelled when Token is NULL.
2035
2036 **/
2037 EFI_STATUS
2038 Ip4Cancel (
2039 IN IP4_PROTOCOL *IpInstance,
2040 IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
2041 )
2042 {
2043 EFI_STATUS Status;
2044
2045 //
2046 // First check the transmitted packet. Ip4CancelTxTokens returns
2047 // EFI_ABORTED to mean that the token has been cancelled when
2048 // token != NULL. So, return EFI_SUCCESS for this condition.
2049 //
2050 Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
2051
2052 if (EFI_ERROR (Status)) {
2053 if ((Token != NULL) && (Status == EFI_ABORTED)) {
2054 return EFI_SUCCESS;
2055 }
2056
2057 return Status;
2058 }
2059
2060 //
2061 // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
2062 // for Token!=NULL and it is cancelled.
2063 //
2064 Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
2065 //
2066 // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
2067 // events.
2068 //
2069 DispatchDpc ();
2070 if (EFI_ERROR (Status)) {
2071 if ((Token != NULL) && (Status == EFI_ABORTED)) {
2072 return EFI_SUCCESS;
2073 }
2074
2075 return Status;
2076 }
2077
2078 //
2079 // OK, if the Token is found when Token != NULL, the NetMapIterate
2080 // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
2081 //
2082 if (Token != NULL) {
2083 return EFI_NOT_FOUND;
2084 }
2085
2086 //
2087 // If Token == NULL, cancel all the tokens. return error if no
2088 // all of them are cancelled.
2089 //
2090 if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
2091 !NetMapIsEmpty (&IpInstance->RxTokens)) {
2092
2093 return EFI_DEVICE_ERROR;
2094 }
2095
2096 return EFI_SUCCESS;
2097 }
2098
2099
2100 /**
2101 Abort an asynchronous transmit or receive request.
2102
2103 The Cancel() function is used to abort a pending transmit or receive request.
2104 If the token is in the transmit or receive request queues, after calling this
2105 function, Token->Status will be set to EFI_ABORTED and then Token->Event will
2106 be signaled. If the token is not in one of the queues, which usually means the
2107 asynchronous operation has completed, this function will not signal the token
2108 and EFI_NOT_FOUND is returned.
2109
2110 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
2111 @param[in] Token Pointer to a token that has been issued by
2112 EFI_IP4_PROTOCOL.Transmit() or
2113 EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
2114 tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
2115 defined in EFI_IP4_PROTOCOL.Transmit().
2116
2117 @retval EFI_SUCCESS The asynchronous I/O request was aborted and
2118 Token.->Event was signaled. When Token is NULL, all
2119 pending requests were aborted and their events were signaled.
2120 @retval EFI_INVALID_PARAMETER This is NULL.
2121 @retval EFI_NOT_STARTED This instance has not been started.
2122 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
2123 RARP, etc.) is not finished yet.
2124 @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
2125 not found in the transmit or receive queue. It has either completed
2126 or was not issued by Transmit() and Receive().
2127
2128 **/
2129 EFI_STATUS
2130 EFIAPI
2131 EfiIp4Cancel (
2132 IN EFI_IP4_PROTOCOL *This,
2133 IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
2134 )
2135 {
2136 IP4_PROTOCOL *IpInstance;
2137 EFI_STATUS Status;
2138 EFI_TPL OldTpl;
2139
2140 if (This == NULL) {
2141 return EFI_INVALID_PARAMETER;
2142 }
2143
2144 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
2145
2146 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2147
2148 if (IpInstance->State != IP4_STATE_CONFIGED) {
2149 Status = EFI_NOT_STARTED;
2150 goto ON_EXIT;
2151 }
2152
2153 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
2154 Status = EFI_NO_MAPPING;
2155 goto ON_EXIT;
2156 }
2157
2158 Status = Ip4Cancel (IpInstance, Token);
2159
2160 ON_EXIT:
2161 gBS->RestoreTPL (OldTpl);
2162 return Status;
2163 }
2164
2165
2166 /**
2167 Polls for incoming data packets and processes outgoing data packets.
2168
2169 The Poll() function polls for incoming data packets and processes outgoing data
2170 packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
2171 function to increase the rate that data packets are moved between the communications
2172 device and the transmit and receive queues.
2173
2174 In some systems the periodic timer event may not poll the underlying communications
2175 device fast enough to transmit and/or receive all data packets without missing
2176 incoming packets or dropping outgoing packets. Drivers and applications that are
2177 experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
2178 more often.
2179
2180 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
2181
2182 @retval EFI_SUCCESS Incoming or outgoing data was processed.
2183 @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
2184 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
2185 RARP, etc.) is not finished yet.
2186 @retval EFI_INVALID_PARAMETER This is NULL.
2187 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
2188 @retval EFI_NOT_READY No incoming or outgoing data is processed.
2189 @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
2190 Consider increasing the polling rate.
2191
2192 **/
2193 EFI_STATUS
2194 EFIAPI
2195 EfiIp4Poll (
2196 IN EFI_IP4_PROTOCOL *This
2197 )
2198 {
2199 IP4_PROTOCOL *IpInstance;
2200 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
2201
2202 if (This == NULL) {
2203 return EFI_INVALID_PARAMETER;
2204 }
2205
2206 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
2207
2208 if (IpInstance->State == IP4_STATE_UNCONFIGED) {
2209 return EFI_NOT_STARTED;
2210 }
2211
2212 Mnp = IpInstance->Service->Mnp;
2213
2214 //
2215 // Don't lock the Poll function to enable the deliver of
2216 // the packet polled up.
2217 //
2218 return Mnp->Poll (Mnp);
2219 }
2220
2221 /**
2222 Decrease the life of the transmitted packets. If it is
2223 decreased to zero, cancel the packet. This function is
2224 called by Ip4PacketTimerTicking which time out both the
2225 received-but-not-delivered and transmitted-but-not-recycle
2226 packets.
2227
2228 @param[in] Map The IP4 child's transmit map.
2229 @param[in] Item Current transmitted packet.
2230 @param[in] Context Not used.
2231
2232 @retval EFI_SUCCESS Always returns EFI_SUCCESS.
2233
2234 **/
2235 EFI_STATUS
2236 EFIAPI
2237 Ip4SentPacketTicking (
2238 IN NET_MAP *Map,
2239 IN NET_MAP_ITEM *Item,
2240 IN VOID *Context
2241 )
2242 {
2243 IP4_TXTOKEN_WRAP *Wrap;
2244
2245 Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
2246 ASSERT (Wrap != NULL);
2247
2248 if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
2249 Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
2250 }
2251
2252 return EFI_SUCCESS;
2253 }
2254
2255 /**
2256 This heart beat timer of IP4 service instance times out all of its IP4 children's
2257 received-but-not-delivered and transmitted-but-not-recycle packets, and provides
2258 time input for its IGMP protocol.
2259
2260 @param[in] Event The IP4 service instance's heart beat timer.
2261 @param[in] Context The IP4 service instance.
2262
2263 **/
2264 VOID
2265 EFIAPI
2266 Ip4TimerTicking (
2267 IN EFI_EVENT Event,
2268 IN VOID *Context
2269 )
2270 {
2271 IP4_SERVICE *IpSb;
2272
2273 IpSb = (IP4_SERVICE *) Context;
2274 NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
2275
2276 Ip4PacketTimerTicking (IpSb);
2277 Ip4IgmpTicking (IpSb);
2278 }
2279
2280 /**
2281 This dedicated timer is used to poll underlying network media status. In case
2282 of cable swap or wireless network switch, a new round auto configuration will
2283 be initiated. The timer will signal the IP4 to run DHCP configuration again.
2284 IP4 driver will free old IP address related resource, such as route table and
2285 Interface, then initiate a DHCP process to acquire new IP, eventually create
2286 route table for new IP address.
2287
2288 @param[in] Event The IP4 service instance's heart beat timer.
2289 @param[in] Context The IP4 service instance.
2290
2291 **/
2292 VOID
2293 EFIAPI
2294 Ip4TimerReconfigChecking (
2295 IN EFI_EVENT Event,
2296 IN VOID *Context
2297 )
2298 {
2299 IP4_SERVICE *IpSb;
2300 BOOLEAN OldMediaPresent;
2301 EFI_STATUS Status;
2302 EFI_SIMPLE_NETWORK_MODE SnpModeData;
2303
2304 IpSb = (IP4_SERVICE *) Context;
2305 NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
2306
2307 OldMediaPresent = IpSb->MediaPresent;
2308
2309 //
2310 // Get fresh mode data from MNP, since underlying media status may change.
2311 // Here, it needs to mention that the MediaPresent can also be checked even if
2312 // EFI_NOT_STARTED returned while this MNP child driver instance isn't configured.
2313 //
2314 Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &SnpModeData);
2315 if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
2316 return;
2317 }
2318
2319 IpSb->MediaPresent = SnpModeData.MediaPresent;
2320 //
2321 // Media transimit Unpresent to Present means new link movement is detected.
2322 //
2323 if (!OldMediaPresent && IpSb->MediaPresent && (IpSb->Ip4Config2Instance.Policy == Ip4Config2PolicyDhcp)) {
2324 //
2325 // Signal the IP4 to run the dhcp configuration again. IP4 driver will free
2326 // old IP address related resource, such as route table and Interface, then
2327 // initiate a DHCP round to acquire new IP, eventually
2328 // create route table for new IP address.
2329 //
2330 if (IpSb->ReconfigEvent != NULL) {
2331 Status = gBS->SignalEvent (IpSb->ReconfigEvent);
2332 DispatchDpc ();
2333 }
2334 }
2335 }