.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * INET 802.1Q VLAN |
---|
3 | 4 | * Ethernet-type device handling. |
---|
.. | .. |
---|
11 | 12 | * Add HW acceleration hooks - David S. Miller <davem@redhat.com>; |
---|
12 | 13 | * Correct all the locking - David S. Miller <davem@redhat.com>; |
---|
13 | 14 | * Use hash table for VLAN groups - David S. Miller <davem@redhat.com> |
---|
14 | | - * |
---|
15 | | - * This program is free software; you can redistribute it and/or |
---|
16 | | - * modify it under the terms of the GNU General Public License |
---|
17 | | - * as published by the Free Software Foundation; either version |
---|
18 | | - * 2 of the License, or (at your option) any later version. |
---|
19 | 15 | */ |
---|
20 | 16 | |
---|
21 | 17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
.. | .. |
---|
55 | 51 | __be16 vlan_proto, u16 vlan_id) |
---|
56 | 52 | { |
---|
57 | 53 | struct net_device **array; |
---|
58 | | - unsigned int pidx, vidx; |
---|
| 54 | + unsigned int vidx; |
---|
59 | 55 | unsigned int size; |
---|
| 56 | + int pidx; |
---|
60 | 57 | |
---|
61 | 58 | ASSERT_RTNL(); |
---|
62 | 59 | |
---|
63 | 60 | pidx = vlan_proto_idx(vlan_proto); |
---|
| 61 | + if (pidx < 0) |
---|
| 62 | + return -EINVAL; |
---|
| 63 | + |
---|
64 | 64 | vidx = vlan_id / VLAN_GROUP_ARRAY_PART_LEN; |
---|
65 | 65 | array = vg->vlan_devices_arrays[pidx][vidx]; |
---|
66 | 66 | if (array != NULL) |
---|
.. | .. |
---|
73 | 73 | |
---|
74 | 74 | vg->vlan_devices_arrays[pidx][vidx] = array; |
---|
75 | 75 | return 0; |
---|
| 76 | +} |
---|
| 77 | + |
---|
| 78 | +static void vlan_stacked_transfer_operstate(const struct net_device *rootdev, |
---|
| 79 | + struct net_device *dev, |
---|
| 80 | + struct vlan_dev_priv *vlan) |
---|
| 81 | +{ |
---|
| 82 | + if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) |
---|
| 83 | + netif_stacked_transfer_operstate(rootdev, dev); |
---|
76 | 84 | } |
---|
77 | 85 | |
---|
78 | 86 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head) |
---|
.. | .. |
---|
112 | 120 | } |
---|
113 | 121 | |
---|
114 | 122 | vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); |
---|
115 | | - |
---|
116 | | - /* Get rid of the vlan's reference to real_dev */ |
---|
117 | | - dev_put(real_dev); |
---|
118 | 123 | } |
---|
119 | 124 | |
---|
120 | 125 | int vlan_check_real_dev(struct net_device *real_dev, |
---|
.. | .. |
---|
168 | 173 | if (err < 0) |
---|
169 | 174 | goto out_uninit_mvrp; |
---|
170 | 175 | |
---|
171 | | - vlan->nest_level = dev_get_nest_level(real_dev) + 1; |
---|
172 | 176 | err = register_netdevice(dev); |
---|
173 | 177 | if (err < 0) |
---|
174 | 178 | goto out_uninit_mvrp; |
---|
.. | .. |
---|
177 | 181 | if (err) |
---|
178 | 182 | goto out_unregister_netdev; |
---|
179 | 183 | |
---|
180 | | - /* Account for reference in struct vlan_dev_priv */ |
---|
181 | | - dev_hold(real_dev); |
---|
182 | | - |
---|
183 | | - netif_stacked_transfer_operstate(real_dev, dev); |
---|
| 184 | + vlan_stacked_transfer_operstate(real_dev, dev, vlan); |
---|
184 | 185 | linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ |
---|
185 | 186 | |
---|
186 | 187 | /* So, got the sucker initialized, now lets place |
---|
.. | .. |
---|
277 | 278 | return 0; |
---|
278 | 279 | |
---|
279 | 280 | out_free_newdev: |
---|
280 | | - if (new_dev->reg_state == NETREG_UNINITIALIZED || |
---|
281 | | - new_dev->reg_state == NETREG_UNREGISTERED) |
---|
282 | | - free_netdev(new_dev); |
---|
| 281 | + free_netdev(new_dev); |
---|
283 | 282 | return err; |
---|
284 | 283 | } |
---|
285 | 284 | |
---|
.. | .. |
---|
331 | 330 | |
---|
332 | 331 | vlandev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
---|
333 | 332 | vlandev->priv_flags |= (vlan->real_dev->priv_flags & IFF_XMIT_DST_RELEASE); |
---|
| 333 | + vlandev->hw_enc_features = vlan_tnl_features(vlan->real_dev); |
---|
334 | 334 | |
---|
335 | 335 | netdev_update_features(vlandev); |
---|
336 | 336 | } |
---|
.. | .. |
---|
358 | 358 | static int vlan_device_event(struct notifier_block *unused, unsigned long event, |
---|
359 | 359 | void *ptr) |
---|
360 | 360 | { |
---|
| 361 | + struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr); |
---|
361 | 362 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
---|
362 | 363 | struct vlan_group *grp; |
---|
363 | 364 | struct vlan_info *vlan_info; |
---|
.. | .. |
---|
398 | 399 | case NETDEV_CHANGE: |
---|
399 | 400 | /* Propagate real device state to vlan devices */ |
---|
400 | 401 | vlan_group_for_each_dev(grp, i, vlandev) |
---|
401 | | - netif_stacked_transfer_operstate(dev, vlandev); |
---|
| 402 | + vlan_stacked_transfer_operstate(dev, vlandev, |
---|
| 403 | + vlan_dev_priv(vlandev)); |
---|
402 | 404 | break; |
---|
403 | 405 | |
---|
404 | 406 | case NETDEV_CHANGEADDR: |
---|
.. | .. |
---|
445 | 447 | dev_close_many(&close_list, false); |
---|
446 | 448 | |
---|
447 | 449 | list_for_each_entry_safe(vlandev, tmp, &close_list, close_list) { |
---|
448 | | - netif_stacked_transfer_operstate(dev, vlandev); |
---|
| 450 | + vlan_stacked_transfer_operstate(dev, vlandev, |
---|
| 451 | + vlan_dev_priv(vlandev)); |
---|
449 | 452 | list_del_init(&vlandev->close_list); |
---|
450 | 453 | } |
---|
451 | 454 | list_del(&close_list); |
---|
.. | .. |
---|
460 | 463 | |
---|
461 | 464 | vlan = vlan_dev_priv(vlandev); |
---|
462 | 465 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
---|
463 | | - dev_change_flags(vlandev, flgs | IFF_UP); |
---|
464 | | - netif_stacked_transfer_operstate(dev, vlandev); |
---|
| 466 | + dev_change_flags(vlandev, flgs | IFF_UP, |
---|
| 467 | + extack); |
---|
| 468 | + vlan_stacked_transfer_operstate(dev, vlandev, vlan); |
---|
465 | 469 | } |
---|
466 | 470 | break; |
---|
467 | 471 | |
---|
.. | .. |
---|
648 | 652 | return err; |
---|
649 | 653 | } |
---|
650 | 654 | |
---|
651 | | -static struct sk_buff *vlan_gro_receive(struct list_head *head, |
---|
652 | | - struct sk_buff *skb) |
---|
653 | | -{ |
---|
654 | | - const struct packet_offload *ptype; |
---|
655 | | - unsigned int hlen, off_vlan; |
---|
656 | | - struct sk_buff *pp = NULL; |
---|
657 | | - struct vlan_hdr *vhdr; |
---|
658 | | - struct sk_buff *p; |
---|
659 | | - __be16 type; |
---|
660 | | - int flush = 1; |
---|
661 | | - |
---|
662 | | - off_vlan = skb_gro_offset(skb); |
---|
663 | | - hlen = off_vlan + sizeof(*vhdr); |
---|
664 | | - vhdr = skb_gro_header_fast(skb, off_vlan); |
---|
665 | | - if (skb_gro_header_hard(skb, hlen)) { |
---|
666 | | - vhdr = skb_gro_header_slow(skb, hlen, off_vlan); |
---|
667 | | - if (unlikely(!vhdr)) |
---|
668 | | - goto out; |
---|
669 | | - } |
---|
670 | | - |
---|
671 | | - type = vhdr->h_vlan_encapsulated_proto; |
---|
672 | | - |
---|
673 | | - rcu_read_lock(); |
---|
674 | | - ptype = gro_find_receive_by_type(type); |
---|
675 | | - if (!ptype) |
---|
676 | | - goto out_unlock; |
---|
677 | | - |
---|
678 | | - flush = 0; |
---|
679 | | - |
---|
680 | | - list_for_each_entry(p, head, list) { |
---|
681 | | - struct vlan_hdr *vhdr2; |
---|
682 | | - |
---|
683 | | - if (!NAPI_GRO_CB(p)->same_flow) |
---|
684 | | - continue; |
---|
685 | | - |
---|
686 | | - vhdr2 = (struct vlan_hdr *)(p->data + off_vlan); |
---|
687 | | - if (compare_vlan_header(vhdr, vhdr2)) |
---|
688 | | - NAPI_GRO_CB(p)->same_flow = 0; |
---|
689 | | - } |
---|
690 | | - |
---|
691 | | - skb_gro_pull(skb, sizeof(*vhdr)); |
---|
692 | | - skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr)); |
---|
693 | | - pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); |
---|
694 | | - |
---|
695 | | -out_unlock: |
---|
696 | | - rcu_read_unlock(); |
---|
697 | | -out: |
---|
698 | | - skb_gro_flush_final(skb, pp, flush); |
---|
699 | | - |
---|
700 | | - return pp; |
---|
701 | | -} |
---|
702 | | - |
---|
703 | | -static int vlan_gro_complete(struct sk_buff *skb, int nhoff) |
---|
704 | | -{ |
---|
705 | | - struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data + nhoff); |
---|
706 | | - __be16 type = vhdr->h_vlan_encapsulated_proto; |
---|
707 | | - struct packet_offload *ptype; |
---|
708 | | - int err = -ENOENT; |
---|
709 | | - |
---|
710 | | - rcu_read_lock(); |
---|
711 | | - ptype = gro_find_complete_by_type(type); |
---|
712 | | - if (ptype) |
---|
713 | | - err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(*vhdr)); |
---|
714 | | - |
---|
715 | | - rcu_read_unlock(); |
---|
716 | | - return err; |
---|
717 | | -} |
---|
718 | | - |
---|
719 | | -static struct packet_offload vlan_packet_offloads[] __read_mostly = { |
---|
720 | | - { |
---|
721 | | - .type = cpu_to_be16(ETH_P_8021Q), |
---|
722 | | - .priority = 10, |
---|
723 | | - .callbacks = { |
---|
724 | | - .gro_receive = vlan_gro_receive, |
---|
725 | | - .gro_complete = vlan_gro_complete, |
---|
726 | | - }, |
---|
727 | | - }, |
---|
728 | | - { |
---|
729 | | - .type = cpu_to_be16(ETH_P_8021AD), |
---|
730 | | - .priority = 10, |
---|
731 | | - .callbacks = { |
---|
732 | | - .gro_receive = vlan_gro_receive, |
---|
733 | | - .gro_complete = vlan_gro_complete, |
---|
734 | | - }, |
---|
735 | | - }, |
---|
736 | | -}; |
---|
737 | | - |
---|
738 | 655 | static int __net_init vlan_init_net(struct net *net) |
---|
739 | 656 | { |
---|
740 | 657 | struct vlan_net *vn = net_generic(net, vlan_net_id); |
---|
.. | .. |
---|
762 | 679 | static int __init vlan_proto_init(void) |
---|
763 | 680 | { |
---|
764 | 681 | int err; |
---|
765 | | - unsigned int i; |
---|
766 | 682 | |
---|
767 | 683 | pr_info("%s v%s\n", vlan_fullname, vlan_version); |
---|
768 | 684 | |
---|
.. | .. |
---|
786 | 702 | if (err < 0) |
---|
787 | 703 | goto err5; |
---|
788 | 704 | |
---|
789 | | - for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) |
---|
790 | | - dev_add_offload(&vlan_packet_offloads[i]); |
---|
791 | | - |
---|
792 | 705 | vlan_ioctl_set(vlan_ioctl_handler); |
---|
793 | 706 | return 0; |
---|
794 | 707 | |
---|
.. | .. |
---|
806 | 719 | |
---|
807 | 720 | static void __exit vlan_cleanup_module(void) |
---|
808 | 721 | { |
---|
809 | | - unsigned int i; |
---|
810 | | - |
---|
811 | 722 | vlan_ioctl_set(NULL); |
---|
812 | | - |
---|
813 | | - for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) |
---|
814 | | - dev_remove_offload(&vlan_packet_offloads[i]); |
---|
815 | 723 | |
---|
816 | 724 | vlan_netlink_fini(); |
---|
817 | 725 | |
---|