1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2018-2020, Intel Corporation. */
3 
4 #include "ice.h"
5 #include "ice_fltr.h"
6 
7 /**
8  * ice_fltr_free_list - free filter lists helper
9  * @dev: pointer to the device struct
10  * @h: pointer to the list head to be freed
11  *
12  * Helper function to free filter lists previously created using
13  * ice_fltr_add_mac_to_list
14  */
15 void ice_fltr_free_list(struct device *dev, struct list_head *h)
16 {
17 	struct ice_fltr_list_entry *e, *tmp;
18 
19 	list_for_each_entry_safe(e, tmp, h, list_entry) {
20 		list_del(&e->list_entry);
21 		devm_kfree(dev, e);
22 	}
23 }
24 
25 /**
26  * ice_fltr_add_entry_to_list - allocate and add filter entry to list
27  * @dev: pointer to device needed by alloc function
28  * @info: filter info struct that gets added to the passed in list
29  * @list: pointer to the list which contains MAC filters entry
30  */
31 static int
32 ice_fltr_add_entry_to_list(struct device *dev, struct ice_fltr_info *info,
33 			   struct list_head *list)
34 {
35 	struct ice_fltr_list_entry *entry;
36 
37 	entry = devm_kzalloc(dev, sizeof(*entry), GFP_ATOMIC);
38 	if (!entry)
39 		return -ENOMEM;
40 
41 	entry->fltr_info = *info;
42 
43 	INIT_LIST_HEAD(&entry->list_entry);
44 	list_add(&entry->list_entry, list);
45 
46 	return 0;
47 }
48 
49 /**
50  * ice_fltr_set_vlan_vsi_promisc
51  * @hw: pointer to the hardware structure
52  * @vsi: the VSI being configured
53  * @promisc_mask: mask of promiscuous config bits
54  *
55  * Set VSI with all associated VLANs to given promiscuous mode(s)
56  */
57 int
58 ice_fltr_set_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi,
59 			      u8 promisc_mask)
60 {
61 	return ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, false);
62 }
63 
64 /**
65  * ice_fltr_clear_vlan_vsi_promisc
66  * @hw: pointer to the hardware structure
67  * @vsi: the VSI being configured
68  * @promisc_mask: mask of promiscuous config bits
69  *
70  * Clear VSI with all associated VLANs to given promiscuous mode(s)
71  */
72 int
73 ice_fltr_clear_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi,
74 				u8 promisc_mask)
75 {
76 	return ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, true);
77 }
78 
79 /**
80  * ice_fltr_clear_vsi_promisc - clear specified promiscuous mode(s)
81  * @hw: pointer to the hardware structure
82  * @vsi_handle: VSI handle to clear mode
83  * @promisc_mask: mask of promiscuous config bits to clear
84  * @vid: VLAN ID to clear VLAN promiscuous
85  */
86 int
87 ice_fltr_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
88 			   u16 vid)
89 {
90 	return ice_clear_vsi_promisc(hw, vsi_handle, promisc_mask, vid);
91 }
92 
93 /**
94  * ice_fltr_set_vsi_promisc - set given VSI to given promiscuous mode(s)
95  * @hw: pointer to the hardware structure
96  * @vsi_handle: VSI handle to configure
97  * @promisc_mask: mask of promiscuous config bits
98  * @vid: VLAN ID to set VLAN promiscuous
99  */
100 int
101 ice_fltr_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
102 			 u16 vid)
103 {
104 	return ice_set_vsi_promisc(hw, vsi_handle, promisc_mask, vid);
105 }
106 
107 /**
108  * ice_fltr_add_mac_list - add list of MAC filters
109  * @vsi: pointer to VSI struct
110  * @list: list of filters
111  */
112 int ice_fltr_add_mac_list(struct ice_vsi *vsi, struct list_head *list)
113 {
114 	return ice_add_mac(&vsi->back->hw, list);
115 }
116 
117 /**
118  * ice_fltr_remove_mac_list - remove list of MAC filters
119  * @vsi: pointer to VSI struct
120  * @list: list of filters
121  */
122 int ice_fltr_remove_mac_list(struct ice_vsi *vsi, struct list_head *list)
123 {
124 	return ice_remove_mac(&vsi->back->hw, list);
125 }
126 
127 /**
128  * ice_fltr_add_vlan_list - add list of VLAN filters
129  * @vsi: pointer to VSI struct
130  * @list: list of filters
131  */
132 static int ice_fltr_add_vlan_list(struct ice_vsi *vsi, struct list_head *list)
133 {
134 	return ice_add_vlan(&vsi->back->hw, list);
135 }
136 
137 /**
138  * ice_fltr_remove_vlan_list - remove list of VLAN filters
139  * @vsi: pointer to VSI struct
140  * @list: list of filters
141  */
142 static int
143 ice_fltr_remove_vlan_list(struct ice_vsi *vsi, struct list_head *list)
144 {
145 	return ice_remove_vlan(&vsi->back->hw, list);
146 }
147 
148 /**
149  * ice_fltr_add_eth_list - add list of ethertype filters
150  * @vsi: pointer to VSI struct
151  * @list: list of filters
152  */
153 static int ice_fltr_add_eth_list(struct ice_vsi *vsi, struct list_head *list)
154 {
155 	return ice_add_eth_mac(&vsi->back->hw, list);
156 }
157 
158 /**
159  * ice_fltr_remove_eth_list - remove list of ethertype filters
160  * @vsi: pointer to VSI struct
161  * @list: list of filters
162  */
163 static int ice_fltr_remove_eth_list(struct ice_vsi *vsi, struct list_head *list)
164 {
165 	return ice_remove_eth_mac(&vsi->back->hw, list);
166 }
167 
168 /**
169  * ice_fltr_remove_all - remove all filters associated with VSI
170  * @vsi: pointer to VSI struct
171  */
172 void ice_fltr_remove_all(struct ice_vsi *vsi)
173 {
174 	ice_remove_vsi_fltr(&vsi->back->hw, vsi->idx);
175 }
176 
177 /**
178  * ice_fltr_add_mac_to_list - add MAC filter info to exsisting list
179  * @vsi: pointer to VSI struct
180  * @list: list to add filter info to
181  * @mac: MAC address to add
182  * @action: filter action
183  */
184 int
185 ice_fltr_add_mac_to_list(struct ice_vsi *vsi, struct list_head *list,
186 			 const u8 *mac, enum ice_sw_fwd_act_type action)
187 {
188 	struct ice_fltr_info info = { 0 };
189 
190 	info.flag = ICE_FLTR_TX;
191 	info.src_id = ICE_SRC_ID_VSI;
192 	info.lkup_type = ICE_SW_LKUP_MAC;
193 	info.fltr_act = action;
194 	info.vsi_handle = vsi->idx;
195 
196 	ether_addr_copy(info.l_data.mac.mac_addr, mac);
197 
198 	return ice_fltr_add_entry_to_list(ice_pf_to_dev(vsi->back), &info,
199 					  list);
200 }
201 
202 /**
203  * ice_fltr_add_vlan_to_list - add VLAN filter info to exsisting list
204  * @vsi: pointer to VSI struct
205  * @list: list to add filter info to
206  * @vlan_id: VLAN ID to add
207  * @action: filter action
208  */
209 static int
210 ice_fltr_add_vlan_to_list(struct ice_vsi *vsi, struct list_head *list,
211 			  u16 vlan_id, enum ice_sw_fwd_act_type action)
212 {
213 	struct ice_fltr_info info = { 0 };
214 
215 	info.flag = ICE_FLTR_TX;
216 	info.src_id = ICE_SRC_ID_VSI;
217 	info.lkup_type = ICE_SW_LKUP_VLAN;
218 	info.fltr_act = action;
219 	info.vsi_handle = vsi->idx;
220 	info.l_data.vlan.vlan_id = vlan_id;
221 
222 	return ice_fltr_add_entry_to_list(ice_pf_to_dev(vsi->back), &info,
223 					  list);
224 }
225 
226 /**
227  * ice_fltr_add_eth_to_list - add ethertype filter info to exsisting list
228  * @vsi: pointer to VSI struct
229  * @list: list to add filter info to
230  * @ethertype: ethertype of packet that matches filter
231  * @flag: filter direction, Tx or Rx
232  * @action: filter action
233  */
234 static int
235 ice_fltr_add_eth_to_list(struct ice_vsi *vsi, struct list_head *list,
236 			 u16 ethertype, u16 flag,
237 			 enum ice_sw_fwd_act_type action)
238 {
239 	struct ice_fltr_info info = { 0 };
240 
241 	info.flag = flag;
242 	info.lkup_type = ICE_SW_LKUP_ETHERTYPE;
243 	info.fltr_act = action;
244 	info.vsi_handle = vsi->idx;
245 	info.l_data.ethertype_mac.ethertype = ethertype;
246 
247 	if (flag == ICE_FLTR_TX)
248 		info.src_id = ICE_SRC_ID_VSI;
249 	else
250 		info.src_id = ICE_SRC_ID_LPORT;
251 
252 	return ice_fltr_add_entry_to_list(ice_pf_to_dev(vsi->back), &info,
253 					  list);
254 }
255 
256 /**
257  * ice_fltr_prepare_mac - add or remove MAC rule
258  * @vsi: pointer to VSI struct
259  * @mac: MAC address to add
260  * @action: action to be performed on filter match
261  * @mac_action: pointer to add or remove MAC function
262  */
263 static int
264 ice_fltr_prepare_mac(struct ice_vsi *vsi, const u8 *mac,
265 		     enum ice_sw_fwd_act_type action,
266 		     int (*mac_action)(struct ice_vsi *, struct list_head *))
267 {
268 	LIST_HEAD(tmp_list);
269 	int result;
270 
271 	if (ice_fltr_add_mac_to_list(vsi, &tmp_list, mac, action)) {
272 		ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
273 		return -ENOMEM;
274 	}
275 
276 	result = mac_action(vsi, &tmp_list);
277 	ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
278 	return result;
279 }
280 
281 /**
282  * ice_fltr_prepare_mac_and_broadcast - add or remove MAC and broadcast filter
283  * @vsi: pointer to VSI struct
284  * @mac: MAC address to add
285  * @action: action to be performed on filter match
286  * @mac_action: pointer to add or remove MAC function
287  */
288 static int
289 ice_fltr_prepare_mac_and_broadcast(struct ice_vsi *vsi, const u8 *mac,
290 				   enum ice_sw_fwd_act_type action,
291 				   int(*mac_action)
292 				   (struct ice_vsi *, struct list_head *))
293 {
294 	u8 broadcast[ETH_ALEN];
295 	LIST_HEAD(tmp_list);
296 	int result;
297 
298 	eth_broadcast_addr(broadcast);
299 	if (ice_fltr_add_mac_to_list(vsi, &tmp_list, mac, action) ||
300 	    ice_fltr_add_mac_to_list(vsi, &tmp_list, broadcast, action)) {
301 		ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
302 		return -ENOMEM;
303 	}
304 
305 	result = mac_action(vsi, &tmp_list);
306 	ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
307 	return result;
308 }
309 
310 /**
311  * ice_fltr_prepare_vlan - add or remove VLAN filter
312  * @vsi: pointer to VSI struct
313  * @vlan_id: VLAN ID to add
314  * @action: action to be performed on filter match
315  * @vlan_action: pointer to add or remove VLAN function
316  */
317 static int
318 ice_fltr_prepare_vlan(struct ice_vsi *vsi, u16 vlan_id,
319 		      enum ice_sw_fwd_act_type action,
320 		      int (*vlan_action)(struct ice_vsi *, struct list_head *))
321 {
322 	LIST_HEAD(tmp_list);
323 	int result;
324 
325 	if (ice_fltr_add_vlan_to_list(vsi, &tmp_list, vlan_id, action))
326 		return -ENOMEM;
327 
328 	result = vlan_action(vsi, &tmp_list);
329 	ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
330 	return result;
331 }
332 
333 /**
334  * ice_fltr_prepare_eth - add or remove ethertype filter
335  * @vsi: pointer to VSI struct
336  * @ethertype: ethertype of packet to be filtered
337  * @flag: direction of packet, Tx or Rx
338  * @action: action to be performed on filter match
339  * @eth_action: pointer to add or remove ethertype function
340  */
341 static int
342 ice_fltr_prepare_eth(struct ice_vsi *vsi, u16 ethertype, u16 flag,
343 		     enum ice_sw_fwd_act_type action,
344 		     int (*eth_action)(struct ice_vsi *, struct list_head *))
345 {
346 	LIST_HEAD(tmp_list);
347 	int result;
348 
349 	if (ice_fltr_add_eth_to_list(vsi, &tmp_list, ethertype, flag, action))
350 		return -ENOMEM;
351 
352 	result = eth_action(vsi, &tmp_list);
353 	ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
354 	return result;
355 }
356 
357 /**
358  * ice_fltr_add_mac - add single MAC filter
359  * @vsi: pointer to VSI struct
360  * @mac: MAC to add
361  * @action: action to be performed on filter match
362  */
363 int ice_fltr_add_mac(struct ice_vsi *vsi, const u8 *mac,
364 		     enum ice_sw_fwd_act_type action)
365 {
366 	return ice_fltr_prepare_mac(vsi, mac, action, ice_fltr_add_mac_list);
367 }
368 
369 /**
370  * ice_fltr_add_mac_and_broadcast - add single MAC and broadcast
371  * @vsi: pointer to VSI struct
372  * @mac: MAC to add
373  * @action: action to be performed on filter match
374  */
375 int
376 ice_fltr_add_mac_and_broadcast(struct ice_vsi *vsi, const u8 *mac,
377 			       enum ice_sw_fwd_act_type action)
378 {
379 	return ice_fltr_prepare_mac_and_broadcast(vsi, mac, action,
380 						  ice_fltr_add_mac_list);
381 }
382 
383 /**
384  * ice_fltr_remove_mac - remove MAC filter
385  * @vsi: pointer to VSI struct
386  * @mac: filter MAC to remove
387  * @action: action to remove
388  */
389 int ice_fltr_remove_mac(struct ice_vsi *vsi, const u8 *mac,
390 			enum ice_sw_fwd_act_type action)
391 {
392 	return ice_fltr_prepare_mac(vsi, mac, action, ice_fltr_remove_mac_list);
393 }
394 
395 /**
396  * ice_fltr_add_vlan - add single VLAN filter
397  * @vsi: pointer to VSI struct
398  * @vlan_id: VLAN ID to add
399  * @action: action to be performed on filter match
400  */
401 int ice_fltr_add_vlan(struct ice_vsi *vsi, u16 vlan_id,
402 		      enum ice_sw_fwd_act_type action)
403 {
404 	return ice_fltr_prepare_vlan(vsi, vlan_id, action,
405 				     ice_fltr_add_vlan_list);
406 }
407 
408 /**
409  * ice_fltr_remove_vlan - remove VLAN filter
410  * @vsi: pointer to VSI struct
411  * @vlan_id: filter VLAN to remove
412  * @action: action to remove
413  */
414 int ice_fltr_remove_vlan(struct ice_vsi *vsi, u16 vlan_id,
415 			 enum ice_sw_fwd_act_type action)
416 {
417 	return ice_fltr_prepare_vlan(vsi, vlan_id, action,
418 				     ice_fltr_remove_vlan_list);
419 }
420 
421 /**
422  * ice_fltr_add_eth - add specyfic ethertype filter
423  * @vsi: pointer to VSI struct
424  * @ethertype: ethertype of filter
425  * @flag: direction of packet to be filtered, Tx or Rx
426  * @action: action to be performed on filter match
427  */
428 int ice_fltr_add_eth(struct ice_vsi *vsi, u16 ethertype, u16 flag,
429 		     enum ice_sw_fwd_act_type action)
430 {
431 	return ice_fltr_prepare_eth(vsi, ethertype, flag, action,
432 				    ice_fltr_add_eth_list);
433 }
434 
435 /**
436  * ice_fltr_remove_eth - remove ethertype filter
437  * @vsi: pointer to VSI struct
438  * @ethertype: ethertype of filter
439  * @flag: direction of filter
440  * @action: action to remove
441  */
442 int ice_fltr_remove_eth(struct ice_vsi *vsi, u16 ethertype, u16 flag,
443 			enum ice_sw_fwd_act_type action)
444 {
445 	return ice_fltr_prepare_eth(vsi, ethertype, flag, action,
446 				    ice_fltr_remove_eth_list);
447 }
448