~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to net/core/dev_addr_lists.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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