diff options
Diffstat (limited to 'net/decnet/dn_dev.c')
-rw-r--r-- | net/decnet/dn_dev.c | 173 |
1 files changed, 102 insertions, 71 deletions
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 01861feb608d..0b9d4c955154 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/if_arp.h> | 38 | #include <linux/if_arp.h> |
39 | #include <linux/if_ether.h> | 39 | #include <linux/if_ether.h> |
40 | #include <linux/skbuff.h> | 40 | #include <linux/skbuff.h> |
41 | #include <linux/rtnetlink.h> | ||
42 | #include <linux/sysctl.h> | 41 | #include <linux/sysctl.h> |
43 | #include <linux/notifier.h> | 42 | #include <linux/notifier.h> |
44 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
@@ -47,6 +46,7 @@ | |||
47 | #include <net/dst.h> | 46 | #include <net/dst.h> |
48 | #include <net/flow.h> | 47 | #include <net/flow.h> |
49 | #include <net/fib_rules.h> | 48 | #include <net/fib_rules.h> |
49 | #include <net/netlink.h> | ||
50 | #include <net/dn.h> | 50 | #include <net/dn.h> |
51 | #include <net/dn_dev.h> | 51 | #include <net/dn_dev.h> |
52 | #include <net/dn_route.h> | 52 | #include <net/dn_route.h> |
@@ -73,7 +73,7 @@ static BLOCKING_NOTIFIER_HEAD(dnaddr_chain); | |||
73 | 73 | ||
74 | static struct dn_dev *dn_dev_create(struct net_device *dev, int *err); | 74 | static struct dn_dev *dn_dev_create(struct net_device *dev, int *err); |
75 | static void dn_dev_delete(struct net_device *dev); | 75 | static void dn_dev_delete(struct net_device *dev); |
76 | static void rtmsg_ifa(int event, struct dn_ifaddr *ifa); | 76 | static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa); |
77 | 77 | ||
78 | static int dn_eth_up(struct net_device *); | 78 | static int dn_eth_up(struct net_device *); |
79 | static void dn_eth_down(struct net_device *); | 79 | static void dn_eth_down(struct net_device *); |
@@ -255,12 +255,10 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms * | |||
255 | struct dn_dev_sysctl_table *t; | 255 | struct dn_dev_sysctl_table *t; |
256 | int i; | 256 | int i; |
257 | 257 | ||
258 | t = kmalloc(sizeof(*t), GFP_KERNEL); | 258 | t = kmemdup(&dn_dev_sysctl, sizeof(*t), GFP_KERNEL); |
259 | if (t == NULL) | 259 | if (t == NULL) |
260 | return; | 260 | return; |
261 | 261 | ||
262 | memcpy(t, &dn_dev_sysctl, sizeof(*t)); | ||
263 | |||
264 | for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) { | 262 | for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) { |
265 | long offset = (long)t->dn_dev_vars[i].data; | 263 | long offset = (long)t->dn_dev_vars[i].data; |
266 | t->dn_dev_vars[i].data = ((char *)parms) + offset; | 264 | t->dn_dev_vars[i].data = ((char *)parms) + offset; |
@@ -442,7 +440,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de | |||
442 | } | 440 | } |
443 | } | 441 | } |
444 | 442 | ||
445 | rtmsg_ifa(RTM_DELADDR, ifa1); | 443 | dn_ifaddr_notify(RTM_DELADDR, ifa1); |
446 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); | 444 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); |
447 | if (destroy) { | 445 | if (destroy) { |
448 | dn_dev_free_ifa(ifa1); | 446 | dn_dev_free_ifa(ifa1); |
@@ -477,7 +475,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
477 | ifa->ifa_next = dn_db->ifa_list; | 475 | ifa->ifa_next = dn_db->ifa_list; |
478 | dn_db->ifa_list = ifa; | 476 | dn_db->ifa_list = ifa; |
479 | 477 | ||
480 | rtmsg_ifa(RTM_NEWADDR, ifa); | 478 | dn_ifaddr_notify(RTM_NEWADDR, ifa); |
481 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); | 479 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); |
482 | 480 | ||
483 | return 0; | 481 | return 0; |
@@ -647,41 +645,62 @@ static struct dn_dev *dn_dev_by_index(int ifindex) | |||
647 | return dn_dev; | 645 | return dn_dev; |
648 | } | 646 | } |
649 | 647 | ||
650 | static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 648 | static struct nla_policy dn_ifa_policy[IFA_MAX+1] __read_mostly = { |
649 | [IFA_ADDRESS] = { .type = NLA_U16 }, | ||
650 | [IFA_LOCAL] = { .type = NLA_U16 }, | ||
651 | [IFA_LABEL] = { .type = NLA_STRING, | ||
652 | .len = IFNAMSIZ - 1 }, | ||
653 | }; | ||
654 | |||
655 | static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | ||
651 | { | 656 | { |
652 | struct rtattr **rta = arg; | 657 | struct nlattr *tb[IFA_MAX+1]; |
653 | struct dn_dev *dn_db; | 658 | struct dn_dev *dn_db; |
654 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 659 | struct ifaddrmsg *ifm; |
655 | struct dn_ifaddr *ifa, **ifap; | 660 | struct dn_ifaddr *ifa, **ifap; |
661 | int err = -EADDRNOTAVAIL; | ||
662 | |||
663 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); | ||
664 | if (err < 0) | ||
665 | goto errout; | ||
656 | 666 | ||
667 | ifm = nlmsg_data(nlh); | ||
657 | if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL) | 668 | if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL) |
658 | return -EADDRNOTAVAIL; | 669 | goto errout; |
670 | |||
671 | for (ifap = &dn_db->ifa_list; (ifa = *ifap); ifap = &ifa->ifa_next) { | ||
672 | if (tb[IFA_LOCAL] && | ||
673 | nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2)) | ||
674 | continue; | ||
659 | 675 | ||
660 | for(ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) { | 676 | if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label)) |
661 | void *tmp = rta[IFA_LOCAL-1]; | ||
662 | if ((tmp && memcmp(RTA_DATA(tmp), &ifa->ifa_local, 2)) || | ||
663 | (rta[IFA_LABEL-1] && rtattr_strcmp(rta[IFA_LABEL-1], ifa->ifa_label))) | ||
664 | continue; | 677 | continue; |
665 | 678 | ||
666 | dn_dev_del_ifa(dn_db, ifap, 1); | 679 | dn_dev_del_ifa(dn_db, ifap, 1); |
667 | return 0; | 680 | return 0; |
668 | } | 681 | } |
669 | 682 | ||
670 | return -EADDRNOTAVAIL; | 683 | errout: |
684 | return err; | ||
671 | } | 685 | } |
672 | 686 | ||
673 | static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 687 | static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
674 | { | 688 | { |
675 | struct rtattr **rta = arg; | 689 | struct nlattr *tb[IFA_MAX+1]; |
676 | struct net_device *dev; | 690 | struct net_device *dev; |
677 | struct dn_dev *dn_db; | 691 | struct dn_dev *dn_db; |
678 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 692 | struct ifaddrmsg *ifm; |
679 | struct dn_ifaddr *ifa; | 693 | struct dn_ifaddr *ifa; |
680 | int rv; | 694 | int err; |
681 | 695 | ||
682 | if (rta[IFA_LOCAL-1] == NULL) | 696 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); |
697 | if (err < 0) | ||
698 | return err; | ||
699 | |||
700 | if (tb[IFA_LOCAL] == NULL) | ||
683 | return -EINVAL; | 701 | return -EINVAL; |
684 | 702 | ||
703 | ifm = nlmsg_data(nlh); | ||
685 | if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) | 704 | if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) |
686 | return -ENODEV; | 705 | return -ENODEV; |
687 | 706 | ||
@@ -695,69 +714,77 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a | |||
695 | if ((ifa = dn_dev_alloc_ifa()) == NULL) | 714 | if ((ifa = dn_dev_alloc_ifa()) == NULL) |
696 | return -ENOBUFS; | 715 | return -ENOBUFS; |
697 | 716 | ||
698 | if (!rta[IFA_ADDRESS - 1]) | 717 | if (tb[IFA_ADDRESS] == NULL) |
699 | rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1]; | 718 | tb[IFA_ADDRESS] = tb[IFA_LOCAL]; |
700 | memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 2); | 719 | |
701 | memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-1]), 2); | 720 | ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]); |
721 | ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]); | ||
702 | ifa->ifa_flags = ifm->ifa_flags; | 722 | ifa->ifa_flags = ifm->ifa_flags; |
703 | ifa->ifa_scope = ifm->ifa_scope; | 723 | ifa->ifa_scope = ifm->ifa_scope; |
704 | ifa->ifa_dev = dn_db; | 724 | ifa->ifa_dev = dn_db; |
705 | if (rta[IFA_LABEL-1]) | 725 | |
706 | rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL-1], IFNAMSIZ); | 726 | if (tb[IFA_LABEL]) |
727 | nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ); | ||
707 | else | 728 | else |
708 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); | 729 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); |
709 | 730 | ||
710 | rv = dn_dev_insert_ifa(dn_db, ifa); | 731 | err = dn_dev_insert_ifa(dn_db, ifa); |
711 | if (rv) | 732 | if (err) |
712 | dn_dev_free_ifa(ifa); | 733 | dn_dev_free_ifa(ifa); |
713 | return rv; | 734 | |
735 | return err; | ||
714 | } | 736 | } |
715 | 737 | ||
716 | static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, | 738 | static inline size_t dn_ifaddr_nlmsg_size(void) |
717 | u32 pid, u32 seq, int event, unsigned int flags) | 739 | { |
740 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) | ||
741 | + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ | ||
742 | + nla_total_size(2) /* IFA_ADDRESS */ | ||
743 | + nla_total_size(2); /* IFA_LOCAL */ | ||
744 | } | ||
745 | |||
746 | static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, | ||
747 | u32 pid, u32 seq, int event, unsigned int flags) | ||
718 | { | 748 | { |
719 | struct ifaddrmsg *ifm; | 749 | struct ifaddrmsg *ifm; |
720 | struct nlmsghdr *nlh; | 750 | struct nlmsghdr *nlh; |
721 | unsigned char *b = skb->tail; | ||
722 | 751 | ||
723 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | 752 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags); |
724 | ifm = NLMSG_DATA(nlh); | 753 | if (nlh == NULL) |
754 | return -ENOBUFS; | ||
725 | 755 | ||
756 | ifm = nlmsg_data(nlh); | ||
726 | ifm->ifa_family = AF_DECnet; | 757 | ifm->ifa_family = AF_DECnet; |
727 | ifm->ifa_prefixlen = 16; | 758 | ifm->ifa_prefixlen = 16; |
728 | ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; | 759 | ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; |
729 | ifm->ifa_scope = ifa->ifa_scope; | 760 | ifm->ifa_scope = ifa->ifa_scope; |
730 | ifm->ifa_index = ifa->ifa_dev->dev->ifindex; | 761 | ifm->ifa_index = ifa->ifa_dev->dev->ifindex; |
762 | |||
731 | if (ifa->ifa_address) | 763 | if (ifa->ifa_address) |
732 | RTA_PUT(skb, IFA_ADDRESS, 2, &ifa->ifa_address); | 764 | NLA_PUT_LE16(skb, IFA_ADDRESS, ifa->ifa_address); |
733 | if (ifa->ifa_local) | 765 | if (ifa->ifa_local) |
734 | RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local); | 766 | NLA_PUT_LE16(skb, IFA_LOCAL, ifa->ifa_local); |
735 | if (ifa->ifa_label[0]) | 767 | if (ifa->ifa_label[0]) |
736 | RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label); | 768 | NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label); |
737 | nlh->nlmsg_len = skb->tail - b; | 769 | |
738 | return skb->len; | 770 | return nlmsg_end(skb, nlh); |
739 | 771 | ||
740 | nlmsg_failure: | 772 | nla_put_failure: |
741 | rtattr_failure: | 773 | return nlmsg_cancel(skb, nlh); |
742 | skb_trim(skb, b - skb->data); | ||
743 | return -1; | ||
744 | } | 774 | } |
745 | 775 | ||
746 | static void rtmsg_ifa(int event, struct dn_ifaddr *ifa) | 776 | static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa) |
747 | { | 777 | { |
748 | struct sk_buff *skb; | 778 | struct sk_buff *skb; |
749 | int payload = sizeof(struct ifaddrmsg) + 128; | ||
750 | int err = -ENOBUFS; | 779 | int err = -ENOBUFS; |
751 | 780 | ||
752 | skb = alloc_skb(nlmsg_total_size(payload), GFP_KERNEL); | 781 | skb = alloc_skb(dn_ifaddr_nlmsg_size(), GFP_KERNEL); |
753 | if (skb == NULL) | 782 | if (skb == NULL) |
754 | goto errout; | 783 | goto errout; |
755 | 784 | ||
756 | err = dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0); | 785 | err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0); |
757 | if (err < 0) { | 786 | /* failure implies BUG in dn_ifaddr_nlmsg_size() */ |
758 | kfree_skb(skb); | 787 | BUG_ON(err < 0); |
759 | goto errout; | ||
760 | } | ||
761 | 788 | ||
762 | err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL); | 789 | err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL); |
763 | errout: | 790 | errout: |
@@ -765,39 +792,43 @@ errout: | |||
765 | rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err); | 792 | rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err); |
766 | } | 793 | } |
767 | 794 | ||
768 | static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | 795 | static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
769 | { | 796 | { |
770 | int idx, dn_idx; | 797 | int idx, dn_idx = 0, skip_ndevs, skip_naddr; |
771 | int s_idx, s_dn_idx; | ||
772 | struct net_device *dev; | 798 | struct net_device *dev; |
773 | struct dn_dev *dn_db; | 799 | struct dn_dev *dn_db; |
774 | struct dn_ifaddr *ifa; | 800 | struct dn_ifaddr *ifa; |
775 | 801 | ||
776 | s_idx = cb->args[0]; | 802 | skip_ndevs = cb->args[0]; |
777 | s_dn_idx = dn_idx = cb->args[1]; | 803 | skip_naddr = cb->args[1]; |
804 | |||
778 | read_lock(&dev_base_lock); | 805 | read_lock(&dev_base_lock); |
779 | for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { | 806 | for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { |
780 | if (idx < s_idx) | 807 | if (idx < skip_ndevs) |
781 | continue; | 808 | continue; |
782 | if (idx > s_idx) | 809 | else if (idx > skip_ndevs) { |
783 | s_dn_idx = 0; | 810 | /* Only skip over addresses for first dev dumped |
811 | * in this iteration (idx == skip_ndevs) */ | ||
812 | skip_naddr = 0; | ||
813 | } | ||
814 | |||
784 | if ((dn_db = dev->dn_ptr) == NULL) | 815 | if ((dn_db = dev->dn_ptr) == NULL) |
785 | continue; | 816 | continue; |
786 | 817 | ||
787 | for(ifa = dn_db->ifa_list, dn_idx = 0; ifa; ifa = ifa->ifa_next, dn_idx++) { | 818 | for (ifa = dn_db->ifa_list, dn_idx = 0; ifa; |
788 | if (dn_idx < s_dn_idx) | 819 | ifa = ifa->ifa_next, dn_idx++) { |
820 | if (dn_idx < skip_naddr) | ||
789 | continue; | 821 | continue; |
790 | 822 | ||
791 | if (dn_dev_fill_ifaddr(skb, ifa, | 823 | if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, |
792 | NETLINK_CB(cb->skb).pid, | 824 | cb->nlh->nlmsg_seq, RTM_NEWADDR, |
793 | cb->nlh->nlmsg_seq, | 825 | NLM_F_MULTI) < 0) |
794 | RTM_NEWADDR, | ||
795 | NLM_F_MULTI) <= 0) | ||
796 | goto done; | 826 | goto done; |
797 | } | 827 | } |
798 | } | 828 | } |
799 | done: | 829 | done: |
800 | read_unlock(&dev_base_lock); | 830 | read_unlock(&dev_base_lock); |
831 | |||
801 | cb->args[0] = idx; | 832 | cb->args[0] = idx; |
802 | cb->args[1] = dn_idx; | 833 | cb->args[1] = dn_idx; |
803 | 834 | ||
@@ -1414,9 +1445,9 @@ static struct file_operations dn_dev_seq_fops = { | |||
1414 | 1445 | ||
1415 | static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] = | 1446 | static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] = |
1416 | { | 1447 | { |
1417 | [RTM_NEWADDR - RTM_BASE] = { .doit = dn_dev_rtm_newaddr, }, | 1448 | [RTM_NEWADDR - RTM_BASE] = { .doit = dn_nl_newaddr, }, |
1418 | [RTM_DELADDR - RTM_BASE] = { .doit = dn_dev_rtm_deladdr, }, | 1449 | [RTM_DELADDR - RTM_BASE] = { .doit = dn_nl_deladdr, }, |
1419 | [RTM_GETADDR - RTM_BASE] = { .dumpit = dn_dev_dump_ifaddr, }, | 1450 | [RTM_GETADDR - RTM_BASE] = { .dumpit = dn_nl_dump_ifaddr, }, |
1420 | #ifdef CONFIG_DECNET_ROUTER | 1451 | #ifdef CONFIG_DECNET_ROUTER |
1421 | [RTM_NEWROUTE - RTM_BASE] = { .doit = dn_fib_rtm_newroute, }, | 1452 | [RTM_NEWROUTE - RTM_BASE] = { .doit = dn_fib_rtm_newroute, }, |
1422 | [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, }, | 1453 | [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, }, |