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_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 48 static 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 75 static 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 82 static 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 108 static 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 115 int __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 131 unroll: 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 } 140 EXPORT_SYMBOL(__hw_addr_add_multiple); 141 142 void __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 } 154 EXPORT_SYMBOL(__hw_addr_del_multiple); 155 156 int __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 } 178 EXPORT_SYMBOL(__hw_addr_sync); 179 180 void __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 } 196 EXPORT_SYMBOL(__hw_addr_unsync); 197 198 void __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 } 208 EXPORT_SYMBOL(__hw_addr_flush); 209 210 void __hw_addr_init(struct netdev_hw_addr_list *list) 211 { 212 INIT_LIST_HEAD(&list->list); 213 list->count = 0; 214 } 215 EXPORT_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 */ 229 void 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 } 236 EXPORT_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 */ 247 int 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 } 270 EXPORT_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 */ 283 int 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 } 295 EXPORT_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 */ 308 int 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 } 332 EXPORT_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 */ 344 int 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 } 360 EXPORT_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 */ 372 int 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 } 385 EXPORT_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 */ 396 int 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); 413 out: 414 netif_addr_unlock_bh(dev); 415 return err; 416 } 417 EXPORT_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 */ 427 int 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 } 439 EXPORT_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 */ 449 int 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 } 461 EXPORT_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 */ 475 int 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 } 489 EXPORT_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 */ 500 void 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 } 512 EXPORT_SYMBOL(dev_uc_unsync); 513 514 /** 515 * dev_uc_flush - Flush unicast addresses 516 * @dev: device 517 * 518 * Flush unicast addresses. 519 */ 520 void 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 } 526 EXPORT_SYMBOL(dev_uc_flush); 527 528 /** 529 * dev_uc_flush - Init unicast address list 530 * @dev: device 531 * 532 * Init unicast address list. 533 */ 534 void dev_uc_init(struct net_device *dev) 535 { 536 __hw_addr_init(&dev->uc); 537 } 538 EXPORT_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 */ 549 int 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); 566 out: 567 netif_addr_unlock_bh(dev); 568 return err; 569 } 570 EXPORT_SYMBOL(dev_mc_add_excl); 571 572 static 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 */ 593 int dev_mc_add(struct net_device *dev, const unsigned char *addr) 594 { 595 return __dev_mc_add(dev, addr, false); 596 } 597 EXPORT_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 */ 606 int dev_mc_add_global(struct net_device *dev, const unsigned char *addr) 607 { 608 return __dev_mc_add(dev, addr, true); 609 } 610 EXPORT_SYMBOL(dev_mc_add_global); 611 612 static 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 */ 634 int dev_mc_del(struct net_device *dev, const unsigned char *addr) 635 { 636 return __dev_mc_del(dev, addr, false); 637 } 638 EXPORT_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 */ 648 int dev_mc_del_global(struct net_device *dev, const unsigned char *addr) 649 { 650 return __dev_mc_del(dev, addr, true); 651 } 652 EXPORT_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 */ 666 int 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 } 680 EXPORT_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 */ 691 void 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 } 703 EXPORT_SYMBOL(dev_mc_unsync); 704 705 /** 706 * dev_mc_flush - Flush multicast addresses 707 * @dev: device 708 * 709 * Flush multicast addresses. 710 */ 711 void 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 } 717 EXPORT_SYMBOL(dev_mc_flush); 718 719 /** 720 * dev_mc_flush - Init multicast address list 721 * @dev: device 722 * 723 * Init multicast address list. 724 */ 725 void dev_mc_init(struct net_device *dev) 726 { 727 __hw_addr_init(&dev->mc); 728 } 729 EXPORT_SYMBOL(dev_mc_init); 730 731 #ifdef CONFIG_PROC_FS 732 #include <linux/seq_file.h> 733 734 static 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 758 static 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 765 static 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 771 static 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 781 static 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 788 static void __net_exit dev_mc_net_exit(struct net *net) 789 { 790 proc_net_remove(net, "dev_mcast"); 791 } 792 793 static struct pernet_operations __net_initdata dev_mc_net_ops = { 794 .init = dev_mc_net_init, 795 .exit = dev_mc_net_exit, 796 }; 797 798 void __init dev_mcast_init(void) 799 { 800 register_pernet_subsys(&dev_mc_net_ops); 801 } 802 803