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