Branch data Line data Source code
1 : : /*
2 : : * net/core/dev_addr_lists.c - Functions for handling net device lists
3 : : * Copyright (c) 2010 Jiri Pirko <jpirko@redhat.com>
4 : : *
5 : : * This file contains functions for working with unicast, multicast and device
6 : : * addresses lists.
7 : : *
8 : : * This program is free software; you can redistribute it and/or modify
9 : : * it under the terms of the GNU General Public License as published by
10 : : * the Free Software Foundation; either version 2 of the License, or
11 : : * (at your option) any later version.
12 : : */
13 : :
14 : : #include <linux/netdevice.h>
15 : : #include <linux/rtnetlink.h>
16 : : #include <linux/export.h>
17 : : #include <linux/list.h>
18 : :
19 : : /*
20 : : * General list handling functions
21 : : */
22 : :
23 : 0 : static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
24 : : const unsigned char *addr, int addr_len,
25 : : unsigned char addr_type, bool global,
26 : : bool sync)
27 : : {
28 : : struct netdev_hw_addr *ha;
29 : : int alloc_size;
30 : :
31 : : alloc_size = sizeof(*ha);
32 : : if (alloc_size < L1_CACHE_BYTES)
33 : : alloc_size = L1_CACHE_BYTES;
34 : : ha = kmalloc(alloc_size, GFP_ATOMIC);
35 [ # # ]: 0 : if (!ha)
36 : : return -ENOMEM;
37 : 0 : memcpy(ha->addr, addr, addr_len);
38 : 0 : ha->type = addr_type;
39 : 0 : ha->refcount = 1;
40 : 0 : ha->global_use = global;
41 : 0 : ha->synced = sync ? 1 : 0;
42 : 0 : ha->sync_cnt = 0;
43 : 0 : list_add_tail_rcu(&ha->list, &list->list);
44 : 0 : list->count++;
45 : :
46 : 0 : return 0;
47 : : }
48 : :
49 : 0 : static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
50 : : const unsigned char *addr, int addr_len,
51 : : unsigned char addr_type, bool global, bool sync,
52 : : int sync_count)
53 : : {
54 : : struct netdev_hw_addr *ha;
55 : :
56 [ # # ]: 0 : if (addr_len > MAX_ADDR_LEN)
57 : : return -EINVAL;
58 : :
59 [ # # ]: 0 : list_for_each_entry(ha, &list->list, list) {
60 [ # # ][ # # ]: 0 : if (!memcmp(ha->addr, addr, addr_len) &&
61 : 0 : ha->type == addr_type) {
62 [ # # ]: 0 : if (global) {
63 : : /* check if addr is already used as global */
64 [ # # ]: 0 : if (ha->global_use)
65 : : return 0;
66 : : else
67 : 0 : ha->global_use = true;
68 : : }
69 [ # # ]: 0 : if (sync) {
70 [ # # ][ # # ]: 0 : if (ha->synced && sync_count)
71 : : return -EEXIST;
72 : : else
73 : 0 : ha->synced++;
74 : : }
75 : 0 : ha->refcount++;
76 : 0 : return 0;
77 : : }
78 : : }
79 : :
80 : 0 : return __hw_addr_create_ex(list, addr, addr_len, addr_type, global,
81 : : sync);
82 : : }
83 : :
84 : : static int __hw_addr_add(struct netdev_hw_addr_list *list,
85 : : const unsigned char *addr, int addr_len,
86 : : unsigned char addr_type)
87 : : {
88 : 0 : return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false,
89 : : 0);
90 : : }
91 : :
92 : 0 : static int __hw_addr_del_entry(struct netdev_hw_addr_list *list,
93 : : struct netdev_hw_addr *ha, bool global,
94 : : bool sync)
95 : : {
96 [ # # ][ # # ]: 0 : if (global && !ha->global_use)
97 : : return -ENOENT;
98 : :
99 [ # # ][ # # ]: 0 : if (sync && !ha->synced)
100 : : return -ENOENT;
101 : :
102 [ # # ]: 0 : if (global)
103 : 0 : ha->global_use = false;
104 : :
105 [ # # ]: 0 : if (sync)
106 : 0 : ha->synced--;
107 : :
108 [ # # ]: 0 : if (--ha->refcount)
109 : : return 0;
110 : : list_del_rcu(&ha->list);
111 : 0 : kfree_rcu(ha, rcu_head);
112 : 0 : list->count--;
113 : : return 0;
114 : : }
115 : :
116 : 0 : static int __hw_addr_del_ex(struct netdev_hw_addr_list *list,
117 : : const unsigned char *addr, int addr_len,
118 : : unsigned char addr_type, bool global, bool sync)
119 : : {
120 : : struct netdev_hw_addr *ha;
121 : :
122 [ # # ]: 0 : list_for_each_entry(ha, &list->list, list) {
123 [ # # ][ # # ]: 0 : if (!memcmp(ha->addr, addr, addr_len) &&
124 [ # # ]: 0 : (ha->type == addr_type || !addr_type))
125 : 0 : return __hw_addr_del_entry(list, ha, global, sync);
126 : : }
127 : : return -ENOENT;
128 : : }
129 : :
130 : : static int __hw_addr_del(struct netdev_hw_addr_list *list,
131 : : const unsigned char *addr, int addr_len,
132 : : unsigned char addr_type)
133 : : {
134 : 0 : return __hw_addr_del_ex(list, addr, addr_len, addr_type, false, false);
135 : : }
136 : :
137 : 0 : static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list,
138 : : struct netdev_hw_addr *ha,
139 : : int addr_len)
140 : : {
141 : : int err;
142 : :
143 : 0 : err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type,
144 : : false, true, ha->sync_cnt);
145 [ # # ]: 0 : if (err && err != -EEXIST)
146 : : return err;
147 : :
148 [ # # ]: 0 : if (!err) {
149 : 0 : ha->sync_cnt++;
150 : 0 : ha->refcount++;
151 : : }
152 : :
153 : : return 0;
154 : : }
155 : :
156 : 0 : static void __hw_addr_unsync_one(struct netdev_hw_addr_list *to_list,
157 : : struct netdev_hw_addr_list *from_list,
158 : : struct netdev_hw_addr *ha,
159 : : int addr_len)
160 : : {
161 : : int err;
162 : :
163 : 0 : err = __hw_addr_del_ex(to_list, ha->addr, addr_len, ha->type,
164 : : false, true);
165 [ # # ]: 0 : if (err)
166 : 0 : return;
167 : 0 : ha->sync_cnt--;
168 : : /* address on from list is not marked synced */
169 : 0 : __hw_addr_del_entry(from_list, ha, false, false);
170 : : }
171 : :
172 : 0 : static int __hw_addr_sync_multiple(struct netdev_hw_addr_list *to_list,
173 : : struct netdev_hw_addr_list *from_list,
174 : : int addr_len)
175 : : {
176 : : int err = 0;
177 : : struct netdev_hw_addr *ha, *tmp;
178 : :
179 [ # # ]: 0 : list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
180 [ # # ]: 0 : if (ha->sync_cnt == ha->refcount) {
181 : 0 : __hw_addr_unsync_one(to_list, from_list, ha, addr_len);
182 : : } else {
183 : 0 : err = __hw_addr_sync_one(to_list, ha, addr_len);
184 [ # # ]: 0 : if (err)
185 : : break;
186 : : }
187 : : }
188 : 0 : return err;
189 : : }
190 : :
191 : : /* This function only works where there is a strict 1-1 relationship
192 : : * between source and destionation of they synch. If you ever need to
193 : : * sync addresses to more then 1 destination, you need to use
194 : : * __hw_addr_sync_multiple().
195 : : */
196 : 0 : int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
197 : : struct netdev_hw_addr_list *from_list,
198 : : int addr_len)
199 : : {
200 : : int err = 0;
201 : : struct netdev_hw_addr *ha, *tmp;
202 : :
203 [ # # ]: 0 : list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
204 [ # # ]: 0 : if (!ha->sync_cnt) {
205 : 0 : err = __hw_addr_sync_one(to_list, ha, addr_len);
206 [ # # ]: 0 : if (err)
207 : : break;
208 [ # # ]: 0 : } else if (ha->refcount == 1)
209 : 0 : __hw_addr_unsync_one(to_list, from_list, ha, addr_len);
210 : : }
211 : 0 : return err;
212 : : }
213 : : EXPORT_SYMBOL(__hw_addr_sync);
214 : :
215 : 0 : void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
216 : : struct netdev_hw_addr_list *from_list,
217 : : int addr_len)
218 : : {
219 : : struct netdev_hw_addr *ha, *tmp;
220 : :
221 [ # # ]: 0 : list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
222 [ # # ]: 0 : if (ha->sync_cnt)
223 : 0 : __hw_addr_unsync_one(to_list, from_list, ha, addr_len);
224 : : }
225 : 0 : }
226 : : EXPORT_SYMBOL(__hw_addr_unsync);
227 : :
228 : 0 : static void __hw_addr_flush(struct netdev_hw_addr_list *list)
229 : : {
230 : : struct netdev_hw_addr *ha, *tmp;
231 : :
232 [ # # ]: 0 : list_for_each_entry_safe(ha, tmp, &list->list, list) {
233 : : list_del_rcu(&ha->list);
234 : 0 : kfree_rcu(ha, rcu_head);
235 : : }
236 : 0 : list->count = 0;
237 : 0 : }
238 : :
239 : 0 : void __hw_addr_init(struct netdev_hw_addr_list *list)
240 : : {
241 : 0 : INIT_LIST_HEAD(&list->list);
242 : 0 : list->count = 0;
243 : 0 : }
244 : : EXPORT_SYMBOL(__hw_addr_init);
245 : :
246 : : /*
247 : : * Device addresses handling functions
248 : : */
249 : :
250 : : /**
251 : : * dev_addr_flush - Flush device address list
252 : : * @dev: device
253 : : *
254 : : * Flush device address list and reset ->dev_addr.
255 : : *
256 : : * The caller must hold the rtnl_mutex.
257 : : */
258 : 0 : void dev_addr_flush(struct net_device *dev)
259 : : {
260 : : /* rtnl_mutex must be held here */
261 : :
262 : 0 : __hw_addr_flush(&dev->dev_addrs);
263 : 0 : dev->dev_addr = NULL;
264 : 0 : }
265 : : EXPORT_SYMBOL(dev_addr_flush);
266 : :
267 : : /**
268 : : * dev_addr_init - Init device address list
269 : : * @dev: device
270 : : *
271 : : * Init device address list and create the first element,
272 : : * used by ->dev_addr.
273 : : *
274 : : * The caller must hold the rtnl_mutex.
275 : : */
276 : 0 : int dev_addr_init(struct net_device *dev)
277 : : {
278 : : unsigned char addr[MAX_ADDR_LEN];
279 : : struct netdev_hw_addr *ha;
280 : : int err;
281 : :
282 : : /* rtnl_mutex must be held here */
283 : :
284 : : __hw_addr_init(&dev->dev_addrs);
285 : 0 : memset(addr, 0, sizeof(addr));
286 : 0 : err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr),
287 : : NETDEV_HW_ADDR_T_LAN);
288 [ # # ]: 0 : if (!err) {
289 : : /*
290 : : * Get the first (previously created) address from the list
291 : : * and set dev_addr pointer to this location.
292 : : */
293 : 0 : ha = list_first_entry(&dev->dev_addrs.list,
294 : : struct netdev_hw_addr, list);
295 : 0 : dev->dev_addr = ha->addr;
296 : : }
297 : 0 : return err;
298 : : }
299 : : EXPORT_SYMBOL(dev_addr_init);
300 : :
301 : : /**
302 : : * dev_addr_add - Add a device address
303 : : * @dev: device
304 : : * @addr: address to add
305 : : * @addr_type: address type
306 : : *
307 : : * Add a device address to the device or increase the reference count if
308 : : * it already exists.
309 : : *
310 : : * The caller must hold the rtnl_mutex.
311 : : */
312 : 0 : int dev_addr_add(struct net_device *dev, const unsigned char *addr,
313 : : unsigned char addr_type)
314 : : {
315 : : int err;
316 : :
317 [ # # ]: 0 : ASSERT_RTNL();
318 : :
319 : 0 : err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type);
320 [ # # ]: 0 : if (!err)
321 : 0 : call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
322 : 0 : return err;
323 : : }
324 : : EXPORT_SYMBOL(dev_addr_add);
325 : :
326 : : /**
327 : : * dev_addr_del - Release a device address.
328 : : * @dev: device
329 : : * @addr: address to delete
330 : : * @addr_type: address type
331 : : *
332 : : * Release reference to a device address and remove it from the device
333 : : * if the reference count drops to zero.
334 : : *
335 : : * The caller must hold the rtnl_mutex.
336 : : */
337 : 0 : int dev_addr_del(struct net_device *dev, const unsigned char *addr,
338 : : unsigned char addr_type)
339 : : {
340 : : int err;
341 : : struct netdev_hw_addr *ha;
342 : :
343 [ # # ]: 0 : ASSERT_RTNL();
344 : :
345 : : /*
346 : : * We can not remove the first address from the list because
347 : : * dev->dev_addr points to that.
348 : : */
349 : 0 : ha = list_first_entry(&dev->dev_addrs.list,
350 : : struct netdev_hw_addr, list);
351 [ # # ][ # # ]: 0 : if (!memcmp(ha->addr, addr, dev->addr_len) &&
352 [ # # ]: 0 : ha->type == addr_type && ha->refcount == 1)
353 : : return -ENOENT;
354 : :
355 : 0 : err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len,
356 : : addr_type);
357 [ # # ]: 0 : if (!err)
358 : 0 : call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
359 : 0 : return err;
360 : : }
361 : : EXPORT_SYMBOL(dev_addr_del);
362 : :
363 : : /*
364 : : * Unicast list handling functions
365 : : */
366 : :
367 : : /**
368 : : * dev_uc_add_excl - Add a global secondary unicast address
369 : : * @dev: device
370 : : * @addr: address to add
371 : : */
372 : 0 : int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr)
373 : : {
374 : : struct netdev_hw_addr *ha;
375 : : int err;
376 : :
377 : : netif_addr_lock_bh(dev);
378 [ # # ]: 0 : list_for_each_entry(ha, &dev->uc.list, list) {
379 [ # # ][ # # ]: 0 : if (!memcmp(ha->addr, addr, dev->addr_len) &&
380 : 0 : ha->type == NETDEV_HW_ADDR_T_UNICAST) {
381 : : err = -EEXIST;
382 : : goto out;
383 : : }
384 : : }
385 : 0 : err = __hw_addr_create_ex(&dev->uc, addr, dev->addr_len,
386 : : NETDEV_HW_ADDR_T_UNICAST, true, false);
387 [ # # ]: 0 : if (!err)
388 : 0 : __dev_set_rx_mode(dev);
389 : : out:
390 : : netif_addr_unlock_bh(dev);
391 : 0 : return err;
392 : : }
393 : : EXPORT_SYMBOL(dev_uc_add_excl);
394 : :
395 : : /**
396 : : * dev_uc_add - Add a secondary unicast address
397 : : * @dev: device
398 : : * @addr: address to add
399 : : *
400 : : * Add a secondary unicast address to the device or increase
401 : : * the reference count if it already exists.
402 : : */
403 : 0 : int dev_uc_add(struct net_device *dev, const unsigned char *addr)
404 : : {
405 : : int err;
406 : :
407 : : netif_addr_lock_bh(dev);
408 : 0 : err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
409 : : NETDEV_HW_ADDR_T_UNICAST);
410 [ # # ]: 0 : if (!err)
411 : 0 : __dev_set_rx_mode(dev);
412 : : netif_addr_unlock_bh(dev);
413 : 0 : return err;
414 : : }
415 : : EXPORT_SYMBOL(dev_uc_add);
416 : :
417 : : /**
418 : : * dev_uc_del - Release secondary unicast address.
419 : : * @dev: device
420 : : * @addr: address to delete
421 : : *
422 : : * Release reference to a secondary unicast address and remove it
423 : : * from the device if the reference count drops to zero.
424 : : */
425 : 0 : int dev_uc_del(struct net_device *dev, const unsigned char *addr)
426 : : {
427 : : int err;
428 : :
429 : : netif_addr_lock_bh(dev);
430 : 0 : err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
431 : : NETDEV_HW_ADDR_T_UNICAST);
432 [ # # ]: 0 : if (!err)
433 : 0 : __dev_set_rx_mode(dev);
434 : : netif_addr_unlock_bh(dev);
435 : 0 : return err;
436 : : }
437 : : EXPORT_SYMBOL(dev_uc_del);
438 : :
439 : : /**
440 : : * dev_uc_sync - Synchronize device's unicast list to another device
441 : : * @to: destination device
442 : : * @from: source device
443 : : *
444 : : * Add newly added addresses to the destination device and release
445 : : * addresses that have no users left. The source device must be
446 : : * locked by netif_addr_lock_bh.
447 : : *
448 : : * This function is intended to be called from the dev->set_rx_mode
449 : : * function of layered software devices. This function assumes that
450 : : * addresses will only ever be synced to the @to devices and no other.
451 : : */
452 : 0 : int dev_uc_sync(struct net_device *to, struct net_device *from)
453 : : {
454 : : int err = 0;
455 : :
456 [ # # ]: 0 : if (to->addr_len != from->addr_len)
457 : : return -EINVAL;
458 : :
459 : : netif_addr_lock_nested(to);
460 : 0 : err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
461 [ # # ]: 0 : if (!err)
462 : 0 : __dev_set_rx_mode(to);
463 : : netif_addr_unlock(to);
464 : 0 : return err;
465 : : }
466 : : EXPORT_SYMBOL(dev_uc_sync);
467 : :
468 : : /**
469 : : * dev_uc_sync_multiple - Synchronize device's unicast list to another
470 : : * device, but allow for multiple calls to sync to multiple devices.
471 : : * @to: destination device
472 : : * @from: source device
473 : : *
474 : : * Add newly added addresses to the destination device and release
475 : : * addresses that have been deleted from the source. The source device
476 : : * must be locked by netif_addr_lock_bh.
477 : : *
478 : : * This function is intended to be called from the dev->set_rx_mode
479 : : * function of layered software devices. It allows for a single source
480 : : * device to be synced to multiple destination devices.
481 : : */
482 : 0 : int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)
483 : : {
484 : : int err = 0;
485 : :
486 [ # # ]: 0 : if (to->addr_len != from->addr_len)
487 : : return -EINVAL;
488 : :
489 : : netif_addr_lock_nested(to);
490 : 0 : err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);
491 [ # # ]: 0 : if (!err)
492 : 0 : __dev_set_rx_mode(to);
493 : : netif_addr_unlock(to);
494 : 0 : return err;
495 : : }
496 : : EXPORT_SYMBOL(dev_uc_sync_multiple);
497 : :
498 : : /**
499 : : * dev_uc_unsync - Remove synchronized addresses from the destination device
500 : : * @to: destination device
501 : : * @from: source device
502 : : *
503 : : * Remove all addresses that were added to the destination device by
504 : : * dev_uc_sync(). This function is intended to be called from the
505 : : * dev->stop function of layered software devices.
506 : : */
507 : 0 : void dev_uc_unsync(struct net_device *to, struct net_device *from)
508 : : {
509 [ # # ]: 0 : if (to->addr_len != from->addr_len)
510 : 0 : return;
511 : :
512 : : netif_addr_lock_bh(from);
513 : : netif_addr_lock_nested(to);
514 : 0 : __hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
515 : 0 : __dev_set_rx_mode(to);
516 : : netif_addr_unlock(to);
517 : : netif_addr_unlock_bh(from);
518 : : }
519 : : EXPORT_SYMBOL(dev_uc_unsync);
520 : :
521 : : /**
522 : : * dev_uc_flush - Flush unicast addresses
523 : : * @dev: device
524 : : *
525 : : * Flush unicast addresses.
526 : : */
527 : 0 : void dev_uc_flush(struct net_device *dev)
528 : : {
529 : : netif_addr_lock_bh(dev);
530 : 0 : __hw_addr_flush(&dev->uc);
531 : : netif_addr_unlock_bh(dev);
532 : 0 : }
533 : : EXPORT_SYMBOL(dev_uc_flush);
534 : :
535 : : /**
536 : : * dev_uc_flush - Init unicast address list
537 : : * @dev: device
538 : : *
539 : : * Init unicast address list.
540 : : */
541 : 0 : void dev_uc_init(struct net_device *dev)
542 : : {
543 : : __hw_addr_init(&dev->uc);
544 : 0 : }
545 : : EXPORT_SYMBOL(dev_uc_init);
546 : :
547 : : /*
548 : : * Multicast list handling functions
549 : : */
550 : :
551 : : /**
552 : : * dev_mc_add_excl - Add a global secondary multicast address
553 : : * @dev: device
554 : : * @addr: address to add
555 : : */
556 : 0 : int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr)
557 : : {
558 : : struct netdev_hw_addr *ha;
559 : : int err;
560 : :
561 : : netif_addr_lock_bh(dev);
562 [ # # ]: 0 : list_for_each_entry(ha, &dev->mc.list, list) {
563 [ # # ][ # # ]: 0 : if (!memcmp(ha->addr, addr, dev->addr_len) &&
564 : 0 : ha->type == NETDEV_HW_ADDR_T_MULTICAST) {
565 : : err = -EEXIST;
566 : : goto out;
567 : : }
568 : : }
569 : 0 : err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len,
570 : : NETDEV_HW_ADDR_T_MULTICAST, true, false);
571 [ # # ]: 0 : if (!err)
572 : 0 : __dev_set_rx_mode(dev);
573 : : out:
574 : : netif_addr_unlock_bh(dev);
575 : 0 : return err;
576 : : }
577 : : EXPORT_SYMBOL(dev_mc_add_excl);
578 : :
579 : 0 : static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,
580 : : bool global)
581 : : {
582 : : int err;
583 : :
584 : : netif_addr_lock_bh(dev);
585 : 0 : err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
586 : : NETDEV_HW_ADDR_T_MULTICAST, global, false, 0);
587 [ # # ]: 0 : if (!err)
588 : 0 : __dev_set_rx_mode(dev);
589 : : netif_addr_unlock_bh(dev);
590 : 0 : return err;
591 : : }
592 : : /**
593 : : * dev_mc_add - Add a multicast address
594 : : * @dev: device
595 : : * @addr: address to add
596 : : *
597 : : * Add a multicast address to the device or increase
598 : : * the reference count if it already exists.
599 : : */
600 : 0 : int dev_mc_add(struct net_device *dev, const unsigned char *addr)
601 : : {
602 : 0 : return __dev_mc_add(dev, addr, false);
603 : : }
604 : : EXPORT_SYMBOL(dev_mc_add);
605 : :
606 : : /**
607 : : * dev_mc_add_global - Add a global multicast address
608 : : * @dev: device
609 : : * @addr: address to add
610 : : *
611 : : * Add a global multicast address to the device.
612 : : */
613 : 0 : int dev_mc_add_global(struct net_device *dev, const unsigned char *addr)
614 : : {
615 : 0 : return __dev_mc_add(dev, addr, true);
616 : : }
617 : : EXPORT_SYMBOL(dev_mc_add_global);
618 : :
619 : 0 : static int __dev_mc_del(struct net_device *dev, const unsigned char *addr,
620 : : bool global)
621 : : {
622 : : int err;
623 : :
624 : : netif_addr_lock_bh(dev);
625 : 0 : err = __hw_addr_del_ex(&dev->mc, addr, dev->addr_len,
626 : : NETDEV_HW_ADDR_T_MULTICAST, global, false);
627 [ # # ]: 0 : if (!err)
628 : 0 : __dev_set_rx_mode(dev);
629 : : netif_addr_unlock_bh(dev);
630 : 0 : return err;
631 : : }
632 : :
633 : : /**
634 : : * dev_mc_del - Delete a multicast address.
635 : : * @dev: device
636 : : * @addr: address to delete
637 : : *
638 : : * Release reference to a multicast address and remove it
639 : : * from the device if the reference count drops to zero.
640 : : */
641 : 0 : int dev_mc_del(struct net_device *dev, const unsigned char *addr)
642 : : {
643 : 0 : return __dev_mc_del(dev, addr, false);
644 : : }
645 : : EXPORT_SYMBOL(dev_mc_del);
646 : :
647 : : /**
648 : : * dev_mc_del_global - Delete a global multicast address.
649 : : * @dev: device
650 : : * @addr: address to delete
651 : : *
652 : : * Release reference to a multicast address and remove it
653 : : * from the device if the reference count drops to zero.
654 : : */
655 : 0 : int dev_mc_del_global(struct net_device *dev, const unsigned char *addr)
656 : : {
657 : 0 : return __dev_mc_del(dev, addr, true);
658 : : }
659 : : EXPORT_SYMBOL(dev_mc_del_global);
660 : :
661 : : /**
662 : : * dev_mc_sync - Synchronize device's multicast list to another device
663 : : * @to: destination device
664 : : * @from: source device
665 : : *
666 : : * Add newly added addresses to the destination device and release
667 : : * addresses that have no users left. The source device must be
668 : : * locked by netif_addr_lock_bh.
669 : : *
670 : : * This function is intended to be called from the ndo_set_rx_mode
671 : : * function of layered software devices.
672 : : */
673 : 0 : int dev_mc_sync(struct net_device *to, struct net_device *from)
674 : : {
675 : : int err = 0;
676 : :
677 [ # # ]: 0 : if (to->addr_len != from->addr_len)
678 : : return -EINVAL;
679 : :
680 : : netif_addr_lock_nested(to);
681 : 0 : err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
682 [ # # ]: 0 : if (!err)
683 : 0 : __dev_set_rx_mode(to);
684 : : netif_addr_unlock(to);
685 : 0 : return err;
686 : : }
687 : : EXPORT_SYMBOL(dev_mc_sync);
688 : :
689 : : /**
690 : : * dev_mc_sync_multiple - Synchronize device's multicast list to another
691 : : * device, but allow for multiple calls to sync to multiple devices.
692 : : * @to: destination device
693 : : * @from: source device
694 : : *
695 : : * Add newly added addresses to the destination device and release
696 : : * addresses that have no users left. The source device must be
697 : : * locked by netif_addr_lock_bh.
698 : : *
699 : : * This function is intended to be called from the ndo_set_rx_mode
700 : : * function of layered software devices. It allows for a single
701 : : * source device to be synced to multiple destination devices.
702 : : */
703 : 0 : int dev_mc_sync_multiple(struct net_device *to, struct net_device *from)
704 : : {
705 : : int err = 0;
706 : :
707 [ # # ]: 0 : if (to->addr_len != from->addr_len)
708 : : return -EINVAL;
709 : :
710 : : netif_addr_lock_nested(to);
711 : 0 : err = __hw_addr_sync_multiple(&to->mc, &from->mc, to->addr_len);
712 [ # # ]: 0 : if (!err)
713 : 0 : __dev_set_rx_mode(to);
714 : : netif_addr_unlock(to);
715 : 0 : return err;
716 : : }
717 : : EXPORT_SYMBOL(dev_mc_sync_multiple);
718 : :
719 : : /**
720 : : * dev_mc_unsync - Remove synchronized addresses from the destination device
721 : : * @to: destination device
722 : : * @from: source device
723 : : *
724 : : * Remove all addresses that were added to the destination device by
725 : : * dev_mc_sync(). This function is intended to be called from the
726 : : * dev->stop function of layered software devices.
727 : : */
728 : 0 : void dev_mc_unsync(struct net_device *to, struct net_device *from)
729 : : {
730 [ # # ]: 0 : if (to->addr_len != from->addr_len)
731 : 0 : return;
732 : :
733 : : netif_addr_lock_bh(from);
734 : : netif_addr_lock_nested(to);
735 : 0 : __hw_addr_unsync(&to->mc, &from->mc, to->addr_len);
736 : 0 : __dev_set_rx_mode(to);
737 : : netif_addr_unlock(to);
738 : : netif_addr_unlock_bh(from);
739 : : }
740 : : EXPORT_SYMBOL(dev_mc_unsync);
741 : :
742 : : /**
743 : : * dev_mc_flush - Flush multicast addresses
744 : : * @dev: device
745 : : *
746 : : * Flush multicast addresses.
747 : : */
748 : 0 : void dev_mc_flush(struct net_device *dev)
749 : : {
750 : : netif_addr_lock_bh(dev);
751 : 0 : __hw_addr_flush(&dev->mc);
752 : : netif_addr_unlock_bh(dev);
753 : 0 : }
754 : : EXPORT_SYMBOL(dev_mc_flush);
755 : :
756 : : /**
757 : : * dev_mc_flush - Init multicast address list
758 : : * @dev: device
759 : : *
760 : : * Init multicast address list.
761 : : */
762 : 0 : void dev_mc_init(struct net_device *dev)
763 : : {
764 : : __hw_addr_init(&dev->mc);
765 : 0 : }
766 : : EXPORT_SYMBOL(dev_mc_init);
|