diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r-- | net/8021q/vlan_dev.c | 217 |
1 files changed, 72 insertions, 145 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index ec46084f44b4..d4a62d1b52b4 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -73,7 +73,7 @@ int vlan_dev_rebuild_header(struct sk_buff *skb) | |||
73 | 73 | ||
74 | static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) | 74 | static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) |
75 | { | 75 | { |
76 | if (VLAN_DEV_INFO(skb->dev)->flags & 1) { | 76 | if (VLAN_DEV_INFO(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) { |
77 | if (skb_shared(skb) || skb_cloned(skb)) { | 77 | if (skb_shared(skb) || skb_cloned(skb)) { |
78 | struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); | 78 | struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); |
79 | kfree_skb(skb); | 79 | kfree_skb(skb); |
@@ -350,7 +350,8 @@ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
350 | * header shuffling in the hard_start_xmit. Users can turn off this | 350 | * header shuffling in the hard_start_xmit. Users can turn off this |
351 | * REORDER behaviour with the vconfig tool. | 351 | * REORDER behaviour with the vconfig tool. |
352 | */ | 352 | */ |
353 | build_vlan_header = ((VLAN_DEV_INFO(dev)->flags & 1) == 0); | 353 | if (!(VLAN_DEV_INFO(dev)->flags & VLAN_FLAG_REORDER_HDR)) |
354 | build_vlan_header = 1; | ||
354 | 355 | ||
355 | if (build_vlan_header) { | 356 | if (build_vlan_header) { |
356 | vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); | 357 | vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); |
@@ -534,172 +535,81 @@ int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) | |||
534 | return 0; | 535 | return 0; |
535 | } | 536 | } |
536 | 537 | ||
537 | int vlan_dev_set_ingress_priority(char *dev_name, __u32 skb_prio, short vlan_prio) | 538 | void vlan_dev_set_ingress_priority(const struct net_device *dev, |
539 | u32 skb_prio, short vlan_prio) | ||
538 | { | 540 | { |
539 | struct net_device *dev = dev_get_by_name(dev_name); | 541 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); |
540 | 542 | ||
541 | if (dev) { | 543 | if (vlan->ingress_priority_map[vlan_prio & 0x7] && !skb_prio) |
542 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | 544 | vlan->nr_ingress_mappings--; |
543 | /* see if a priority mapping exists.. */ | 545 | else if (!vlan->ingress_priority_map[vlan_prio & 0x7] && skb_prio) |
544 | VLAN_DEV_INFO(dev)->ingress_priority_map[vlan_prio & 0x7] = skb_prio; | 546 | vlan->nr_ingress_mappings++; |
545 | dev_put(dev); | ||
546 | return 0; | ||
547 | } | ||
548 | 547 | ||
549 | dev_put(dev); | 548 | vlan->ingress_priority_map[vlan_prio & 0x7] = skb_prio; |
550 | } | ||
551 | return -EINVAL; | ||
552 | } | 549 | } |
553 | 550 | ||
554 | int vlan_dev_set_egress_priority(char *dev_name, __u32 skb_prio, short vlan_prio) | 551 | int vlan_dev_set_egress_priority(const struct net_device *dev, |
552 | u32 skb_prio, short vlan_prio) | ||
555 | { | 553 | { |
556 | struct net_device *dev = dev_get_by_name(dev_name); | 554 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); |
557 | struct vlan_priority_tci_mapping *mp = NULL; | 555 | struct vlan_priority_tci_mapping *mp = NULL; |
558 | struct vlan_priority_tci_mapping *np; | 556 | struct vlan_priority_tci_mapping *np; |
557 | u32 vlan_qos = (vlan_prio << 13) & 0xE000; | ||
559 | 558 | ||
560 | if (dev) { | 559 | /* See if a priority mapping exists.. */ |
561 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | 560 | mp = vlan->egress_priority_map[skb_prio & 0xF]; |
562 | /* See if a priority mapping exists.. */ | 561 | while (mp) { |
563 | mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF]; | 562 | if (mp->priority == skb_prio) { |
564 | while (mp) { | 563 | if (mp->vlan_qos && !vlan_qos) |
565 | if (mp->priority == skb_prio) { | 564 | vlan->nr_egress_mappings--; |
566 | mp->vlan_qos = ((vlan_prio << 13) & 0xE000); | 565 | else if (!mp->vlan_qos && vlan_qos) |
567 | dev_put(dev); | 566 | vlan->nr_egress_mappings++; |
568 | return 0; | 567 | mp->vlan_qos = vlan_qos; |
569 | } | 568 | return 0; |
570 | mp = mp->next; | ||
571 | } | ||
572 | |||
573 | /* Create a new mapping then. */ | ||
574 | mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF]; | ||
575 | np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL); | ||
576 | if (np) { | ||
577 | np->next = mp; | ||
578 | np->priority = skb_prio; | ||
579 | np->vlan_qos = ((vlan_prio << 13) & 0xE000); | ||
580 | VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF] = np; | ||
581 | dev_put(dev); | ||
582 | return 0; | ||
583 | } else { | ||
584 | dev_put(dev); | ||
585 | return -ENOBUFS; | ||
586 | } | ||
587 | } | ||
588 | dev_put(dev); | ||
589 | } | ||
590 | return -EINVAL; | ||
591 | } | ||
592 | |||
593 | /* Flags are defined in the vlan_dev_info class in include/linux/if_vlan.h file. */ | ||
594 | int vlan_dev_set_vlan_flag(char *dev_name, __u32 flag, short flag_val) | ||
595 | { | ||
596 | struct net_device *dev = dev_get_by_name(dev_name); | ||
597 | |||
598 | if (dev) { | ||
599 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | ||
600 | /* verify flag is supported */ | ||
601 | if (flag == 1) { | ||
602 | if (flag_val) { | ||
603 | VLAN_DEV_INFO(dev)->flags |= 1; | ||
604 | } else { | ||
605 | VLAN_DEV_INFO(dev)->flags &= ~1; | ||
606 | } | ||
607 | dev_put(dev); | ||
608 | return 0; | ||
609 | } else { | ||
610 | printk(KERN_ERR "%s: flag %i is not valid.\n", | ||
611 | __FUNCTION__, (int)(flag)); | ||
612 | dev_put(dev); | ||
613 | return -EINVAL; | ||
614 | } | ||
615 | } else { | ||
616 | printk(KERN_ERR | ||
617 | "%s: %s is not a vlan device, priv_flags: %hX.\n", | ||
618 | __FUNCTION__, dev->name, dev->priv_flags); | ||
619 | dev_put(dev); | ||
620 | } | 569 | } |
621 | } else { | 570 | mp = mp->next; |
622 | printk(KERN_ERR "%s: Could not find device: %s\n", | ||
623 | __FUNCTION__, dev_name); | ||
624 | } | 571 | } |
625 | 572 | ||
626 | return -EINVAL; | 573 | /* Create a new mapping then. */ |
574 | mp = vlan->egress_priority_map[skb_prio & 0xF]; | ||
575 | np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL); | ||
576 | if (!np) | ||
577 | return -ENOBUFS; | ||
578 | |||
579 | np->next = mp; | ||
580 | np->priority = skb_prio; | ||
581 | np->vlan_qos = vlan_qos; | ||
582 | vlan->egress_priority_map[skb_prio & 0xF] = np; | ||
583 | if (vlan_qos) | ||
584 | vlan->nr_egress_mappings++; | ||
585 | return 0; | ||
627 | } | 586 | } |
628 | 587 | ||
629 | 588 | /* Flags are defined in the vlan_flags enum in include/linux/if_vlan.h file. */ | |
630 | int vlan_dev_get_realdev_name(const char *dev_name, char* result) | 589 | int vlan_dev_set_vlan_flag(const struct net_device *dev, |
590 | u32 flag, short flag_val) | ||
631 | { | 591 | { |
632 | struct net_device *dev = dev_get_by_name(dev_name); | 592 | /* verify flag is supported */ |
633 | int rv = 0; | 593 | if (flag == VLAN_FLAG_REORDER_HDR) { |
634 | if (dev) { | 594 | if (flag_val) { |
635 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | 595 | VLAN_DEV_INFO(dev)->flags |= VLAN_FLAG_REORDER_HDR; |
636 | strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23); | ||
637 | rv = 0; | ||
638 | } else { | 596 | } else { |
639 | rv = -EINVAL; | 597 | VLAN_DEV_INFO(dev)->flags &= ~VLAN_FLAG_REORDER_HDR; |
640 | } | 598 | } |
641 | dev_put(dev); | 599 | return 0; |
642 | } else { | ||
643 | rv = -ENODEV; | ||
644 | } | 600 | } |
645 | return rv; | 601 | printk(KERN_ERR "%s: flag %i is not valid.\n", __FUNCTION__, flag); |
602 | return -EINVAL; | ||
646 | } | 603 | } |
647 | 604 | ||
648 | int vlan_dev_get_vid(const char *dev_name, unsigned short* result) | 605 | void vlan_dev_get_realdev_name(const struct net_device *dev, char *result) |
649 | { | 606 | { |
650 | struct net_device *dev = dev_get_by_name(dev_name); | 607 | strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23); |
651 | int rv = 0; | ||
652 | if (dev) { | ||
653 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | ||
654 | *result = VLAN_DEV_INFO(dev)->vlan_id; | ||
655 | rv = 0; | ||
656 | } else { | ||
657 | rv = -EINVAL; | ||
658 | } | ||
659 | dev_put(dev); | ||
660 | } else { | ||
661 | rv = -ENODEV; | ||
662 | } | ||
663 | return rv; | ||
664 | } | 608 | } |
665 | 609 | ||
666 | 610 | void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result) | |
667 | int vlan_dev_set_mac_address(struct net_device *dev, void *addr_struct_p) | ||
668 | { | 611 | { |
669 | struct sockaddr *addr = (struct sockaddr *)(addr_struct_p); | 612 | *result = VLAN_DEV_INFO(dev)->vlan_id; |
670 | int i; | ||
671 | |||
672 | if (netif_running(dev)) | ||
673 | return -EBUSY; | ||
674 | |||
675 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
676 | |||
677 | printk("%s: Setting MAC address to ", dev->name); | ||
678 | for (i = 0; i < 6; i++) | ||
679 | printk(" %2.2x", dev->dev_addr[i]); | ||
680 | printk(".\n"); | ||
681 | |||
682 | if (memcmp(VLAN_DEV_INFO(dev)->real_dev->dev_addr, | ||
683 | dev->dev_addr, | ||
684 | dev->addr_len) != 0) { | ||
685 | if (!(VLAN_DEV_INFO(dev)->real_dev->flags & IFF_PROMISC)) { | ||
686 | int flgs = VLAN_DEV_INFO(dev)->real_dev->flags; | ||
687 | |||
688 | /* Increment our in-use promiscuity counter */ | ||
689 | dev_set_promiscuity(VLAN_DEV_INFO(dev)->real_dev, 1); | ||
690 | |||
691 | /* Make PROMISC visible to the user. */ | ||
692 | flgs |= IFF_PROMISC; | ||
693 | printk("VLAN (%s): Setting underlying device (%s) to promiscious mode.\n", | ||
694 | dev->name, VLAN_DEV_INFO(dev)->real_dev->name); | ||
695 | dev_change_flags(VLAN_DEV_INFO(dev)->real_dev, flgs); | ||
696 | } | ||
697 | } else { | ||
698 | printk("VLAN (%s): Underlying device (%s) has same MAC, not checking promiscious mode.\n", | ||
699 | dev->name, VLAN_DEV_INFO(dev)->real_dev->name); | ||
700 | } | ||
701 | |||
702 | return 0; | ||
703 | } | 613 | } |
704 | 614 | ||
705 | static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, | 615 | static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, |
@@ -788,15 +698,32 @@ static void vlan_flush_mc_list(struct net_device *dev) | |||
788 | 698 | ||
789 | int vlan_dev_open(struct net_device *dev) | 699 | int vlan_dev_open(struct net_device *dev) |
790 | { | 700 | { |
791 | if (!(VLAN_DEV_INFO(dev)->real_dev->flags & IFF_UP)) | 701 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); |
702 | struct net_device *real_dev = vlan->real_dev; | ||
703 | int err; | ||
704 | |||
705 | if (!(real_dev->flags & IFF_UP)) | ||
792 | return -ENETDOWN; | 706 | return -ENETDOWN; |
793 | 707 | ||
708 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { | ||
709 | err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN); | ||
710 | if (err < 0) | ||
711 | return err; | ||
712 | } | ||
713 | memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); | ||
714 | |||
794 | return 0; | 715 | return 0; |
795 | } | 716 | } |
796 | 717 | ||
797 | int vlan_dev_stop(struct net_device *dev) | 718 | int vlan_dev_stop(struct net_device *dev) |
798 | { | 719 | { |
720 | struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; | ||
721 | |||
799 | vlan_flush_mc_list(dev); | 722 | vlan_flush_mc_list(dev); |
723 | |||
724 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) | ||
725 | dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); | ||
726 | |||
800 | return 0; | 727 | return 0; |
801 | } | 728 | } |
802 | 729 | ||