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