• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2     Implementation of managing the multicast receive filters of a network
3     interface.
4 
5 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials are licensed and made available under the
7 terms and conditions of the BSD License which accompanies this distribution. The
8 full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 
17 
18 #include "Snp.h"
19 
20 /**
21   Call undi to enable the receive filters.
22 
23   @param  Snp                Pointer to snp driver structure.
24   @param  EnableFlags        Bit mask for enabling the receive filters.
25   @param  MCastAddressCount  Multicast address count for a new multicast address
26                              list.
27   @param  MCastAddressList   List of new multicast addresses.
28 
29   @retval EFI_SUCCESS           The multicast receive filter list was updated.
30   @retval EFI_INVALID_PARAMETER Invalid UNDI command.
31   @retval EFI_UNSUPPORTED       Command is not supported by UNDI.
32   @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
33 
34 **/
35 EFI_STATUS
PxeRecvFilterEnable(SNP_DRIVER * Snp,UINT32 EnableFlags,UINTN MCastAddressCount,EFI_MAC_ADDRESS * MCastAddressList)36 PxeRecvFilterEnable (
37   SNP_DRIVER      *Snp,
38   UINT32          EnableFlags,
39   UINTN           MCastAddressCount,
40   EFI_MAC_ADDRESS *MCastAddressList
41   )
42 {
43   Snp->Cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;
44   Snp->Cdb.OpFlags    = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;
45   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
46   Snp->Cdb.DBsize     = PXE_DBSIZE_NOT_USED;
47   Snp->Cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;
48   Snp->Cdb.DBaddr     = PXE_DBADDR_NOT_USED;
49   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
50   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
51   Snp->Cdb.IFnum      = Snp->IfNum;
52   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
53 
54   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
55     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
56   }
57 
58   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
59     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
60   }
61 
62   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
63     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
64   }
65 
66   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
67     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
68   }
69 
70   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
71     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
72   }
73 
74   if (MCastAddressCount != 0) {
75     Snp->Cdb.CPBsize  = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));
76     Snp->Cdb.CPBaddr  = (UINT64)(UINTN)Snp->Cpb;
77     CopyMem (Snp->Cpb, MCastAddressList, Snp->Cdb.CPBsize);
78   }
79   //
80   // Issue UNDI command and check result.
81   //
82   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));
83 
84   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
85 
86   if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
87     //
88     // UNDI command failed.  Return UNDI status to caller.
89     //
90     DEBUG (
91       (EFI_D_ERROR,
92       "\nsnp->undi.receive_filters()  %xh:%xh\n",
93       Snp->Cdb.StatFlags,
94       Snp->Cdb.StatCode)
95       );
96 
97     switch (Snp->Cdb.StatCode) {
98     case PXE_STATCODE_INVALID_CDB:
99     case PXE_STATCODE_INVALID_CPB:
100     case PXE_STATCODE_INVALID_PARAMETER:
101       return EFI_INVALID_PARAMETER;
102 
103     case PXE_STATCODE_UNSUPPORTED:
104       return EFI_UNSUPPORTED;
105     }
106 
107     return EFI_DEVICE_ERROR;
108   }
109 
110   return EFI_SUCCESS;
111 }
112 
113 /**
114   Call undi to disable the receive filters.
115 
116   @param  Snp             Pointer to snp driver structure
117   @param  DisableFlags    Bit mask for disabling the receive filters
118   @param  ResetMCastList  Boolean flag to reset/delete the multicast filter
119                           list.
120 
121   @retval EFI_SUCCESS           The multicast receive filter list was updated.
122   @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
123 
124 **/
125 EFI_STATUS
PxeRecvFilterDisable(SNP_DRIVER * Snp,UINT32 DisableFlags,BOOLEAN ResetMCastList)126 PxeRecvFilterDisable (
127   SNP_DRIVER *Snp,
128   UINT32     DisableFlags,
129   BOOLEAN    ResetMCastList
130   )
131 {
132   Snp->Cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;
133   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
134   Snp->Cdb.DBsize     = PXE_DBSIZE_NOT_USED;
135   Snp->Cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;
136   Snp->Cdb.DBaddr     = PXE_DBADDR_NOT_USED;
137   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
138   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
139   Snp->Cdb.IFnum      = Snp->IfNum;
140   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
141 
142   Snp->Cdb.OpFlags    = (UINT16) ((DisableFlags != 0) ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);
143 
144   if (ResetMCastList) {
145     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;
146   }
147 
148   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
149     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
150   }
151 
152   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
153     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
154   }
155 
156   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
157     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
158   }
159 
160   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
161     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
162   }
163 
164   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
165     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
166   }
167   //
168   // Issue UNDI command and check result.
169   //
170   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));
171 
172   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
173 
174   if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
175     //
176     // UNDI command failed.  Return UNDI status to caller.
177     //
178     DEBUG (
179       (EFI_D_ERROR,
180       "\nsnp->undi.receive_filters()  %xh:%xh\n",
181       Snp->Cdb.StatFlags,
182       Snp->Cdb.StatCode)
183       );
184 
185     return EFI_DEVICE_ERROR;
186   }
187 
188   return EFI_SUCCESS;
189 }
190 
191 /**
192   Call undi to read the receive filters.
193 
194   @param  Snp                Pointer to snp driver structure.
195 
196   @retval EFI_SUCCESS           The receive filter was read.
197   @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
198 
199 **/
200 EFI_STATUS
PxeRecvFilterRead(SNP_DRIVER * Snp)201 PxeRecvFilterRead (
202   SNP_DRIVER *Snp
203   )
204 {
205   Snp->Cdb.OpCode   = PXE_OPCODE_RECEIVE_FILTERS;
206   Snp->Cdb.OpFlags  = PXE_OPFLAGS_RECEIVE_FILTER_READ;
207   Snp->Cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;
208   Snp->Cdb.DBsize   = (UINT16) (Snp->Mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));
209   Snp->Cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;
210   if (Snp->Cdb.DBsize == 0) {
211     Snp->Cdb.DBaddr = (UINT64)(UINTN) NULL;
212   } else {
213     Snp->Cdb.DBaddr = (UINT64)(UINTN) Snp->Db;
214     ZeroMem (Snp->Db, Snp->Cdb.DBsize);
215   }
216 
217   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
218   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
219   Snp->Cdb.IFnum      = Snp->IfNum;
220   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
221 
222   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));
223 
224   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
225 
226   if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
227     //
228     // UNDI command failed.  Return UNDI status to caller.
229     //
230     DEBUG (
231       (EFI_D_ERROR,
232       "\nsnp->undi.receive_filters()  %xh:%xh\n",
233       Snp->Cdb.StatFlags,
234       Snp->Cdb.StatCode)
235       );
236 
237     return EFI_DEVICE_ERROR;
238   }
239   //
240   // Convert UNDI32 StatFlags to EFI SNP filter flags.
241   //
242   Snp->Mode.ReceiveFilterSetting = 0;
243 
244   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {
245     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
246   }
247 
248   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {
249     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
250   }
251 
252   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {
253     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
254   }
255 
256   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {
257     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
258   }
259 
260   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
261     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
262   }
263 
264   CopyMem (Snp->Mode.MCastFilter, Snp->Db, Snp->Cdb.DBsize);
265 
266   //
267   // Count number of active entries in multicast filter list.
268   //
269   {
270     EFI_MAC_ADDRESS ZeroMacAddr;
271 
272     SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);
273 
274     for (Snp->Mode.MCastFilterCount = 0;
275          Snp->Mode.MCastFilterCount < Snp->Mode.MaxMCastFilterCount;
276          Snp->Mode.MCastFilterCount++
277         ) {
278       if (CompareMem (
279             &Snp->Mode.MCastFilter[Snp->Mode.MCastFilterCount],
280             &ZeroMacAddr,
281             sizeof ZeroMacAddr
282             ) == 0) {
283         break;
284       }
285     }
286   }
287 
288   return EFI_SUCCESS;
289 }
290 
291 
292 /**
293   Manages the multicast receive filters of a network interface.
294 
295   This function is used enable and disable the hardware and software receive
296   filters for the underlying network device.
297   The receive filter change is broken down into three steps:
298   * The filter mask bits that are set (ON) in the Enable parameter are added to
299     the current receive filter settings.
300   * The filter mask bits that are set (ON) in the Disable parameter are subtracted
301     from the updated receive filter settings.
302   * If the resulting receive filter setting is not supported by the hardware a
303     more liberal setting is selected.
304   If the same bits are set in the Enable and Disable parameters, then the bits
305   in the Disable parameter takes precedence.
306   If the ResetMCastFilter parameter is TRUE, then the multicast address list
307   filter is disabled (irregardless of what other multicast bits are set in the
308   Enable and Disable parameters). The SNP->Mode->MCastFilterCount field is set
309   to zero. The Snp->Mode->MCastFilter contents are undefined.
310   After enabling or disabling receive filter settings, software should verify
311   the new settings by checking the Snp->Mode->ReceiveFilterSettings,
312   Snp->Mode->MCastFilterCount and Snp->Mode->MCastFilter fields.
313   Note: Some network drivers and/or devices will automatically promote receive
314     filter settings if the requested setting can not be honored. For example, if
315     a request for four multicast addresses is made and the underlying hardware
316     only supports two multicast addresses the driver might set the promiscuous
317     or promiscuous multicast receive filters instead. The receiving software is
318     responsible for discarding any extra packets that get through the hardware
319     receive filters.
320     Note: Note: To disable all receive filter hardware, the network driver must
321       be Shutdown() and Stopped(). Calling ReceiveFilters() with Disable set to
322       Snp->Mode->ReceiveFilterSettings will make it so no more packets are
323       returned by the Receive() function, but the receive hardware may still be
324       moving packets into system memory before inspecting and discarding them.
325       Unexpected system errors, reboots and hangs can occur if an OS is loaded
326       and the network devices are not Shutdown() and Stopped().
327   If ResetMCastFilter is TRUE, then the multicast receive filter list on the
328   network interface will be reset to the default multicast receive filter list.
329   If ResetMCastFilter is FALSE, and this network interface allows the multicast
330   receive filter list to be modified, then the MCastFilterCnt and MCastFilter
331   are used to update the current multicast receive filter list. The modified
332   receive filter list settings can be found in the MCastFilter field of
333   EFI_SIMPLE_NETWORK_MODE. If the network interface does not allow the multicast
334   receive filter list to be modified, then EFI_INVALID_PARAMETER will be returned.
335   If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
336   If the receive filter mask and multicast receive filter list have been
337   successfully updated on the network interface, EFI_SUCCESS will be returned.
338 
339   @param This             A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
340   @param Enable           A bit mask of receive filters to enable on the network
341                           interface.
342   @param Disable          A bit mask of receive filters to disable on the network
343                           interface. For backward compatibility with EFI 1.1
344                           platforms, the EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit
345                           must be set when the ResetMCastFilter parameter is TRUE.
346   @param ResetMCastFilter Set to TRUE to reset the contents of the multicast
347                           receive filters on the network interface to their
348                           default values.
349   @param MCastFilterCnt   Number of multicast HW MAC addresses in the new MCastFilter
350                           list. This value must be less than or equal to the
351                           MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE.
352                           This field is optional if ResetMCastFilter is TRUE.
353   @param MCastFilter      A pointer to a list of new multicast receive filter HW
354                           MAC addresses. This list will replace any existing
355                           multicast HW MAC address list. This field is optional
356                           if ResetMCastFilter is TRUE.
357 
358   @retval EFI_SUCCESS            The multicast receive filter list was updated.
359   @retval EFI_NOT_STARTED        The network interface has not been started.
360   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
361                                  * This is NULL
362                                  * There are bits set in Enable that are not set
363                                    in Snp->Mode->ReceiveFilterMask
364                                  * There are bits set in Disable that are not set
365                                    in Snp->Mode->ReceiveFilterMask
366                                  * Multicast is being enabled (the
367                                    EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is
368                                    set in Enable, it is not set in Disable, and
369                                    ResetMCastFilter is FALSE) and MCastFilterCount
370                                    is zero
371                                  * Multicast is being enabled and MCastFilterCount
372                                    is greater than Snp->Mode->MaxMCastFilterCount
373                                  * Multicast is being enabled and MCastFilter is NULL
374                                  * Multicast is being enabled and one or more of
375                                    the addresses in the MCastFilter list are not
376                                    valid multicast MAC addresses
377   @retval EFI_DEVICE_ERROR       One or more of the following conditions is TRUE:
378                                  * The network interface has been started but has
379                                    not been initialized
380                                  * An unexpected error was returned by the
381                                    underlying network driver or device
382   @retval EFI_UNSUPPORTED        This function is not supported by the network
383                                  interface.
384 
385 **/
386 EFI_STATUS
387 EFIAPI
SnpUndi32ReceiveFilters(IN EFI_SIMPLE_NETWORK_PROTOCOL * This,IN UINT32 Enable,IN UINT32 Disable,IN BOOLEAN ResetMCastFilter,IN UINTN MCastFilterCnt,OPTIONAL IN EFI_MAC_ADDRESS * MCastFilter OPTIONAL)388 SnpUndi32ReceiveFilters (
389   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
390   IN UINT32                      Enable,
391   IN UINT32                      Disable,
392   IN BOOLEAN                     ResetMCastFilter,
393   IN UINTN                       MCastFilterCnt,  OPTIONAL
394   IN EFI_MAC_ADDRESS             *MCastFilter     OPTIONAL
395   )
396 {
397   SNP_DRIVER  *Snp;
398   EFI_STATUS  Status;
399   EFI_TPL     OldTpl;
400 
401   if (This == NULL) {
402     return EFI_INVALID_PARAMETER;
403   }
404 
405   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
406 
407   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
408 
409   switch (Snp->Mode.State) {
410   case EfiSimpleNetworkInitialized:
411     break;
412 
413   case EfiSimpleNetworkStopped:
414     Status = EFI_NOT_STARTED;
415     goto ON_EXIT;
416 
417   default:
418     Status = EFI_DEVICE_ERROR;
419     goto ON_EXIT;
420   }
421   //
422   // check if we are asked to enable or disable something that the UNDI
423   // does not even support!
424   //
425   if (((Enable &~Snp->Mode.ReceiveFilterMask) != 0) ||
426     ((Disable &~Snp->Mode.ReceiveFilterMask) != 0)) {
427     Status = EFI_INVALID_PARAMETER;
428     goto ON_EXIT;
429   }
430 
431   if (ResetMCastFilter) {
432 
433     Disable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & Snp->Mode.ReceiveFilterMask;
434     MCastFilterCnt = 0;
435     MCastFilter    = NULL;
436   } else {
437     if (MCastFilterCnt != 0) {
438       if ((MCastFilterCnt > Snp->Mode.MaxMCastFilterCount) ||
439           (MCastFilter == NULL)) {
440 
441         Status = EFI_INVALID_PARAMETER;
442         goto ON_EXIT;
443       }
444     }
445   }
446 
447   if (Enable == 0 && Disable == 0 && !ResetMCastFilter && MCastFilterCnt == 0) {
448     Status = EFI_SUCCESS;
449     goto ON_EXIT;
450   }
451 
452   if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {
453     Status = EFI_INVALID_PARAMETER;
454     goto ON_EXIT;
455   }
456 
457   if ((Enable != 0) || (MCastFilterCnt != 0)) {
458     Status = PxeRecvFilterEnable (
459                Snp,
460                Enable,
461                MCastFilterCnt,
462                MCastFilter
463                );
464 
465     if (EFI_ERROR (Status)) {
466       goto ON_EXIT;
467     }
468   }
469 
470   if ((Disable != 0) || ResetMCastFilter) {
471     Status = PxeRecvFilterDisable (Snp, Disable, ResetMCastFilter);
472 
473     if (EFI_ERROR (Status)) {
474       goto ON_EXIT;
475     }
476   }
477 
478   Status = PxeRecvFilterRead (Snp);
479 
480 ON_EXIT:
481   gBS->RestoreTPL (OldTpl);
482 
483   return Status;
484 }
485