343b516d9e09d2b9ae8d7b71b8f9bb8b03a24a7a
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Receive_filters.c
1 /** @file\r
2 Copyright (c) 2004 - 2007, Intel Corporation\r
3 All rights reserved. This program and the accompanying materials\r
4 are licensed and made available under the terms and conditions of the BSD License\r
5 which accompanies this distribution.  The full text of the license may be found at\r
6 http://opensource.org/licenses/bsd-license.php\r
7 \r
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
10 \r
11 Module name:\r
12   receive_filters.c\r
13 \r
14 Abstract:\r
15 \r
16 Revision history:\r
17   2000-Feb-17 M(f)J   Genesis.\r
18 \r
19 **/\r
20 \r
21 \r
22 \r
23 #include "Snp.h"\r
24 \r
25 /**\r
26   this routine calls undi to enable the receive filters.\r
27 \r
28   @param  snp                pointer to snp driver structure\r
29   @param  EnableFlags        bit mask for enabling the receive filters\r
30   @param  MCastAddressCount  multicast address count for a new multicast address\r
31                              list\r
32   @param  MCastAddressList   list of new multicast addresses\r
33 \r
34 \r
35 **/\r
36 EFI_STATUS\r
37 pxe_rcvfilter_enable (\r
38   SNP_DRIVER      *snp,\r
39   UINT32          EnableFlags,\r
40   UINTN           MCastAddressCount,\r
41   EFI_MAC_ADDRESS *MCastAddressList\r
42   )\r
43 {\r
44   snp->cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;\r
45   snp->cdb.OpFlags    = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;\r
46   snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
47   snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
48   snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
49   snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
50   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
51   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
52   snp->cdb.IFnum      = snp->if_num;\r
53   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
54 \r
55   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {\r
56     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;\r
57   }\r
58 \r
59   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {\r
60     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;\r
61   }\r
62 \r
63   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
64     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;\r
65   }\r
66 \r
67   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
68     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;\r
69   }\r
70 \r
71   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
72     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;\r
73   }\r
74 \r
75   if (MCastAddressCount != 0) {\r
76     snp->cdb.CPBsize  = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));\r
77     snp->cdb.CPBaddr  = (UINT64)(UINTN) snp->cpb;\r
78     CopyMem (snp->cpb, MCastAddressList, snp->cdb.CPBsize);\r
79   }\r
80   //\r
81   // Issue UNDI command and check result.\r
82   //\r
83   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));\r
84 \r
85   (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
86 \r
87   if (snp->cdb.StatCode != EFI_SUCCESS) {\r
88     //\r
89     // UNDI command failed.  Return UNDI status to caller.\r
90     //\r
91     DEBUG (\r
92       (EFI_D_ERROR,\r
93       "\nsnp->undi.receive_filters()  %xh:%xh\n",\r
94       snp->cdb.StatFlags,\r
95       snp->cdb.StatCode)\r
96       );\r
97 \r
98     switch (snp->cdb.StatCode) {\r
99     case PXE_STATCODE_INVALID_CDB:\r
100     case PXE_STATCODE_INVALID_CPB:\r
101     case PXE_STATCODE_INVALID_PARAMETER:\r
102       return EFI_INVALID_PARAMETER;\r
103 \r
104     case PXE_STATCODE_UNSUPPORTED:\r
105       return EFI_UNSUPPORTED;\r
106     }\r
107 \r
108     return EFI_DEVICE_ERROR;\r
109   }\r
110 \r
111   return EFI_SUCCESS;\r
112 }\r
113 \r
114 /**\r
115   this routine calls undi to disable the receive filters.\r
116 \r
117   @param  snp                pointer to snp driver structure\r
118   @param  DisableFlags       bit mask for disabling the receive filters\r
119   @param  ResetMCastList     boolean flag to reset/delete the multicast filter list\r
120 \r
121 \r
122 **/\r
123 EFI_STATUS\r
124 pxe_rcvfilter_disable (\r
125   SNP_DRIVER *snp,\r
126   UINT32     DisableFlags,\r
127   BOOLEAN    ResetMCastList\r
128   )\r
129 {\r
130   snp->cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;\r
131   snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
132   snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
133   snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
134   snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
135   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
136   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
137   snp->cdb.IFnum      = snp->if_num;\r
138   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
139 \r
140   snp->cdb.OpFlags    = (UINT16) (DisableFlags ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);\r
141 \r
142   if (ResetMCastList) {\r
143     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;\r
144   }\r
145 \r
146   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {\r
147     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;\r
148   }\r
149 \r
150   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {\r
151     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;\r
152   }\r
153 \r
154   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
155     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;\r
156   }\r
157 \r
158   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
159     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;\r
160   }\r
161 \r
162   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
163     snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;\r
164   }\r
165   //\r
166   // Issue UNDI command and check result.\r
167   //\r
168   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));\r
169 \r
170   (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
171 \r
172   if (snp->cdb.StatCode != EFI_SUCCESS) {\r
173     //\r
174     // UNDI command failed.  Return UNDI status to caller.\r
175     //\r
176     DEBUG (\r
177       (EFI_D_ERROR,\r
178       "\nsnp->undi.receive_filters()  %xh:%xh\n",\r
179       snp->cdb.StatFlags,\r
180       snp->cdb.StatCode)\r
181       );\r
182 \r
183     return EFI_DEVICE_ERROR;\r
184   }\r
185 \r
186   return EFI_SUCCESS;\r
187 }\r
188 \r
189 /**\r
190   this routine calls undi to read the receive filters.\r
191 \r
192   @param  snp                pointer to snp driver structure\r
193 \r
194 \r
195 **/\r
196 EFI_STATUS\r
197 pxe_rcvfilter_read (\r
198   SNP_DRIVER *snp\r
199   )\r
200 {\r
201   snp->cdb.OpCode   = PXE_OPCODE_RECEIVE_FILTERS;\r
202   snp->cdb.OpFlags  = PXE_OPFLAGS_RECEIVE_FILTER_READ;\r
203   snp->cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;\r
204   snp->cdb.DBsize   = (UINT16) (snp->mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));\r
205   snp->cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;\r
206   if (snp->cdb.DBsize == 0) {\r
207     snp->cdb.DBaddr = (UINT64)(UINTN) NULL;\r
208   } else {\r
209     snp->cdb.DBaddr = (UINT64)(UINTN) snp->db;\r
210     ZeroMem (snp->db, snp->cdb.DBsize);\r
211   }\r
212 \r
213   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
214   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
215   snp->cdb.IFnum      = snp->if_num;\r
216   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
217 \r
218   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));\r
219 \r
220   (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
221 \r
222   if (snp->cdb.StatCode != EFI_SUCCESS) {\r
223     //\r
224     // UNDI command failed.  Return UNDI status to caller.\r
225     //\r
226     DEBUG (\r
227       (EFI_D_ERROR,\r
228       "\nsnp->undi.receive_filters()  %xh:%xh\n",\r
229       snp->cdb.StatFlags,\r
230       snp->cdb.StatCode)\r
231       );\r
232 \r
233     return EFI_DEVICE_ERROR;\r
234   }\r
235   //\r
236   // Convert UNDI32 StatFlags to EFI SNP filter flags.\r
237   //\r
238   snp->mode.ReceiveFilterSetting = 0;\r
239 \r
240   if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {\r
241     snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
242   }\r
243 \r
244   if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {\r
245     snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
246   }\r
247 \r
248   if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {\r
249     snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
250   }\r
251 \r
252   if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {\r
253     snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
254   }\r
255 \r
256   if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {\r
257     snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
258   }\r
259 \r
260   CopyMem (snp->mode.MCastFilter, snp->db, snp->cdb.DBsize);\r
261 \r
262   //\r
263   // Count number of active entries in multicast filter list.\r
264   //\r
265   {\r
266     EFI_MAC_ADDRESS ZeroMacAddr;\r
267 \r
268     SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);\r
269 \r
270     for (snp->mode.MCastFilterCount = 0;\r
271          snp->mode.MCastFilterCount < snp->mode.MaxMCastFilterCount;\r
272          snp->mode.MCastFilterCount++\r
273         ) {\r
274       if (CompareMem (\r
275             &snp->mode.MCastFilter[snp->mode.MCastFilterCount],\r
276             &ZeroMacAddr,\r
277             sizeof ZeroMacAddr\r
278             ) == 0) {\r
279         break;\r
280       }\r
281     }\r
282   }\r
283 \r
284   return EFI_SUCCESS;\r
285 }\r
286 \r
287 \r
288 /**\r
289   This is the SNP interface routine for reading/enabling/disabling the\r
290   receive filters.\r
291   This routine basically retrieves snp structure, checks the SNP state and\r
292   checks the parameter validity, calls one of the above routines to actually\r
293   do the work\r
294 \r
295   @param  this               context pointer\r
296   @param  EnableFlags        bit mask for enabling the receive filters\r
297   @param  DisableFlags       bit mask for disabling the receive filters\r
298   @param  ResetMCastList     boolean flag to reset/delete the multicast filter list\r
299   @param  MCastAddressCount  multicast address count for a new multicast address\r
300                              list\r
301   @param  MCastAddressList   list of new multicast addresses\r
302 \r
303 \r
304 **/\r
305 EFI_STATUS\r
306 EFIAPI\r
307 snp_undi32_receive_filters (\r
308   IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
309   IN UINT32                      EnableFlags,\r
310   IN UINT32                      DisableFlags,\r
311   IN BOOLEAN                     ResetMCastList,\r
312   IN UINTN                       MCastAddressCount OPTIONAL,\r
313   IN EFI_MAC_ADDRESS             * MCastAddressList OPTIONAL\r
314   )\r
315 {\r
316   SNP_DRIVER  *snp;\r
317   EFI_STATUS  Status;\r
318   EFI_TPL     OldTpl;\r
319 \r
320   if (this == NULL) {\r
321     return EFI_INVALID_PARAMETER;\r
322   }\r
323 \r
324   snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
325 \r
326   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
327 \r
328   switch (snp->mode.State) {\r
329   case EfiSimpleNetworkInitialized:\r
330     break;\r
331 \r
332   case EfiSimpleNetworkStopped:\r
333     Status = EFI_NOT_STARTED;\r
334     goto ON_EXIT;\r
335 \r
336   default:\r
337     Status = EFI_DEVICE_ERROR;\r
338     goto ON_EXIT;\r
339   }\r
340   //\r
341   // check if we are asked to enable or disable something that the UNDI\r
342   // does not even support!\r
343   //\r
344   if (((EnableFlags &~snp->mode.ReceiveFilterMask) != 0) ||\r
345     ((DisableFlags &~snp->mode.ReceiveFilterMask) != 0)) {\r
346     Status = EFI_INVALID_PARAMETER;\r
347     goto ON_EXIT;\r
348   }\r
349 \r
350   if (ResetMCastList) {\r
351 \r
352     DisableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & snp->mode.ReceiveFilterMask;\r
353     MCastAddressCount = 0;\r
354     MCastAddressList  = NULL;\r
355   } else {\r
356     if (MCastAddressCount != 0) {\r
357       if ((MCastAddressCount > snp->mode.MaxMCastFilterCount) ||\r
358         (MCastAddressList == NULL)) {\r
359 \r
360         Status = EFI_INVALID_PARAMETER;\r
361         goto ON_EXIT;\r
362       }\r
363     }\r
364   }\r
365 \r
366   if (EnableFlags == 0 && DisableFlags == 0 && !ResetMCastList && MCastAddressCount == 0) {\r
367     Status = EFI_SUCCESS;\r
368     goto ON_EXIT;\r
369   }\r
370 \r
371   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastAddressCount == 0) {\r
372     Status = EFI_INVALID_PARAMETER;\r
373     goto ON_EXIT;\r
374   }\r
375 \r
376   if ((EnableFlags != 0) || (MCastAddressCount != 0)) {\r
377     Status = pxe_rcvfilter_enable (\r
378               snp,\r
379               EnableFlags,\r
380               MCastAddressCount,\r
381               MCastAddressList\r
382               );\r
383 \r
384     if (EFI_ERROR (Status)) {\r
385       goto ON_EXIT;\r
386     }\r
387   }\r
388 \r
389   if ((DisableFlags != 0) || ResetMCastList) {\r
390     Status = pxe_rcvfilter_disable (snp, DisableFlags, ResetMCastList);\r
391 \r
392     if (EFI_ERROR (Status)) {\r
393       goto ON_EXIT;\r
394     }\r
395   }\r
396 \r
397   Status = pxe_rcvfilter_read (snp);\r
398 \r
399 ON_EXIT:\r
400   gBS->RestoreTPL (OldTpl);\r
401 \r
402   return Status;\r
403 }\r