Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/ncsi: Refactor MAC, VLAN filters

The NCSI driver defines a generic ncsi_channel_filter struct that can be
used to store arbitrarily formatted filters, and several generic methods
of accessing data stored in such a filter.
However in both the driver and as defined in the NCSI specification
there are only two actual filters: VLAN ID filters and MAC address
filters. The splitting of the MAC filter into unicast, multicast, and
mixed is also technically not necessary as these are stored in the same
location in hardware.

To save complexity, particularly in the set up and accessing of these
generic filters, remove them in favour of two specific structs. These
can be acted on directly and do not need several generic helper
functions to use.

This also fixes a memory error found by KASAN on ARM32 (which is not
upstream yet), where response handlers accessing a filter's data field
could write past allocated memory.

[ 114.926512] ==================================================================
[ 114.933861] BUG: KASAN: slab-out-of-bounds in ncsi_configure_channel+0x4b8/0xc58
[ 114.941304] Read of size 2 at addr 94888558 by task kworker/0:2/546
[ 114.947593]
[ 114.949146] CPU: 0 PID: 546 Comm: kworker/0:2 Not tainted 4.16.0-rc6-00119-ge156398bfcad #13
...
[ 115.170233] The buggy address belongs to the object at 94888540
[ 115.170233] which belongs to the cache kmalloc-32 of size 32
[ 115.181917] The buggy address is located 24 bytes inside of
[ 115.181917] 32-byte region [94888540, 94888560)
[ 115.192115] The buggy address belongs to the page:
[ 115.196943] page:9eeac100 count:1 mapcount:0 mapping:94888000 index:0x94888fc1
[ 115.204200] flags: 0x100(slab)
[ 115.207330] raw: 00000100 94888000 94888fc1 0000003f 00000001 9eea2014 9eecaa74 96c003e0
[ 115.215444] page dumped because: kasan: bad access detected
[ 115.221036]
[ 115.222544] Memory state around the buggy address:
[ 115.227384] 94888400: fb fb fb fb fc fc fc fc 04 fc fc fc fc fc fc fc
[ 115.233959] 94888480: 00 00 00 fc fc fc fc fc 00 04 fc fc fc fc fc fc
[ 115.240529] >94888500: 00 00 04 fc fc fc fc fc 00 00 04 fc fc fc fc fc
[ 115.247077] ^
[ 115.252523] 94888580: 00 04 fc fc fc fc fc fc 06 fc fc fc fc fc fc fc
[ 115.259093] 94888600: 00 00 06 fc fc fc fc fc 00 00 04 fc fc fc fc fc
[ 115.265639] ==================================================================

Reported-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Samuel Mendoza-Jonas and committed by
David S. Miller
062b3e1b c210f7b4

+147 -311
+15 -19
net/ncsi/internal.h
··· 68 68 NCSI_MODE_MAX 69 69 }; 70 70 71 - enum { 72 - NCSI_FILTER_BASE = 0, 73 - NCSI_FILTER_VLAN = 0, 74 - NCSI_FILTER_UC, 75 - NCSI_FILTER_MC, 76 - NCSI_FILTER_MIXED, 77 - NCSI_FILTER_MAX 78 - }; 79 - 80 71 struct ncsi_channel_version { 81 72 u32 version; /* Supported BCD encoded NCSI version */ 82 73 u32 alpha2; /* Supported BCD encoded NCSI version */ ··· 89 98 u32 data[8]; /* Data entries */ 90 99 }; 91 100 92 - struct ncsi_channel_filter { 93 - u32 index; /* Index of channel filters */ 94 - u32 total; /* Total entries in the filter table */ 95 - u64 bitmap; /* Bitmap of valid entries */ 96 - u32 data[]; /* Data for the valid entries */ 101 + struct ncsi_channel_mac_filter { 102 + u8 n_uc; 103 + u8 n_mc; 104 + u8 n_mixed; 105 + u64 bitmap; 106 + unsigned char *addrs; 107 + }; 108 + 109 + struct ncsi_channel_vlan_filter { 110 + u8 n_vids; 111 + u64 bitmap; 112 + u16 *vids; 97 113 }; 98 114 99 115 struct ncsi_channel_stats { ··· 184 186 struct ncsi_channel_version version; 185 187 struct ncsi_channel_cap caps[NCSI_CAP_MAX]; 186 188 struct ncsi_channel_mode modes[NCSI_MODE_MAX]; 187 - struct ncsi_channel_filter *filters[NCSI_FILTER_MAX]; 189 + /* Filtering Settings */ 190 + struct ncsi_channel_mac_filter mac_filter; 191 + struct ncsi_channel_vlan_filter vlan_filter; 188 192 struct ncsi_channel_stats stats; 189 193 struct { 190 194 struct timer_list timer; ··· 320 320 list_for_each_entry_rcu(nc, &np->channels, node) 321 321 322 322 /* Resources */ 323 - u32 *ncsi_get_filter(struct ncsi_channel *nc, int table, int index); 324 - int ncsi_find_filter(struct ncsi_channel *nc, int table, void *data); 325 - int ncsi_add_filter(struct ncsi_channel *nc, int table, void *data); 326 - int ncsi_remove_filter(struct ncsi_channel *nc, int table, int index); 327 323 void ncsi_start_channel_monitor(struct ncsi_channel *nc); 328 324 void ncsi_stop_channel_monitor(struct ncsi_channel *nc); 329 325 struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np,
+53 -175
net/ncsi/ncsi-manage.c
··· 27 27 LIST_HEAD(ncsi_dev_list); 28 28 DEFINE_SPINLOCK(ncsi_dev_lock); 29 29 30 - static inline int ncsi_filter_size(int table) 31 - { 32 - int sizes[] = { 2, 6, 6, 6 }; 33 - 34 - BUILD_BUG_ON(ARRAY_SIZE(sizes) != NCSI_FILTER_MAX); 35 - if (table < NCSI_FILTER_BASE || table >= NCSI_FILTER_MAX) 36 - return -EINVAL; 37 - 38 - return sizes[table]; 39 - } 40 - 41 - u32 *ncsi_get_filter(struct ncsi_channel *nc, int table, int index) 42 - { 43 - struct ncsi_channel_filter *ncf; 44 - int size; 45 - 46 - ncf = nc->filters[table]; 47 - if (!ncf) 48 - return NULL; 49 - 50 - size = ncsi_filter_size(table); 51 - if (size < 0) 52 - return NULL; 53 - 54 - return ncf->data + size * index; 55 - } 56 - 57 - /* Find the first active filter in a filter table that matches the given 58 - * data parameter. If data is NULL, this returns the first active filter. 59 - */ 60 - int ncsi_find_filter(struct ncsi_channel *nc, int table, void *data) 61 - { 62 - struct ncsi_channel_filter *ncf; 63 - void *bitmap; 64 - int index, size; 65 - unsigned long flags; 66 - 67 - ncf = nc->filters[table]; 68 - if (!ncf) 69 - return -ENXIO; 70 - 71 - size = ncsi_filter_size(table); 72 - if (size < 0) 73 - return size; 74 - 75 - spin_lock_irqsave(&nc->lock, flags); 76 - bitmap = (void *)&ncf->bitmap; 77 - index = -1; 78 - while ((index = find_next_bit(bitmap, ncf->total, index + 1)) 79 - < ncf->total) { 80 - if (!data || !memcmp(ncf->data + size * index, data, size)) { 81 - spin_unlock_irqrestore(&nc->lock, flags); 82 - return index; 83 - } 84 - } 85 - spin_unlock_irqrestore(&nc->lock, flags); 86 - 87 - return -ENOENT; 88 - } 89 - 90 - int ncsi_add_filter(struct ncsi_channel *nc, int table, void *data) 91 - { 92 - struct ncsi_channel_filter *ncf; 93 - int index, size; 94 - void *bitmap; 95 - unsigned long flags; 96 - 97 - size = ncsi_filter_size(table); 98 - if (size < 0) 99 - return size; 100 - 101 - index = ncsi_find_filter(nc, table, data); 102 - if (index >= 0) 103 - return index; 104 - 105 - ncf = nc->filters[table]; 106 - if (!ncf) 107 - return -ENODEV; 108 - 109 - spin_lock_irqsave(&nc->lock, flags); 110 - bitmap = (void *)&ncf->bitmap; 111 - do { 112 - index = find_next_zero_bit(bitmap, ncf->total, 0); 113 - if (index >= ncf->total) { 114 - spin_unlock_irqrestore(&nc->lock, flags); 115 - return -ENOSPC; 116 - } 117 - } while (test_and_set_bit(index, bitmap)); 118 - 119 - memcpy(ncf->data + size * index, data, size); 120 - spin_unlock_irqrestore(&nc->lock, flags); 121 - 122 - return index; 123 - } 124 - 125 - int ncsi_remove_filter(struct ncsi_channel *nc, int table, int index) 126 - { 127 - struct ncsi_channel_filter *ncf; 128 - int size; 129 - void *bitmap; 130 - unsigned long flags; 131 - 132 - size = ncsi_filter_size(table); 133 - if (size < 0) 134 - return size; 135 - 136 - ncf = nc->filters[table]; 137 - if (!ncf || index >= ncf->total) 138 - return -ENODEV; 139 - 140 - spin_lock_irqsave(&nc->lock, flags); 141 - bitmap = (void *)&ncf->bitmap; 142 - if (test_and_clear_bit(index, bitmap)) 143 - memset(ncf->data + size * index, 0, size); 144 - spin_unlock_irqrestore(&nc->lock, flags); 145 - 146 - return 0; 147 - } 148 - 149 30 static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down) 150 31 { 151 32 struct ncsi_dev *nd = &ndp->ndev; ··· 220 339 static void ncsi_remove_channel(struct ncsi_channel *nc) 221 340 { 222 341 struct ncsi_package *np = nc->package; 223 - struct ncsi_channel_filter *ncf; 224 342 unsigned long flags; 225 - int i; 343 + 344 + spin_lock_irqsave(&nc->lock, flags); 226 345 227 346 /* Release filters */ 228 - spin_lock_irqsave(&nc->lock, flags); 229 - for (i = 0; i < NCSI_FILTER_MAX; i++) { 230 - ncf = nc->filters[i]; 231 - if (!ncf) 232 - continue; 233 - 234 - nc->filters[i] = NULL; 235 - kfree(ncf); 236 - } 347 + kfree(nc->mac_filter.addrs); 348 + kfree(nc->vlan_filter.vids); 237 349 238 350 nc->state = NCSI_CHANNEL_INACTIVE; 239 351 spin_unlock_irqrestore(&nc->lock, flags); ··· 544 670 static int clear_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, 545 671 struct ncsi_cmd_arg *nca) 546 672 { 673 + struct ncsi_channel_vlan_filter *ncf; 674 + unsigned long flags; 675 + void *bitmap; 547 676 int index; 548 - u32 *data; 549 677 u16 vid; 550 678 551 - index = ncsi_find_filter(nc, NCSI_FILTER_VLAN, NULL); 552 - if (index < 0) { 553 - /* Filter table empty */ 679 + ncf = &nc->vlan_filter; 680 + bitmap = &ncf->bitmap; 681 + 682 + spin_lock_irqsave(&nc->lock, flags); 683 + index = find_next_bit(bitmap, ncf->n_vids, 0); 684 + if (index >= ncf->n_vids) { 685 + spin_unlock_irqrestore(&nc->lock, flags); 554 686 return -1; 555 687 } 688 + vid = ncf->vids[index]; 556 689 557 - data = ncsi_get_filter(nc, NCSI_FILTER_VLAN, index); 558 - if (!data) { 559 - netdev_err(ndp->ndev.dev, 560 - "NCSI: failed to retrieve filter %d\n", index); 561 - /* Set the VLAN id to 0 - this will still disable the entry in 562 - * the filter table, but we won't know what it was. 563 - */ 564 - vid = 0; 565 - } else { 566 - vid = *(u16 *)data; 567 - } 568 - 569 - netdev_printk(KERN_DEBUG, ndp->ndev.dev, 570 - "NCSI: removed vlan tag %u at index %d\n", 571 - vid, index + 1); 572 - ncsi_remove_filter(nc, NCSI_FILTER_VLAN, index); 690 + clear_bit(index, bitmap); 691 + ncf->vids[index] = 0; 692 + spin_unlock_irqrestore(&nc->lock, flags); 573 693 574 694 nca->type = NCSI_PKT_CMD_SVF; 575 695 nca->words[1] = vid; ··· 579 711 static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, 580 712 struct ncsi_cmd_arg *nca) 581 713 { 714 + struct ncsi_channel_vlan_filter *ncf; 582 715 struct vlan_vid *vlan = NULL; 583 - int index = 0; 716 + unsigned long flags; 717 + int i, index; 718 + void *bitmap; 719 + u16 vid; 584 720 721 + if (list_empty(&ndp->vlan_vids)) 722 + return -1; 723 + 724 + ncf = &nc->vlan_filter; 725 + bitmap = &ncf->bitmap; 726 + 727 + spin_lock_irqsave(&nc->lock, flags); 728 + 729 + rcu_read_lock(); 585 730 list_for_each_entry_rcu(vlan, &ndp->vlan_vids, list) { 586 - index = ncsi_find_filter(nc, NCSI_FILTER_VLAN, &vlan->vid); 587 - if (index < 0) { 588 - /* New tag to add */ 589 - netdev_printk(KERN_DEBUG, ndp->ndev.dev, 590 - "NCSI: new vlan id to set: %u\n", 591 - vlan->vid); 731 + vid = vlan->vid; 732 + for (i = 0; i < ncf->n_vids; i++) 733 + if (ncf->vids[i] == vid) { 734 + vid = 0; 735 + break; 736 + } 737 + if (vid) 592 738 break; 593 - } 594 - netdev_printk(KERN_DEBUG, ndp->ndev.dev, 595 - "vid %u already at filter pos %d\n", 596 - vlan->vid, index); 597 739 } 740 + rcu_read_unlock(); 598 741 599 - if (!vlan || index >= 0) { 600 - netdev_printk(KERN_DEBUG, ndp->ndev.dev, 601 - "no vlan ids left to set\n"); 742 + if (!vid) { 743 + /* No VLAN ID is not set */ 744 + spin_unlock_irqrestore(&nc->lock, flags); 602 745 return -1; 603 746 } 604 747 605 - index = ncsi_add_filter(nc, NCSI_FILTER_VLAN, &vlan->vid); 606 - if (index < 0) { 748 + index = find_next_zero_bit(bitmap, ncf->n_vids, 0); 749 + if (index < 0 || index >= ncf->n_vids) { 607 750 netdev_err(ndp->ndev.dev, 608 - "Failed to add new VLAN tag, error %d\n", index); 609 - if (index == -ENOSPC) 610 - netdev_err(ndp->ndev.dev, 611 - "Channel %u already has all VLAN filters set\n", 612 - nc->id); 751 + "Channel %u already has all VLAN filters set\n", 752 + nc->id); 753 + spin_unlock_irqrestore(&nc->lock, flags); 613 754 return -1; 614 755 } 615 756 616 - netdev_printk(KERN_DEBUG, ndp->ndev.dev, 617 - "NCSI: set vid %u in packet, index %u\n", 618 - vlan->vid, index + 1); 757 + ncf->vids[index] = vid; 758 + set_bit(index, bitmap); 759 + spin_unlock_irqrestore(&nc->lock, flags); 760 + 619 761 nca->type = NCSI_PKT_CMD_SVF; 620 - nca->words[1] = vlan->vid; 762 + nca->words[1] = vid; 621 763 /* HW filter index starts at 1 */ 622 764 nca->bytes[6] = index + 1; 623 765 nca->bytes[7] = 0x01;
+7 -13
net/ncsi/ncsi-netlink.c
··· 58 58 struct ncsi_dev_priv *ndp, 59 59 struct ncsi_channel *nc) 60 60 { 61 - struct nlattr *vid_nest; 62 - struct ncsi_channel_filter *ncf; 61 + struct ncsi_channel_vlan_filter *ncf; 63 62 struct ncsi_channel_mode *m; 64 - u32 *data; 63 + struct nlattr *vid_nest; 65 64 int i; 66 65 67 66 nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id); ··· 78 79 vid_nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR_VLAN_LIST); 79 80 if (!vid_nest) 80 81 return -ENOMEM; 81 - ncf = nc->filters[NCSI_FILTER_VLAN]; 82 + ncf = &nc->vlan_filter; 82 83 i = -1; 83 - if (ncf) { 84 - while ((i = find_next_bit((void *)&ncf->bitmap, ncf->total, 85 - i + 1)) < ncf->total) { 86 - data = ncsi_get_filter(nc, NCSI_FILTER_VLAN, i); 87 - /* Uninitialised channels will have 'zero' vlan ids */ 88 - if (!data || !*data) 89 - continue; 84 + while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids, 85 + i + 1)) < ncf->n_vids) { 86 + if (ncf->vids[i]) 90 87 nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID, 91 - *(u16 *)data); 92 - } 88 + ncf->vids[i]); 93 89 } 94 90 nla_nest_end(skb, vid_nest); 95 91
+72 -104
net/ncsi/ncsi-rsp.c
··· 334 334 struct ncsi_rsp_pkt *rsp; 335 335 struct ncsi_dev_priv *ndp = nr->ndp; 336 336 struct ncsi_channel *nc; 337 - struct ncsi_channel_filter *ncf; 338 - unsigned short vlan; 339 - int ret; 337 + struct ncsi_channel_vlan_filter *ncf; 338 + unsigned long flags; 339 + void *bitmap; 340 340 341 341 /* Find the package and channel */ 342 342 rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ··· 346 346 return -ENODEV; 347 347 348 348 cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd); 349 - ncf = nc->filters[NCSI_FILTER_VLAN]; 350 - if (!ncf) 351 - return -ENOENT; 352 - if (cmd->index >= ncf->total) 349 + ncf = &nc->vlan_filter; 350 + if (cmd->index > ncf->n_vids) 353 351 return -ERANGE; 354 352 355 - /* Add or remove the VLAN filter */ 353 + /* Add or remove the VLAN filter. Remember HW indexes from 1 */ 354 + spin_lock_irqsave(&nc->lock, flags); 355 + bitmap = &ncf->bitmap; 356 356 if (!(cmd->enable & 0x1)) { 357 - /* HW indexes from 1 */ 358 - ret = ncsi_remove_filter(nc, NCSI_FILTER_VLAN, cmd->index - 1); 357 + if (test_and_clear_bit(cmd->index - 1, bitmap)) 358 + ncf->vids[cmd->index - 1] = 0; 359 359 } else { 360 - vlan = ntohs(cmd->vlan); 361 - ret = ncsi_add_filter(nc, NCSI_FILTER_VLAN, &vlan); 360 + set_bit(cmd->index - 1, bitmap); 361 + ncf->vids[cmd->index - 1] = ntohs(cmd->vlan); 362 362 } 363 + spin_unlock_irqrestore(&nc->lock, flags); 363 364 364 - return ret; 365 + return 0; 365 366 } 366 367 367 368 static int ncsi_rsp_handler_ev(struct ncsi_request *nr) ··· 423 422 struct ncsi_rsp_pkt *rsp; 424 423 struct ncsi_dev_priv *ndp = nr->ndp; 425 424 struct ncsi_channel *nc; 426 - struct ncsi_channel_filter *ncf; 425 + struct ncsi_channel_mac_filter *ncf; 426 + unsigned long flags; 427 427 void *bitmap; 428 + bool enabled; 429 + int index; 430 + 428 431 429 432 /* Find the package and channel */ 430 433 rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ··· 441 436 * isn't supported yet. 442 437 */ 443 438 cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd); 444 - switch (cmd->at_e >> 5) { 445 - case 0x0: /* UC address */ 446 - ncf = nc->filters[NCSI_FILTER_UC]; 447 - break; 448 - case 0x1: /* MC address */ 449 - ncf = nc->filters[NCSI_FILTER_MC]; 450 - break; 451 - default: 452 - return -EINVAL; 453 - } 439 + enabled = cmd->at_e & 0x1; 440 + ncf = &nc->mac_filter; 441 + bitmap = &ncf->bitmap; 454 442 455 - /* Sanity check on the filter */ 456 - if (!ncf) 457 - return -ENOENT; 458 - else if (cmd->index >= ncf->total) 443 + if (cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed) 459 444 return -ERANGE; 460 445 461 - bitmap = &ncf->bitmap; 462 - if (cmd->at_e & 0x1) { 463 - set_bit(cmd->index, bitmap); 464 - memcpy(ncf->data + 6 * cmd->index, cmd->mac, 6); 446 + index = (cmd->index - 1) * ETH_ALEN; 447 + spin_lock_irqsave(&nc->lock, flags); 448 + if (enabled) { 449 + set_bit(cmd->index - 1, bitmap); 450 + memcpy(&ncf->addrs[index], cmd->mac, ETH_ALEN); 465 451 } else { 466 - clear_bit(cmd->index, bitmap); 467 - memset(ncf->data + 6 * cmd->index, 0, 6); 452 + clear_bit(cmd->index - 1, bitmap); 453 + memset(&ncf->addrs[index], 0, ETH_ALEN); 468 454 } 455 + spin_unlock_irqrestore(&nc->lock, flags); 469 456 470 457 return 0; 471 458 } ··· 628 631 struct ncsi_rsp_gc_pkt *rsp; 629 632 struct ncsi_dev_priv *ndp = nr->ndp; 630 633 struct ncsi_channel *nc; 631 - struct ncsi_channel_filter *ncf; 632 - size_t size, entry_size; 633 - int cnt, i; 634 + size_t size; 634 635 635 636 /* Find the channel */ 636 637 rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp); ··· 650 655 nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode & 651 656 NCSI_CAP_VLAN_MASK; 652 657 653 - /* Build filters */ 654 - for (i = 0; i < NCSI_FILTER_MAX; i++) { 655 - switch (i) { 656 - case NCSI_FILTER_VLAN: 657 - cnt = rsp->vlan_cnt; 658 - entry_size = 2; 659 - break; 660 - case NCSI_FILTER_MIXED: 661 - cnt = rsp->mixed_cnt; 662 - entry_size = 6; 663 - break; 664 - case NCSI_FILTER_MC: 665 - cnt = rsp->mc_cnt; 666 - entry_size = 6; 667 - break; 668 - case NCSI_FILTER_UC: 669 - cnt = rsp->uc_cnt; 670 - entry_size = 6; 671 - break; 672 - default: 673 - continue; 674 - } 658 + size = (rsp->uc_cnt + rsp->mc_cnt + rsp->mixed_cnt) * ETH_ALEN; 659 + nc->mac_filter.addrs = kzalloc(size, GFP_KERNEL); 660 + if (!nc->mac_filter.addrs) 661 + return -ENOMEM; 662 + nc->mac_filter.n_uc = rsp->uc_cnt; 663 + nc->mac_filter.n_mc = rsp->mc_cnt; 664 + nc->mac_filter.n_mixed = rsp->mixed_cnt; 675 665 676 - if (!cnt || nc->filters[i]) 677 - continue; 678 - 679 - size = sizeof(*ncf) + cnt * entry_size; 680 - ncf = kzalloc(size, GFP_ATOMIC); 681 - if (!ncf) { 682 - pr_warn("%s: Cannot alloc filter table (%d)\n", 683 - __func__, i); 684 - return -ENOMEM; 685 - } 686 - 687 - ncf->index = i; 688 - ncf->total = cnt; 689 - if (i == NCSI_FILTER_VLAN) { 690 - /* Set VLAN filters active so they are cleared in 691 - * first configuration state 692 - */ 693 - ncf->bitmap = U64_MAX; 694 - } else { 695 - ncf->bitmap = 0x0ul; 696 - } 697 - nc->filters[i] = ncf; 698 - } 666 + nc->vlan_filter.vids = kcalloc(rsp->vlan_cnt, 667 + sizeof(*nc->vlan_filter.vids), 668 + GFP_KERNEL); 669 + if (!nc->vlan_filter.vids) 670 + return -ENOMEM; 671 + /* Set VLAN filters active so they are cleared in the first 672 + * configuration state 673 + */ 674 + nc->vlan_filter.bitmap = U64_MAX; 675 + nc->vlan_filter.n_vids = rsp->vlan_cnt; 699 676 700 677 return 0; 701 678 } 702 679 703 680 static int ncsi_rsp_handler_gp(struct ncsi_request *nr) 704 681 { 705 - struct ncsi_rsp_gp_pkt *rsp; 682 + struct ncsi_channel_vlan_filter *ncvf; 683 + struct ncsi_channel_mac_filter *ncmf; 706 684 struct ncsi_dev_priv *ndp = nr->ndp; 685 + struct ncsi_rsp_gp_pkt *rsp; 707 686 struct ncsi_channel *nc; 708 - unsigned short enable, vlan; 687 + unsigned short enable; 709 688 unsigned char *pdata; 710 - int table, i; 689 + unsigned long flags; 690 + void *bitmap; 691 + int i; 711 692 712 693 /* Find the channel */ 713 694 rsp = (struct ncsi_rsp_gp_pkt *)skb_network_header(nr->rsp); ··· 717 746 /* MAC addresses filter table */ 718 747 pdata = (unsigned char *)rsp + 48; 719 748 enable = rsp->mac_enable; 749 + ncmf = &nc->mac_filter; 750 + spin_lock_irqsave(&nc->lock, flags); 751 + bitmap = &ncmf->bitmap; 720 752 for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) { 721 - if (i >= (nc->filters[NCSI_FILTER_UC]->total + 722 - nc->filters[NCSI_FILTER_MC]->total)) 723 - table = NCSI_FILTER_MIXED; 724 - else if (i >= nc->filters[NCSI_FILTER_UC]->total) 725 - table = NCSI_FILTER_MC; 726 - else 727 - table = NCSI_FILTER_UC; 728 - 729 753 if (!(enable & (0x1 << i))) 730 - continue; 754 + clear_bit(i, bitmap); 755 + else 756 + set_bit(i, bitmap); 731 757 732 - if (ncsi_find_filter(nc, table, pdata) >= 0) 733 - continue; 734 - 735 - ncsi_add_filter(nc, table, pdata); 758 + memcpy(&ncmf->addrs[i * ETH_ALEN], pdata, ETH_ALEN); 736 759 } 760 + spin_unlock_irqrestore(&nc->lock, flags); 737 761 738 762 /* VLAN filter table */ 739 763 enable = ntohs(rsp->vlan_enable); 764 + ncvf = &nc->vlan_filter; 765 + bitmap = &ncvf->bitmap; 766 + spin_lock_irqsave(&nc->lock, flags); 740 767 for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) { 741 768 if (!(enable & (0x1 << i))) 742 - continue; 769 + clear_bit(i, bitmap); 770 + else 771 + set_bit(i, bitmap); 743 772 744 - vlan = ntohs(*(__be16 *)pdata); 745 - if (ncsi_find_filter(nc, NCSI_FILTER_VLAN, &vlan) >= 0) 746 - continue; 747 - 748 - ncsi_add_filter(nc, NCSI_FILTER_VLAN, &vlan); 773 + ncvf->vids[i] = ntohs(*(__be16 *)pdata); 749 774 } 775 + spin_unlock_irqrestore(&nc->lock, flags); 750 776 751 777 return 0; 752 778 }