MdeModulePkg: Update Ip4Dxe driver to support Ip4Config2 protocol,
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Impl.c
1 /** @file
2
3 Copyright (c) 2005 - 2015, 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->Service = IpSb;
554
555 InitializeListHead (&IpInstance->Link);
556 NetMapInit (&IpInstance->RxTokens);
557 NetMapInit (&IpInstance->TxTokens);
558 InitializeListHead (&IpInstance->Received);
559 InitializeListHead (&IpInstance->Delivered);
560 InitializeListHead (&IpInstance->AddrLink);
561
562 EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
563 }
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
600 IpSb = IpInstance->Service;
601
602 //
603 // User is changing packet filters. It must be stopped
604 // before the station address can be changed.
605 //
606 if (IpInstance->State == IP4_STATE_CONFIGED) {
607 //
608 // Cancel all the pending transmit/receive from upper layer
609 //
610 Status = Ip4Cancel (IpInstance, NULL);
611
612 if (EFI_ERROR (Status)) {
613 return EFI_DEVICE_ERROR;
614 }
615
616 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
617 return EFI_SUCCESS;
618 }
619
620 //
621 // Configure a fresh IP4 protocol instance. Create a route table.
622 // Each IP child has its own route table, which may point to the
623 // default table if it is using default address.
624 //
625 Status = EFI_OUT_OF_RESOURCES;
626 IpInstance->RouteTable = Ip4CreateRouteTable ();
627
628 if (IpInstance->RouteTable == NULL) {
629 return Status;
630 }
631
632 //
633 // Set up the interface.
634 //
635 CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
636 CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
637
638 Ip = NTOHL (Ip);
639 Netmask = NTOHL (Netmask);
640
641 if (!Config->UseDefaultAddress) {
642 //
643 // Find whether there is already an interface with the same
644 // station address. All the instances with the same station
645 // address shares one interface.
646 //
647 IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
648
649 if (IpIf != NULL) {
650 NET_GET_REF (IpIf);
651
652 } else {
653 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
654
655 if (IpIf == NULL) {
656 goto ON_ERROR;
657 }
658
659 Status = Ip4SetAddress (IpIf, Ip, Netmask);
660
661 if (EFI_ERROR (Status)) {
662 Status = EFI_DEVICE_ERROR;
663 Ip4FreeInterface (IpIf, IpInstance);
664 goto ON_ERROR;
665 }
666
667 InsertTailList (&IpSb->Interfaces, &IpIf->Link);
668 }
669
670 //
671 // Add a route to this connected network in the route table
672 //
673 Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
674
675 } else {
676 //
677 // Use the default address. If the default configuration hasn't
678 // been started, start it.
679 //
680 if (IpSb->State == IP4_SERVICE_UNSTARTED) {
681 Status = EFI_NO_MAPPING;
682 goto ON_ERROR;
683 }
684
685 IpIf = IpSb->DefaultInterface;
686 NET_GET_REF (IpSb->DefaultInterface);
687
688 //
689 // If default address is used, so is the default route table.
690 // Any route set by the instance has the precedence over the
691 // routes in the default route table. Link the default table
692 // after the instance's table. Routing will search the local
693 // table first.
694 //
695 NET_GET_REF (IpSb->DefaultRouteTable);
696 IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
697 }
698
699 IpInstance->Interface = IpIf;
700 if (IpIf->Arp != NULL) {
701 Arp = NULL;
702 Status = gBS->OpenProtocol (
703 IpIf->ArpHandle,
704 &gEfiArpProtocolGuid,
705 (VOID **) &Arp,
706 gIp4DriverBinding.DriverBindingHandle,
707 IpInstance->Handle,
708 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
709 );
710 if (EFI_ERROR (Status)) {
711 goto ON_ERROR;
712 }
713 }
714 InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
715
716 CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
717 IpInstance->State = IP4_STATE_CONFIGED;
718
719 //
720 // Although EFI_NO_MAPPING is an error code, the IP child has been
721 // successfully configured and doesn't need reconfiguration when
722 // default address is acquired.
723 //
724 if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
725 return EFI_NO_MAPPING;
726 }
727
728 return EFI_SUCCESS;
729
730 ON_ERROR:
731 Ip4FreeRouteTable (IpInstance->RouteTable);
732 IpInstance->RouteTable = NULL;
733 return Status;
734 }
735
736
737 /**
738 Clean up the IP4 child, release all the resources used by it.
739
740 @param[in] IpInstance The IP4 child to clean up.
741
742 @retval EFI_SUCCESS The IP4 child is cleaned up.
743 @retval EFI_DEVICE_ERROR Some resources failed to be released.
744
745 **/
746 EFI_STATUS
747 Ip4CleanProtocol (
748 IN IP4_PROTOCOL *IpInstance
749 )
750 {
751 if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
752 return EFI_DEVICE_ERROR;
753 }
754
755 if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
756 return EFI_DEVICE_ERROR;
757 }
758
759 //
760 // Some packets haven't been recycled. It is because either the
761 // user forgets to recycle the packets, or because the callback
762 // hasn't been called. Just leave it alone.
763 //
764 if (!IsListEmpty (&IpInstance->Delivered)) {
765 ;
766 }
767
768 if (IpInstance->Interface != NULL) {
769 RemoveEntryList (&IpInstance->AddrLink);
770 if (IpInstance->Interface->Arp != NULL) {
771 gBS->CloseProtocol (
772 IpInstance->Interface->ArpHandle,
773 &gEfiArpProtocolGuid,
774 gIp4DriverBinding.DriverBindingHandle,
775 IpInstance->Handle
776 );
777 }
778 Ip4FreeInterface (IpInstance->Interface, IpInstance);
779 IpInstance->Interface = NULL;
780 }
781
782 if (IpInstance->RouteTable != NULL) {
783 if (IpInstance->RouteTable->Next != NULL) {
784 Ip4FreeRouteTable (IpInstance->RouteTable->Next);
785 }
786
787 Ip4FreeRouteTable (IpInstance->RouteTable);
788 IpInstance->RouteTable = NULL;
789 }
790
791 if (IpInstance->EfiRouteTable != NULL) {
792 FreePool (IpInstance->EfiRouteTable);
793 IpInstance->EfiRouteTable = NULL;
794 IpInstance->EfiRouteCount = 0;
795 }
796
797 if (IpInstance->Groups != NULL) {
798 FreePool (IpInstance->Groups);
799 IpInstance->Groups = NULL;
800 IpInstance->GroupCount = 0;
801 }
802
803 NetMapClean (&IpInstance->TxTokens);
804
805 NetMapClean (&IpInstance->RxTokens);
806
807 return EFI_SUCCESS;
808 }
809
810
811 /**
812 Validate that Ip/Netmask pair is OK to be used as station
813 address. Only continuous netmasks are supported. and check
814 that StationAddress is a unicast address on the newtwork.
815
816 @param[in] Ip The IP address to validate.
817 @param[in] Netmask The netmaks of the IP.
818
819 @retval TRUE The Ip/Netmask pair is valid.
820 @retval FALSE The Ip/Netmask pair is invalid.
821
822 **/
823 BOOLEAN
824 Ip4StationAddressValid (
825 IN IP4_ADDR Ip,
826 IN IP4_ADDR Netmask
827 )
828 {
829 IP4_ADDR NetBrdcastMask;
830 INTN Len;
831 INTN Type;
832
833 //
834 // Only support the station address with 0.0.0.0/0 to enable DHCP client.
835 //
836 if (Netmask == IP4_ALLZERO_ADDRESS) {
837 return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
838 }
839
840 //
841 // Only support the continuous net masks
842 //
843 if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {
844 return FALSE;
845 }
846
847 //
848 // Station address can't be class D or class E address
849 //
850 if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
851 return FALSE;
852 }
853
854 //
855 // Station address can't be subnet broadcast/net broadcast address
856 //
857 if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
858 return FALSE;
859 }
860
861 NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];
862
863 if (Ip == (Ip | ~NetBrdcastMask)) {
864 return FALSE;
865 }
866
867 return TRUE;
868 }
869
870
871 /**
872 Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
873
874 The Configure() function is used to set, change, or reset the operational
875 parameters and filter settings for this EFI IPv4 Protocol instance. Until these
876 parameters have been set, no network traffic can be sent or received by this
877 instance. Once the parameters have been reset (by calling this function with
878 IpConfigData set to NULL), no more traffic can be sent or received until these
879 parameters have been set again. Each EFI IPv4 Protocol instance can be started
880 and stopped independently of each other by enabling or disabling their receive
881 filter settings with the Configure() function.
882
883 When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
884 be appended as an alias address into the addresses list in the EFI IPv4 Protocol
885 driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
886 to retrieve the default IPv4 address if it is not available yet. Clients could
887 frequently call GetModeData() to check the status to ensure that the default IPv4
888 address is ready.
889
890 If operational parameters are reset or changed, any pending transmit and receive
891 requests will be cancelled. Their completion token status will be set to EFI_ABORTED
892 and their events will be signaled.
893
894 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
895 @param[in] IpConfigData Pointer to the EFI IPv4 Protocol configuration data structure.
896
897 @retval EFI_SUCCESS The driver instance was successfully opened.
898 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
899 RARP, etc.) is not finished yet.
900 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
901 @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE:
902 A configuration protocol (DHCP, BOOTP, RARP, etc.) could
903 not be located when clients choose to use the default IPv4
904 address. This EFI IPv4 Protocol implementation does not
905 support this requested filter or timeout setting.
906 @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated.
907 @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the
908 IPv4 address or subnet mask can be changed. The interface must
909 also be stopped when switching to/from raw packet mode.
910 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4
911 Protocol driver instance is not opened.
912
913 **/
914 EFI_STATUS
915 EFIAPI
916 EfiIp4Configure (
917 IN EFI_IP4_PROTOCOL *This,
918 IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
919 )
920 {
921 IP4_PROTOCOL *IpInstance;
922 EFI_IP4_CONFIG_DATA *Current;
923 EFI_TPL OldTpl;
924 EFI_STATUS Status;
925 BOOLEAN AddrOk;
926 IP4_ADDR IpAddress;
927 IP4_ADDR SubnetMask;
928
929 //
930 // First, validate the parameters
931 //
932 if (This == NULL) {
933 return EFI_INVALID_PARAMETER;
934 }
935
936 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
937 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
938
939 //
940 // Validate the configuration first.
941 //
942 if (IpConfigData != NULL) {
943
944 CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
945 CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
946
947 IpAddress = NTOHL (IpAddress);
948 SubnetMask = NTOHL (SubnetMask);
949
950 //
951 // Check whether the station address is a valid unicast address
952 //
953 if (!IpConfigData->UseDefaultAddress) {
954 AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
955
956 if (!AddrOk) {
957 Status = EFI_INVALID_PARAMETER;
958 goto ON_EXIT;
959 }
960 }
961
962 //
963 // User can only update packet filters when already configured.
964 // If it wants to change the station address, it must configure(NULL)
965 // the instance first.
966 //
967 if (IpInstance->State == IP4_STATE_CONFIGED) {
968 Current = &IpInstance->ConfigData;
969
970 if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
971 Status = EFI_ALREADY_STARTED;
972 goto ON_EXIT;
973 }
974
975 if (!Current->UseDefaultAddress &&
976 (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
977 !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
978 Status = EFI_ALREADY_STARTED;
979 goto ON_EXIT;
980 }
981
982 if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
983 Status = EFI_NO_MAPPING;
984 goto ON_EXIT;
985 }
986 }
987 }
988
989 //
990 // Configure the instance or clean it up.
991 //
992 if (IpConfigData != NULL) {
993 Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
994 } else {
995 Status = Ip4CleanProtocol (IpInstance);
996
997 //
998 // Don't change the state if it is DESTROY, consider the following
999 // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
1000 // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
1001 // the unload fails miserably.
1002 //
1003 if (IpInstance->State == IP4_STATE_CONFIGED) {
1004 IpInstance->State = IP4_STATE_UNCONFIGED;
1005 }
1006 }
1007
1008 //
1009 // Update the MNP's configure data. Ip4ServiceConfigMnp will check
1010 // whether it is necessary to reconfigure the MNP.
1011 //
1012 Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
1013
1014 ON_EXIT:
1015 gBS->RestoreTPL (OldTpl);
1016 return Status;
1017
1018 }
1019
1020
1021 /**
1022 Change the IP4 child's multicast setting. The caller
1023 should make sure that the parameters is valid.
1024
1025 @param[in] IpInstance The IP4 child to change the setting.
1026 @param[in] JoinFlag TRUE to join the group, otherwise leave it.
1027 @param[in] GroupAddress The target group address.
1028
1029 @retval EFI_ALREADY_STARTED Want to join the group, but already a member of it.
1030 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
1031 @retval EFI_DEVICE_ERROR Failed to set the group configuraton.
1032 @retval EFI_SUCCESS Successfully updated the group setting.
1033 @retval EFI_NOT_FOUND Try to leave the group which it isn't a member.
1034
1035 **/
1036 EFI_STATUS
1037 Ip4Groups (
1038 IN IP4_PROTOCOL *IpInstance,
1039 IN BOOLEAN JoinFlag,
1040 IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
1041 )
1042 {
1043 IP4_ADDR *Members;
1044 IP4_ADDR Group;
1045 UINT32 Index;
1046
1047 //
1048 // Add it to the instance's Groups, and join the group by IGMP.
1049 // IpInstance->Groups is in network byte order. IGMP operates in
1050 // host byte order
1051 //
1052 if (JoinFlag) {
1053 //
1054 // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.
1055 //
1056 ASSERT (GroupAddress != NULL);
1057 CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
1058
1059 for (Index = 0; Index < IpInstance->GroupCount; Index++) {
1060 if (IpInstance->Groups[Index] == Group) {
1061 return EFI_ALREADY_STARTED;
1062 }
1063 }
1064
1065 Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
1066
1067 if (Members == NULL) {
1068 return EFI_OUT_OF_RESOURCES;
1069 }
1070
1071 if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
1072 FreePool (Members);
1073 return EFI_DEVICE_ERROR;
1074 }
1075
1076 if (IpInstance->Groups != NULL) {
1077 FreePool (IpInstance->Groups);
1078 }
1079
1080 IpInstance->Groups = Members;
1081 IpInstance->GroupCount++;
1082
1083 return EFI_SUCCESS;
1084 }
1085
1086 //
1087 // Leave the group. Leave all the groups if GroupAddress is NULL.
1088 // Must iterate from the end to the beginning because the GroupCount
1089 // is decreamented each time an address is removed..
1090 //
1091 for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
1092 Group = IpInstance->Groups[Index - 1];
1093
1094 if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
1095 if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
1096 return EFI_DEVICE_ERROR;
1097 }
1098
1099 Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
1100 IpInstance->GroupCount--;
1101
1102 if (IpInstance->GroupCount == 0) {
1103 ASSERT (Index == 1);
1104
1105 FreePool (IpInstance->Groups);
1106 IpInstance->Groups = NULL;
1107 }
1108
1109 if (GroupAddress != NULL) {
1110 return EFI_SUCCESS;
1111 }
1112 }
1113 }
1114
1115 return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
1116 }
1117
1118
1119 /**
1120 Joins and leaves multicast groups.
1121
1122 The Groups() function is used to join and leave multicast group sessions. Joining
1123 a group will enable reception of matching multicast packets. Leaving a group will
1124 disable the multicast packet reception.
1125
1126 If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
1127
1128 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1129 @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
1130 @param[in] GroupAddress Pointer to the IPv4 multicast address.
1131
1132 @retval EFI_SUCCESS The operation completed successfully.
1133 @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
1134 - This is NULL.
1135 - JoinFlag is TRUE and GroupAddress is NULL.
1136 - GroupAddress is not NULL and *GroupAddress is
1137 not a multicast IPv4 address.
1138 @retval EFI_NOT_STARTED This instance has not been started.
1139 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
1140 RARP, etc.) is not finished yet.
1141 @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
1142 @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups.
1143 @retval EFI_ALREADY_STARTED The group address is already in the group table (when
1144 JoinFlag is TRUE).
1145 @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
1146 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
1147
1148 **/
1149 EFI_STATUS
1150 EFIAPI
1151 EfiIp4Groups (
1152 IN EFI_IP4_PROTOCOL *This,
1153 IN BOOLEAN JoinFlag,
1154 IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
1155 )
1156 {
1157 IP4_PROTOCOL *IpInstance;
1158 EFI_STATUS Status;
1159 EFI_TPL OldTpl;
1160 IP4_ADDR McastIp;
1161
1162 if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
1163 return EFI_INVALID_PARAMETER;
1164 }
1165
1166 if (GroupAddress != NULL) {
1167 CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
1168
1169 if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
1170 return EFI_INVALID_PARAMETER;
1171 }
1172 }
1173
1174 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1175 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1176
1177 if (IpInstance->State != IP4_STATE_CONFIGED) {
1178 Status = EFI_NOT_STARTED;
1179 goto ON_EXIT;
1180 }
1181
1182 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1183 Status = EFI_NO_MAPPING;
1184 goto ON_EXIT;
1185 }
1186
1187 Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
1188
1189 ON_EXIT:
1190 gBS->RestoreTPL (OldTpl);
1191 return Status;
1192 }
1193
1194
1195 /**
1196 Adds and deletes routing table entries.
1197
1198 The Routes() function adds a route to or deletes a route from the routing table.
1199
1200 Routes are determined by comparing the SubnetAddress with the destination IPv4
1201 address arithmetically AND-ed with the SubnetMask. The gateway address must be
1202 on the same subnet as the configured station address.
1203
1204 The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
1205 The default route matches all destination IPv4 addresses that do not match any
1206 other routes.
1207
1208 A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
1209 IP address if it can be found in the ARP cache or on the local subnet. One automatic
1210 nonroute entry will be inserted into the routing table for outgoing packets that
1211 are addressed to a local subnet (gateway address of 0.0.0.0).
1212
1213 Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
1214 IPv4 Protocol instances that use the default IPv4 address will also have copies
1215 of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
1216 copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
1217 instances. As a result, client modification to the routing table will be lost.
1218
1219 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1220 @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
1221 FALSE to add this route to the routing table. SubnetAddress
1222 and SubnetMask are used as the key to each route entry.
1223 @param[in] SubnetAddress The address of the subnet that needs to be routed.
1224 @param[in] SubnetMask The subnet mask of SubnetAddress.
1225 @param[in] GatewayAddress The unicast gateway IPv4 address for this route.
1226
1227 @retval EFI_SUCCESS The operation completed successfully.
1228 @retval EFI_NOT_STARTED The driver instance has not been started.
1229 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
1230 RARP, etc.) is not finished yet.
1231 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
1232 - This is NULL.
1233 - SubnetAddress is NULL.
1234 - SubnetMask is NULL.
1235 - GatewayAddress is NULL.
1236 - *SubnetAddress is not a valid subnet address.
1237 - *SubnetMask is not a valid subnet mask.
1238 - *GatewayAddress is not a valid unicast IPv4 address.
1239 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
1240 @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
1241 @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
1242 DeleteRoute is FALSE).
1243
1244 **/
1245 EFI_STATUS
1246 EFIAPI
1247 EfiIp4Routes (
1248 IN EFI_IP4_PROTOCOL *This,
1249 IN BOOLEAN DeleteRoute,
1250 IN EFI_IPv4_ADDRESS *SubnetAddress,
1251 IN EFI_IPv4_ADDRESS *SubnetMask,
1252 IN EFI_IPv4_ADDRESS *GatewayAddress
1253 )
1254 {
1255 IP4_PROTOCOL *IpInstance;
1256 IP4_INTERFACE *IpIf;
1257 IP4_ADDR Dest;
1258 IP4_ADDR Netmask;
1259 IP4_ADDR Nexthop;
1260 EFI_STATUS Status;
1261 EFI_TPL OldTpl;
1262
1263 //
1264 // First, validate the parameters
1265 //
1266 if ((This == NULL) || (SubnetAddress == NULL) ||
1267 (SubnetMask == NULL) || (GatewayAddress == NULL)) {
1268 return EFI_INVALID_PARAMETER;
1269 }
1270
1271 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1272 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1273
1274 if (IpInstance->State != IP4_STATE_CONFIGED) {
1275 Status = EFI_NOT_STARTED;
1276 goto ON_EXIT;
1277 }
1278
1279 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1280 Status = EFI_NO_MAPPING;
1281 goto ON_EXIT;
1282 }
1283
1284 CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
1285 CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
1286 CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
1287
1288 Dest = NTOHL (Dest);
1289 Netmask = NTOHL (Netmask);
1290 Nexthop = NTOHL (Nexthop);
1291
1292 IpIf = IpInstance->Interface;
1293
1294 if (!IP4_IS_VALID_NETMASK (Netmask)) {
1295 Status = EFI_INVALID_PARAMETER;
1296 goto ON_EXIT;
1297 }
1298
1299 //
1300 // the gateway address must be a unicast on the connected network if not zero.
1301 //
1302 if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
1303 (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
1304 IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
1305
1306 Status = EFI_INVALID_PARAMETER;
1307 goto ON_EXIT;
1308 }
1309
1310 if (DeleteRoute) {
1311 Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1312 } else {
1313 Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
1314 }
1315
1316 ON_EXIT:
1317 gBS->RestoreTPL (OldTpl);
1318 return Status;
1319 }
1320
1321
1322 /**
1323 Check whether the user's token or event has already
1324 been enqueued on IP4's list.
1325
1326 @param[in] Map The container of either user's transmit or receive
1327 token.
1328 @param[in] Item Current item to check against.
1329 @param[in] Context The Token to check againist.
1330
1331 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP.
1332 @retval EFI_SUCCESS The current item isn't the same token/event as the
1333 context.
1334
1335 **/
1336 EFI_STATUS
1337 EFIAPI
1338 Ip4TokenExist (
1339 IN NET_MAP *Map,
1340 IN NET_MAP_ITEM *Item,
1341 IN VOID *Context
1342 )
1343 {
1344 EFI_IP4_COMPLETION_TOKEN *Token;
1345 EFI_IP4_COMPLETION_TOKEN *TokenInItem;
1346
1347 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1348 TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
1349
1350 if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
1351 return EFI_ACCESS_DENIED;
1352 }
1353
1354 return EFI_SUCCESS;
1355 }
1356
1357 /**
1358 Validate the user's token against current station address.
1359
1360 @param[in] Token User's token to validate.
1361 @param[in] IpIf The IP4 child's interface.
1362 @param[in] RawData Set to TRUE to send unformatted packets.
1363
1364 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1365 @retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.
1366 @retval EFI_SUCCESS The token is valid.
1367
1368 **/
1369 EFI_STATUS
1370 Ip4TxTokenValid (
1371 IN EFI_IP4_COMPLETION_TOKEN *Token,
1372 IN IP4_INTERFACE *IpIf,
1373 IN BOOLEAN RawData
1374 )
1375 {
1376 EFI_IP4_TRANSMIT_DATA *TxData;
1377 EFI_IP4_OVERRIDE_DATA *Override;
1378 IP4_ADDR Src;
1379 IP4_ADDR Gateway;
1380 UINT32 Offset;
1381 UINT32 Index;
1382 UINT32 HeadLen;
1383
1384 if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
1385 return EFI_INVALID_PARAMETER;
1386 }
1387
1388 TxData = Token->Packet.TxData;
1389
1390 //
1391 // Check the fragment table: no empty fragment, and length isn't bogus.
1392 //
1393 if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
1394 return EFI_INVALID_PARAMETER;
1395 }
1396
1397 Offset = TxData->TotalDataLength;
1398
1399 if (Offset > IP4_MAX_PACKET_SIZE) {
1400 return EFI_BAD_BUFFER_SIZE;
1401 }
1402
1403 for (Index = 0; Index < TxData->FragmentCount; Index++) {
1404 if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
1405 (TxData->FragmentTable[Index].FragmentLength == 0)) {
1406
1407 return EFI_INVALID_PARAMETER;
1408 }
1409
1410 Offset -= TxData->FragmentTable[Index].FragmentLength;
1411 }
1412
1413 if (Offset != 0) {
1414 return EFI_INVALID_PARAMETER;
1415 }
1416
1417 //
1418 // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData
1419 // is TRUE.
1420 //
1421 if (RawData) {
1422 return EFI_SUCCESS;
1423 }
1424
1425 //
1426 // Check the IP options: no more than 40 bytes and format is OK
1427 //
1428 if (TxData->OptionsLength != 0) {
1429 if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
1430 return EFI_INVALID_PARAMETER;
1431 }
1432
1433 if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
1434 return EFI_INVALID_PARAMETER;
1435 }
1436 }
1437
1438 //
1439 // Check the source and gateway: they must be a valid unicast.
1440 // Gateway must also be on the connected network.
1441 //
1442 if (TxData->OverrideData != NULL) {
1443 Override = TxData->OverrideData;
1444
1445 CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1446 CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
1447
1448 Src = NTOHL (Src);
1449 Gateway = NTOHL (Gateway);
1450
1451 if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
1452 (Src == IP4_ALLONE_ADDRESS) ||
1453 IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
1454
1455 return EFI_INVALID_PARAMETER;
1456 }
1457
1458 //
1459 // If gateway isn't zero, it must be a unicast address, and
1460 // on the connected network.
1461 //
1462 if ((Gateway != IP4_ALLZERO_ADDRESS) &&
1463 ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
1464 !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
1465 IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
1466
1467 return EFI_INVALID_PARAMETER;
1468 }
1469 }
1470
1471 //
1472 // Check the packet length: Head length and packet length all has a limit
1473 //
1474 HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
1475
1476 if ((HeadLen > IP4_MAX_HEADLEN) ||
1477 (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
1478
1479 return EFI_BAD_BUFFER_SIZE;
1480 }
1481
1482 return EFI_SUCCESS;
1483 }
1484
1485
1486 /**
1487 The callback function for the net buffer which wraps the user's
1488 transmit token. Although it seems this function is pretty simple,
1489 there are some subtle things.
1490 When user requests the IP to transmit a packet by passing it a
1491 token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
1492 is wrapped in an net buffer. the net buffer's Free function is
1493 set to Ip4FreeTxToken. The Token and token wrap are added to the
1494 IP child's TxToken map. Then the buffer is passed to Ip4Output for
1495 transmission. If something error happened before that, the buffer
1496 is freed, which in turn will free the token wrap. The wrap may
1497 have been added to the TxToken map or not, and the user's event
1498 shouldn't be fired because we are still in the EfiIp4Transmit. If
1499 the buffer has been sent by Ip4Output, it should be removed from
1500 the TxToken map and user's event signaled. The token wrap and buffer
1501 are bound together. Check the comments in Ip4Output for information
1502 about IP fragmentation.
1503
1504 @param[in] Context The token's wrap.
1505
1506 **/
1507 VOID
1508 EFIAPI
1509 Ip4FreeTxToken (
1510 IN VOID *Context
1511 )
1512 {
1513 IP4_TXTOKEN_WRAP *Wrap;
1514 NET_MAP_ITEM *Item;
1515
1516 Wrap = (IP4_TXTOKEN_WRAP *) Context;
1517
1518 //
1519 // Signal IpSecRecycleEvent to inform IPsec free the memory
1520 //
1521 if (Wrap->IpSecRecycleSignal != NULL) {
1522 gBS->SignalEvent (Wrap->IpSecRecycleSignal);
1523 }
1524
1525 //
1526 // Find the token in the instance's map. EfiIp4Transmit put the
1527 // token to the map. If that failed, NetMapFindKey will return NULL.
1528 //
1529 Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
1530
1531 if (Item != NULL) {
1532 NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
1533 }
1534
1535 if (Wrap->Sent) {
1536 gBS->SignalEvent (Wrap->Token->Event);
1537
1538 //
1539 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
1540 //
1541 DispatchDpc ();
1542 }
1543
1544 FreePool (Wrap);
1545 }
1546
1547
1548 /**
1549 The callback function to Ip4Output to update the transmit status.
1550
1551 @param Ip4Instance The Ip4Instance that request the transmit.
1552 @param Packet The user's transmit request.
1553 @param IoStatus The result of the transmission.
1554 @param Flag Not used during transmission.
1555 @param Context The token's wrap.
1556
1557 **/
1558 VOID
1559 Ip4OnPacketSent (
1560 IP4_PROTOCOL *Ip4Instance,
1561 NET_BUF *Packet,
1562 EFI_STATUS IoStatus,
1563 UINT32 Flag,
1564 VOID *Context
1565 )
1566 {
1567 IP4_TXTOKEN_WRAP *Wrap;
1568
1569 //
1570 // This is the transmission request from upper layer,
1571 // not the IP4 driver itself.
1572 //
1573 ASSERT (Ip4Instance != NULL);
1574
1575 //
1576 // The first fragment of the packet has been sent. Update
1577 // the token's status. That is, if fragmented, the transmit's
1578 // status is the first fragment's status. The Wrap will be
1579 // release when all the fragments are release. Check the comments
1580 // in Ip4FreeTxToken and Ip4Output for information.
1581 //
1582 Wrap = (IP4_TXTOKEN_WRAP *) Context;
1583 Wrap->Token->Status = IoStatus;
1584
1585 NetbufFree (Wrap->Packet);
1586 }
1587
1588
1589 /**
1590 Places outgoing data packets into the transmit queue.
1591
1592 The Transmit() function places a sending request in the transmit queue of this
1593 EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
1594 errors occur, the event in the token will be signaled and the status is updated.
1595
1596 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1597 @param[in] Token Pointer to the transmit token.
1598
1599 @retval EFI_SUCCESS The data has been queued for transmission.
1600 @retval EFI_NOT_STARTED This instance has not been started.
1601 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
1602 RARP, etc.) is not finished yet.
1603 @retval EFI_INVALID_PARAMETER One or more pameters are invalid.
1604 @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event
1605 was already in the transmit queue.
1606 @retval EFI_NOT_READY The completion token could not be queued because the transmit
1607 queue is full.
1608 @retval EFI_NOT_FOUND Not route is found to destination address.
1609 @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
1610 @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
1611 short to transmit.
1612 @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is
1613 greater than MTU (or greater than the maximum packet size if
1614 Token.Packet.TxData.OverrideData.
1615 DoNotFragment is TRUE).
1616
1617 **/
1618 EFI_STATUS
1619 EFIAPI
1620 EfiIp4Transmit (
1621 IN EFI_IP4_PROTOCOL *This,
1622 IN EFI_IP4_COMPLETION_TOKEN *Token
1623 )
1624 {
1625 IP4_SERVICE *IpSb;
1626 IP4_PROTOCOL *IpInstance;
1627 IP4_INTERFACE *IpIf;
1628 IP4_TXTOKEN_WRAP *Wrap;
1629 EFI_IP4_TRANSMIT_DATA *TxData;
1630 EFI_IP4_CONFIG_DATA *Config;
1631 EFI_IP4_OVERRIDE_DATA *Override;
1632 IP4_HEAD Head;
1633 IP4_ADDR GateWay;
1634 EFI_STATUS Status;
1635 EFI_TPL OldTpl;
1636 BOOLEAN DontFragment;
1637 UINT32 HeadLen;
1638 UINT8 RawHdrLen;
1639 UINT32 OptionsLength;
1640 UINT8 *OptionsBuffer;
1641 VOID *FirstFragment;
1642
1643 if (This == NULL) {
1644 return EFI_INVALID_PARAMETER;
1645 }
1646
1647 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1648
1649 if (IpInstance->State != IP4_STATE_CONFIGED) {
1650 return EFI_NOT_STARTED;
1651 }
1652
1653 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1654
1655 IpSb = IpInstance->Service;
1656 IpIf = IpInstance->Interface;
1657 Config = &IpInstance->ConfigData;
1658
1659 if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
1660 Status = EFI_NO_MAPPING;
1661 goto ON_EXIT;
1662 }
1663
1664 //
1665 // make sure that token is properly formated
1666 //
1667 Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);
1668
1669 if (EFI_ERROR (Status)) {
1670 goto ON_EXIT;
1671 }
1672
1673 //
1674 // Check whether the token or signal already existed.
1675 //
1676 if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
1677 Status = EFI_ACCESS_DENIED;
1678 goto ON_EXIT;
1679 }
1680
1681 //
1682 // Build the IP header, need to fill in the Tos, TotalLen, Id,
1683 // fragment, Ttl, protocol, Src, and Dst.
1684 //
1685 TxData = Token->Packet.TxData;
1686
1687 FirstFragment = NULL;
1688
1689 if (Config->RawData) {
1690 //
1691 // When RawData is TRUE, first buffer in FragmentTable points to a raw
1692 // IPv4 fragment including IPv4 header and options.
1693 //
1694 FirstFragment = TxData->FragmentTable[0].FragmentBuffer;
1695 CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));
1696
1697 RawHdrLen = (UINT8) (RawHdrLen & 0x0f);
1698 if (RawHdrLen < 5) {
1699 Status = EFI_INVALID_PARAMETER;
1700 goto ON_EXIT;
1701 }
1702
1703 RawHdrLen = (UINT8) (RawHdrLen << 2);
1704
1705 CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);
1706
1707 Ip4NtohHead (&Head);
1708 HeadLen = 0;
1709 DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);
1710
1711 if (!DontFragment) {
1712 Status = EFI_INVALID_PARAMETER;
1713 goto ON_EXIT;
1714 }
1715
1716 GateWay = IP4_ALLZERO_ADDRESS;
1717
1718 //
1719 // Get IPv4 options from first fragment.
1720 //
1721 if (RawHdrLen == IP4_MIN_HEADLEN) {
1722 OptionsLength = 0;
1723 OptionsBuffer = NULL;
1724 } else {
1725 OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;
1726 OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;
1727 }
1728
1729 //
1730 // Trim off IPv4 header and options from first fragment.
1731 //
1732 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;
1733 TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;
1734 } else {
1735 CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
1736 Head.Dst = NTOHL (Head.Dst);
1737
1738 if (TxData->OverrideData != NULL) {
1739 Override = TxData->OverrideData;
1740 Head.Protocol = Override->Protocol;
1741 Head.Tos = Override->TypeOfService;
1742 Head.Ttl = Override->TimeToLive;
1743 DontFragment = Override->DoNotFragment;
1744
1745 CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
1746 CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
1747
1748 Head.Src = NTOHL (Head.Src);
1749 GateWay = NTOHL (GateWay);
1750 } else {
1751 Head.Src = IpIf->Ip;
1752 GateWay = IP4_ALLZERO_ADDRESS;
1753 Head.Protocol = Config->DefaultProtocol;
1754 Head.Tos = Config->TypeOfService;
1755 Head.Ttl = Config->TimeToLive;
1756 DontFragment = Config->DoNotFragment;
1757 }
1758
1759 Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
1760 HeadLen = (TxData->OptionsLength + 3) & (~0x03);
1761
1762 OptionsLength = TxData->OptionsLength;
1763 OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);
1764 }
1765
1766 //
1767 // If don't fragment and fragment needed, return error
1768 //
1769 if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {
1770 Status = EFI_BAD_BUFFER_SIZE;
1771 goto ON_EXIT;
1772 }
1773
1774 //
1775 // OK, it survives all the validation check. Wrap the token in
1776 // a IP4_TXTOKEN_WRAP and the data in a netbuf
1777 //
1778 Status = EFI_OUT_OF_RESOURCES;
1779 Wrap = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));
1780 if (Wrap == NULL) {
1781 goto ON_EXIT;
1782 }
1783
1784 Wrap->IpInstance = IpInstance;
1785 Wrap->Token = Token;
1786 Wrap->Sent = FALSE;
1787 Wrap->Life = IP4_US_TO_SEC (Config->TransmitTimeout);
1788 Wrap->Packet = NetbufFromExt (
1789 (NET_FRAGMENT *) TxData->FragmentTable,
1790 TxData->FragmentCount,
1791 IP4_MAX_HEADLEN,
1792 0,
1793 Ip4FreeTxToken,
1794 Wrap
1795 );
1796
1797 if (Wrap->Packet == NULL) {
1798 FreePool (Wrap);
1799 goto ON_EXIT;
1800 }
1801
1802 Token->Status = EFI_NOT_READY;
1803
1804 if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
1805 //
1806 // NetbufFree will call Ip4FreeTxToken, which in turn will
1807 // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
1808 // enqueued.
1809 //
1810 if (Config->RawData) {
1811 //
1812 // Restore pointer of first fragment in RawData mode.
1813 //
1814 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1815 }
1816
1817 NetbufFree (Wrap->Packet);
1818 goto ON_EXIT;
1819 }
1820
1821 //
1822 // Mark the packet sent before output it. Mark it not sent again if the
1823 // returned status is not EFI_SUCCESS;
1824 //
1825 Wrap->Sent = TRUE;
1826
1827 Status = Ip4Output (
1828 IpSb,
1829 IpInstance,
1830 Wrap->Packet,
1831 &Head,
1832 OptionsBuffer,
1833 OptionsLength,
1834 GateWay,
1835 Ip4OnPacketSent,
1836 Wrap
1837 );
1838
1839 if (EFI_ERROR (Status)) {
1840 Wrap->Sent = FALSE;
1841
1842 if (Config->RawData) {
1843 //
1844 // Restore pointer of first fragment in RawData mode.
1845 //
1846 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1847 }
1848
1849 NetbufFree (Wrap->Packet);
1850 }
1851
1852 if (Config->RawData) {
1853 //
1854 // Restore pointer of first fragment in RawData mode.
1855 //
1856 TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
1857 }
1858
1859 ON_EXIT:
1860 gBS->RestoreTPL (OldTpl);
1861 return Status;
1862 }
1863
1864
1865 /**
1866 Places a receiving request into the receiving queue.
1867
1868 The Receive() function places a completion token into the receive packet queue.
1869 This function is always asynchronous.
1870
1871 The Token.Event field in the completion token must be filled in by the caller
1872 and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
1873 driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
1874 is signaled.
1875
1876 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
1877 @param[in] Token Pointer to a token that is associated with the receive data descriptor.
1878
1879 @retval EFI_SUCCESS The receive completion token was cached.
1880 @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
1881 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
1882 is not finished yet.
1883 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
1884 - This is NULL.
1885 - Token is NULL.
1886 - Token.Event is NULL.
1887 @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
1888 resources (usually memory).
1889 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
1890 The EFI IPv4 Protocol instance has been reset to startup defaults.
1891 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
1892 in the receive queue.
1893 @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
1894 @retval EFI_ICMP_ERROR An ICMP error packet was received.
1895
1896 **/
1897 EFI_STATUS
1898 EFIAPI
1899 EfiIp4Receive (
1900 IN EFI_IP4_PROTOCOL *This,
1901 IN EFI_IP4_COMPLETION_TOKEN *Token
1902 )
1903 {
1904 IP4_PROTOCOL *IpInstance;
1905 EFI_STATUS Status;
1906 EFI_TPL OldTpl;
1907
1908 //
1909 // First validate the parameters
1910 //
1911 if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
1912 return EFI_INVALID_PARAMETER;
1913 }
1914
1915 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
1916
1917 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1918
1919 if (IpInstance->State != IP4_STATE_CONFIGED) {
1920 Status = EFI_NOT_STARTED;
1921 goto ON_EXIT;
1922 }
1923
1924 //
1925 // Check whether the toke is already on the receive queue.
1926 //
1927 Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
1928
1929 if (EFI_ERROR (Status)) {
1930 Status = EFI_ACCESS_DENIED;
1931 goto ON_EXIT;
1932 }
1933
1934 //
1935 // Queue the token then check whether there is pending received packet.
1936 //
1937 Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
1938
1939 if (EFI_ERROR (Status)) {
1940 goto ON_EXIT;
1941 }
1942
1943 Status = Ip4InstanceDeliverPacket (IpInstance);
1944
1945 //
1946 // Dispatch the DPC queued by the NotifyFunction of this instane's receive
1947 // event.
1948 //
1949 DispatchDpc ();
1950
1951 ON_EXIT:
1952 gBS->RestoreTPL (OldTpl);
1953 return Status;
1954 }
1955
1956
1957 /**
1958 Cancel the transmitted but not recycled packet. If a matching
1959 token is found, it will call Ip4CancelPacket to cancel the
1960 packet. Ip4CancelPacket will cancel all the fragments of the
1961 packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
1962 will be deleted from the Map, and user's event signalled.
1963 Because Ip4CancelPacket and other functions are all called in
1964 line, so, after Ip4CancelPacket returns, the Item has been freed.
1965
1966 @param[in] Map The IP4 child's transmit queue.
1967 @param[in] Item The current transmitted packet to test.
1968 @param[in] Context The user's token to cancel.
1969
1970 @retval EFI_SUCCESS Continue to check the next Item.
1971 @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.
1972
1973 **/
1974 EFI_STATUS
1975 EFIAPI
1976 Ip4CancelTxTokens (
1977 IN NET_MAP *Map,
1978 IN NET_MAP_ITEM *Item,
1979 IN VOID *Context
1980 )
1981 {
1982 EFI_IP4_COMPLETION_TOKEN *Token;
1983 IP4_TXTOKEN_WRAP *Wrap;
1984
1985 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
1986
1987 //
1988 // Return EFI_SUCCESS to check the next item in the map if
1989 // this one doesn't match.
1990 //
1991 if ((Token != NULL) && (Token != Item->Key)) {
1992 return EFI_SUCCESS;
1993 }
1994
1995 Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
1996 ASSERT (Wrap != NULL);
1997
1998 //
1999 // Don't access the Item, Wrap and Token's members after this point.
2000 // Item and wrap has been freed. And we no longer own the Token.
2001 //
2002 Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
2003
2004 //
2005 // If only one item is to be cancel, return EFI_ABORTED to stop
2006 // iterating the map any more.
2007 //
2008 if (Token != NULL) {
2009 return EFI_ABORTED;
2010 }
2011
2012 return EFI_SUCCESS;
2013 }
2014
2015
2016 /**
2017 Cancel the receive request. This is quiet simple, because
2018 it is only enqueued in our local receive map.
2019
2020 @param[in] Map The IP4 child's receive queue.
2021 @param[in] Item Current receive request to cancel.
2022 @param[in] Context The user's token to cancel.
2023
2024 @retval EFI_SUCCESS Continue to check the next receive request on the
2025 queue.
2026 @retval EFI_ABORTED The user's token (token != NULL) has been
2027 cancelled.
2028
2029 **/
2030 EFI_STATUS
2031 EFIAPI
2032 Ip4CancelRxTokens (
2033 IN NET_MAP *Map,
2034 IN NET_MAP_ITEM *Item,
2035 IN VOID *Context
2036 )
2037 {
2038 EFI_IP4_COMPLETION_TOKEN *Token;
2039 EFI_IP4_COMPLETION_TOKEN *This;
2040
2041 Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
2042 This = Item->Key;
2043
2044 if ((Token != NULL) && (Token != This)) {
2045 return EFI_SUCCESS;
2046 }
2047
2048 NetMapRemoveItem (Map, Item, NULL);
2049
2050 This->Status = EFI_ABORTED;
2051 This->Packet.RxData = NULL;
2052 gBS->SignalEvent (This->Event);
2053
2054 if (Token != NULL) {
2055 return EFI_ABORTED;
2056 }
2057
2058 return EFI_SUCCESS;
2059 }
2060
2061
2062 /**
2063 Cancel the user's receive/transmit request.
2064
2065 @param[in] IpInstance The IP4 child.
2066 @param[in] Token The token to cancel. If NULL, all token will be
2067 cancelled.
2068
2069 @retval EFI_SUCCESS The token is cancelled.
2070 @retval EFI_NOT_FOUND The token isn't found on either the
2071 transmit/receive queue.
2072 @retval EFI_DEVICE_ERROR Not all token is cancelled when Token is NULL.
2073
2074 **/
2075 EFI_STATUS
2076 Ip4Cancel (
2077 IN IP4_PROTOCOL *IpInstance,
2078 IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
2079 )
2080 {
2081 EFI_STATUS Status;
2082
2083 //
2084 // First check the transmitted packet. Ip4CancelTxTokens returns
2085 // EFI_ABORTED to mean that the token has been cancelled when
2086 // token != NULL. So, return EFI_SUCCESS for this condition.
2087 //
2088 Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
2089
2090 if (EFI_ERROR (Status)) {
2091 if ((Token != NULL) && (Status == EFI_ABORTED)) {
2092 return EFI_SUCCESS;
2093 }
2094
2095 return Status;
2096 }
2097
2098 //
2099 // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
2100 // for Token!=NULL and it is cancelled.
2101 //
2102 Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
2103 //
2104 // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
2105 // events.
2106 //
2107 DispatchDpc ();
2108 if (EFI_ERROR (Status)) {
2109 if ((Token != NULL) && (Status == EFI_ABORTED)) {
2110 return EFI_SUCCESS;
2111 }
2112
2113 return Status;
2114 }
2115
2116 //
2117 // OK, if the Token is found when Token != NULL, the NetMapIterate
2118 // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
2119 //
2120 if (Token != NULL) {
2121 return EFI_NOT_FOUND;
2122 }
2123
2124 //
2125 // If Token == NULL, cancel all the tokens. return error if no
2126 // all of them are cancelled.
2127 //
2128 if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
2129 !NetMapIsEmpty (&IpInstance->RxTokens)) {
2130
2131 return EFI_DEVICE_ERROR;
2132 }
2133
2134 return EFI_SUCCESS;
2135 }
2136
2137
2138 /**
2139 Abort an asynchronous transmit or receive request.
2140
2141 The Cancel() function is used to abort a pending transmit or receive request.
2142 If the token is in the transmit or receive request queues, after calling this
2143 function, Token->Status will be set to EFI_ABORTED and then Token->Event will
2144 be signaled. If the token is not in one of the queues, which usually means the
2145 asynchronous operation has completed, this function will not signal the token
2146 and EFI_NOT_FOUND is returned.
2147
2148 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
2149 @param[in] Token Pointer to a token that has been issued by
2150 EFI_IP4_PROTOCOL.Transmit() or
2151 EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
2152 tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
2153 defined in EFI_IP4_PROTOCOL.Transmit().
2154
2155 @retval EFI_SUCCESS The asynchronous I/O request was aborted and
2156 Token.->Event was signaled. When Token is NULL, all
2157 pending requests were aborted and their events were signaled.
2158 @retval EFI_INVALID_PARAMETER This is NULL.
2159 @retval EFI_NOT_STARTED This instance has not been started.
2160 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
2161 RARP, etc.) is not finished yet.
2162 @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
2163 not found in the transmit or receive queue. It has either completed
2164 or was not issued by Transmit() and Receive().
2165
2166 **/
2167 EFI_STATUS
2168 EFIAPI
2169 EfiIp4Cancel (
2170 IN EFI_IP4_PROTOCOL *This,
2171 IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
2172 )
2173 {
2174 IP4_PROTOCOL *IpInstance;
2175 EFI_STATUS Status;
2176 EFI_TPL OldTpl;
2177
2178 if (This == NULL) {
2179 return EFI_INVALID_PARAMETER;
2180 }
2181
2182 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
2183
2184 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2185
2186 if (IpInstance->State != IP4_STATE_CONFIGED) {
2187 Status = EFI_NOT_STARTED;
2188 goto ON_EXIT;
2189 }
2190
2191 if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
2192 Status = EFI_NO_MAPPING;
2193 goto ON_EXIT;
2194 }
2195
2196 Status = Ip4Cancel (IpInstance, Token);
2197
2198 ON_EXIT:
2199 gBS->RestoreTPL (OldTpl);
2200 return Status;
2201 }
2202
2203
2204 /**
2205 Polls for incoming data packets and processes outgoing data packets.
2206
2207 The Poll() function polls for incoming data packets and processes outgoing data
2208 packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
2209 function to increase the rate that data packets are moved between the communications
2210 device and the transmit and receive queues.
2211
2212 In some systems the periodic timer event may not poll the underlying communications
2213 device fast enough to transmit and/or receive all data packets without missing
2214 incoming packets or dropping outgoing packets. Drivers and applications that are
2215 experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
2216 more often.
2217
2218 @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
2219
2220 @retval EFI_SUCCESS Incoming or outgoing data was processed.
2221 @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
2222 @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
2223 RARP, etc.) is not finished yet.
2224 @retval EFI_INVALID_PARAMETER This is NULL.
2225 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
2226 @retval EFI_NOT_READY No incoming or outgoing data is processed.
2227 @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
2228 Consider increasing the polling rate.
2229
2230 **/
2231 EFI_STATUS
2232 EFIAPI
2233 EfiIp4Poll (
2234 IN EFI_IP4_PROTOCOL *This
2235 )
2236 {
2237 IP4_PROTOCOL *IpInstance;
2238 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
2239
2240 if (This == NULL) {
2241 return EFI_INVALID_PARAMETER;
2242 }
2243
2244 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
2245
2246 if (IpInstance->State == IP4_STATE_UNCONFIGED) {
2247 return EFI_NOT_STARTED;
2248 }
2249
2250 Mnp = IpInstance->Service->Mnp;
2251
2252 //
2253 // Don't lock the Poll function to enable the deliver of
2254 // the packet polled up.
2255 //
2256 return Mnp->Poll (Mnp);
2257 }
2258
2259 /**
2260 Decrease the life of the transmitted packets. If it is
2261 decreased to zero, cancel the packet. This function is
2262 called by Ip4PacketTimerTicking which time out both the
2263 received-but-not-delivered and transmitted-but-not-recycle
2264 packets.
2265
2266 @param[in] Map The IP4 child's transmit map.
2267 @param[in] Item Current transmitted packet.
2268 @param[in] Context Not used.
2269
2270 @retval EFI_SUCCESS Always returns EFI_SUCCESS.
2271
2272 **/
2273 EFI_STATUS
2274 EFIAPI
2275 Ip4SentPacketTicking (
2276 IN NET_MAP *Map,
2277 IN NET_MAP_ITEM *Item,
2278 IN VOID *Context
2279 )
2280 {
2281 IP4_TXTOKEN_WRAP *Wrap;
2282
2283 Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
2284 ASSERT (Wrap != NULL);
2285
2286 if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
2287 Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
2288 }
2289
2290 return EFI_SUCCESS;
2291 }
2292
2293
2294 /**
2295 The heart beat timer of IP4 service instance. It times out
2296 all of its IP4 children's received-but-not-delivered and
2297 transmitted-but-not-recycle packets, and provides time input
2298 for its IGMP protocol.
2299
2300 @param[in] Event The IP4 service instance's heart beat timer.
2301 @param[in] Context The IP4 service instance.
2302
2303 **/
2304 VOID
2305 EFIAPI
2306 Ip4TimerTicking (
2307 IN EFI_EVENT Event,
2308 IN VOID *Context
2309 )
2310 {
2311 IP4_SERVICE *IpSb;
2312
2313 IpSb = (IP4_SERVICE *) Context;
2314 NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
2315
2316 Ip4PacketTimerTicking (IpSb);
2317 Ip4IgmpTicking (IpSb);
2318 }