The batman-adv configuration interface was implemented solely using sysfs. This approach was condemned by non-batadv developers as "huge mistake". Instead a netlink/genl based implementation was suggested. Beside the mesh/soft-interface specific configuration, the VLANs on top of the mesh/soft-interface have configuration settings. The genl interface reflects this by allowing to get/set it using the vlan specific commands BATADV_CMD_GET_VLAN/BATADV_CMD_SET_VLAN. The set command BATADV_CMD_SET_MESH will also notify interested userspace listeners of the "config" mcast group using the BATADV_CMD_SET_VLAN command message type that settings might have been changed and what the current values are.
Unified · Split
| @@ -345,6 +345,11 @@ enum batadv_nl_attrs { · 344 unmodified lines | |||
| 345 | */ | 345 | */ |
| 346 | BATADV_ATTR_MCAST_FLAGS_PRIV, | 346 | BATADV_ATTR_MCAST_FLAGS_PRIV, |
| 347 | 347 | ||
| 348 | /** | ||
| 349 | * @BATADV_ATTR_VLANID: VLAN id on top of soft interface | ||
| 350 | */ | ||
| 351 | BATADV_ATTR_VLANID, | ||
| 352 | |||
| 348 | /* add attributes above here, update the policy in netlink.c */ | 353 | /* add attributes above here, update the policy in netlink.c */ |
| 349 | 354 | ||
| 350 | /** | 355 | /** |
| @@ -465,6 +470,18 @@ enum batadv_nl_commands { · 114 unmodified lines | |||
| 465 | */ | 470 | */ |
| 466 | BATADV_CMD_SET_HARDIF, | 471 | BATADV_CMD_SET_HARDIF, |
| 467 | 472 | ||
| 473 | /** | ||
| 474 | * @BATADV_CMD_GET_VLAN: Get attributes from a VLAN of the | ||
| 475 | * current softif | ||
| 476 | */ | ||
| 477 | BATADV_CMD_GET_VLAN, | ||
| 478 | |||
| 479 | /** | ||
| 480 | * @BATADV_CMD_SET_VLAN: Set attributes for VLAN of the | ||
| 481 | * current softif | ||
| 482 | */ | ||
| 483 | BATADV_CMD_SET_VLAN, | ||
| 484 | |||
| 468 | /* add new commands above here */ | 485 | /* add new commands above here */ |
| 469 | 486 | ||
| 470 | /** | 487 | /** |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include <linux/genetlink.h> | 30 | #include <linux/genetlink.h> |
| 31 | #include <linux/gfp.h> | 31 | #include <linux/gfp.h> |
| 32 | #include <linux/if_ether.h> | 32 | #include <linux/if_ether.h> |
| 33 | #include <linux/if_vlan.h> | ||
| 33 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 34 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
| 35 | #include <linux/list.h> | 36 | #include <linux/list.h> |
| @@ -84,6 +85,13 @@ enum batadv_genl_ops_flags { · 48 unmodified lines | |||
| 84 | * saved in info->user_ptr[1] | 85 | * saved in info->user_ptr[1] |
| 85 | */ | 86 | */ |
| 86 | BATADV_FLAG_NEED_HARDIF = BIT(1), | 87 | BATADV_FLAG_NEED_HARDIF = BIT(1), |
| 88 | |||
| 89 | /** | ||
| 90 | * @BATADV_FLAG_NEED_VLAN: request requires valid vlan in | ||
| 91 | * attribute BATADV_ATTR_VLANID and expects a pointer to it to be | ||
| 92 | * saved in info->user_ptr[1] | ||
| 93 | */ | ||
| 94 | BATADV_FLAG_NEED_VLAN = BIT(2), | ||
| 87 | }; | 95 | }; |
| 88 | 96 | ||
| 89 | static const struct genl_multicast_group batadv_netlink_mcgrps[] = { | 97 | static const struct genl_multicast_group batadv_netlink_mcgrps[] = { |
| @@ -130,6 +138,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { · 40 unmodified lines | |||
| 130 | [BATADV_ATTR_DAT_CACHE_VID] = { .type = NLA_U16 }, | 138 | [BATADV_ATTR_DAT_CACHE_VID] = { .type = NLA_U16 }, |
| 131 | [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, | 139 | [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, |
| 132 | [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, | 140 | [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, |
| 141 | [BATADV_ATTR_VLANID] = { .type = NLA_U16 }, | ||
| 133 | }; | 142 | }; |
| 134 | 143 | ||
| 135 | /** | 144 | /** |
| @@ -653,6 +662,123 @@ batadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb) · 517 unmodified lines | |||
| 653 | return msg->len; | 662 | return msg->len; |
| 654 | } | 663 | } |
| 655 | 664 | ||
| 665 | /** | ||
| 666 | * batadv_netlink_vlan_fill() - Fill message with vlan attributes | ||
| 667 | * @msg: Netlink message to dump into | ||
| 668 | * @bat_priv: the bat priv with all the soft interface information | ||
| 669 | * @vlan: vlan which was modified | ||
| 670 | * @cmd: type of message to generate | ||
| 671 | * @portid: Port making netlink request | ||
| 672 | * @seq: sequence number for message | ||
| 673 | * @flags: Additional flags for message | ||
| 674 | * | ||
| 675 | * Return: 0 on success or negative error number in case of failure | ||
| 676 | */ | ||
| 677 | static int batadv_netlink_vlan_fill(struct sk_buff *msg, | ||
| 678 | struct batadv_priv *bat_priv, | ||
| 679 | struct batadv_softif_vlan *vlan, | ||
| 680 | enum batadv_nl_commands cmd, | ||
| 681 | u32 portid, u32 seq, int flags) | ||
| 682 | { | ||
| 683 | void *hdr; | ||
| 684 | |||
| 685 | hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd); | ||
| 686 | if (!hdr) | ||
| 687 | return -ENOBUFS; | ||
| 688 | |||
| 689 | if (nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, | ||
| 690 | bat_priv->soft_iface->ifindex)) | ||
| 691 | goto nla_put_failure; | ||
| 692 | |||
| 693 | if (nla_put_u32(msg, BATADV_ATTR_VLANID, vlan->vid & VLAN_VID_MASK)) | ||
| 694 | goto nla_put_failure; | ||
| 695 | |||
| 696 | genlmsg_end(msg, hdr); | ||
| 697 | return 0; | ||
| 698 | |||
| 699 | nla_put_failure: | ||
| 700 | genlmsg_cancel(msg, hdr); | ||
| 701 | return -EMSGSIZE; | ||
| 702 | } | ||
| 703 | |||
| 704 | /** | ||
| 705 | * batadv_netlink_notify_vlan() - send vlan attributes to listener | ||
| 706 | * @bat_priv: the bat priv with all the soft interface information | ||
| 707 | * @vlan: vlan which was modified | ||
| 708 | * | ||
| 709 | * Return: 0 on success, < 0 on error | ||
| 710 | */ | ||
| 711 | static int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv, | ||
| 712 | struct batadv_softif_vlan *vlan) | ||
| 713 | { | ||
| 714 | struct sk_buff *msg; | ||
| 715 | int ret; | ||
| 716 | |||
| 717 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 718 | if (!msg) | ||
| 719 | return -ENOMEM; | ||
| 720 | |||
| 721 | ret = batadv_netlink_vlan_fill(msg, bat_priv, vlan, | ||
| 722 | BATADV_CMD_SET_VLAN, 0, 0, 0); | ||
| 723 | if (ret < 0) { | ||
| 724 | nlmsg_free(msg); | ||
| 725 | return ret; | ||
| 726 | } | ||
| 727 | |||
| 728 | genlmsg_multicast_netns(&batadv_netlink_family, | ||
| 729 | dev_net(bat_priv->soft_iface), msg, 0, | ||
| 730 | BATADV_NL_MCGRP_CONFIG, GFP_KERNEL); | ||
| 731 | |||
| 732 | return 0; | ||
| 733 | } | ||
| 734 | |||
| 735 | /** | ||
| 736 | * batadv_netlink_get_vlan() - Get vlan attributes | ||
| 737 | * @skb: Netlink message with request data | ||
| 738 | * @info: receiver information | ||
| 739 | * | ||
| 740 | * Return: 0 on success or negative error number in case of failure | ||
| 741 | */ | ||
| 742 | static int batadv_netlink_get_vlan(struct sk_buff *skb, struct genl_info *info) | ||
| 743 | { | ||
| 744 | struct batadv_softif_vlan *vlan = info->user_ptr[1]; | ||
| 745 | struct batadv_priv *bat_priv = info->user_ptr[0]; | ||
| 746 | struct sk_buff *msg; | ||
| 747 | int ret; | ||
| 748 | |||
| 749 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 750 | if (!msg) | ||
| 751 | return -ENOMEM; | ||
| 752 | |||
| 753 | ret = batadv_netlink_vlan_fill(msg, bat_priv, vlan, BATADV_CMD_GET_VLAN, | ||
| 754 | info->snd_portid, info->snd_seq, 0); | ||
| 755 | if (ret < 0) { | ||
| 756 | nlmsg_free(msg); | ||
| 757 | return ret; | ||
| 758 | } | ||
| 759 | |||
| 760 | ret = genlmsg_reply(msg, info); | ||
| 761 | |||
| 762 | return ret; | ||
| 763 | } | ||
| 764 | |||
| 765 | /** | ||
| 766 | * batadv_netlink_set_vlan() - Get vlan attributes | ||
| 767 | * @skb: Netlink message with request data | ||
| 768 | * @info: receiver information | ||
| 769 | * | ||
| 770 | * Return: 0 on success or negative error number in case of failure | ||
| 771 | */ | ||
| 772 | static int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info) | ||
| 773 | { | ||
| 774 | struct batadv_softif_vlan *vlan = info->user_ptr[1]; | ||
| 775 | struct batadv_priv *bat_priv = info->user_ptr[0]; | ||
| 776 | |||
| 777 | batadv_netlink_notify_vlan(bat_priv, vlan); | ||
| 778 | |||
| 779 | return 0; | ||
| 780 | } | ||
| 781 | |||
| 656 | /** | 782 | /** |
| 657 | * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes | 783 | * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes |
| 658 | * @net: the applicable net namespace | 784 | * @net: the applicable net namespace |
| @@ -733,6 +859,34 @@ err_put_harddev: · 74 unmodified lines | |||
| 733 | return ERR_PTR(-EINVAL); | 859 | return ERR_PTR(-EINVAL); |
| 734 | } | 860 | } |
| 735 | 861 | ||
| 862 | /** | ||
| 863 | * batadv_get_vlan_from_info() - Retrieve vlan from genl attributes | ||
| 864 | * @bat_priv: the bat priv with all the soft interface information | ||
| 865 | * @net: the applicable net namespace | ||
| 866 | * @info: receiver information | ||
| 867 | * | ||
| 868 | * Return: Pointer to vlan on success (with increased refcnt), error pointer | ||
| 869 | * on error | ||
| 870 | */ | ||
| 871 | static struct batadv_softif_vlan * | ||
| 872 | batadv_get_vlan_from_info(struct batadv_priv *bat_priv, struct net *net, | ||
| 873 | struct genl_info *info) | ||
| 874 | { | ||
| 875 | struct batadv_softif_vlan *vlan; | ||
| 876 | u16 vid; | ||
| 877 | |||
| 878 | if (!info->attrs[BATADV_ATTR_VLANID]) | ||
| 879 | return ERR_PTR(-EINVAL); | ||
| 880 | |||
| 881 | vid = nla_get_u16(info->attrs[BATADV_ATTR_VLANID]); | ||
| 882 | |||
| 883 | vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG); | ||
| 884 | if (!vlan) | ||
| 885 | return ERR_PTR(-ENOENT); | ||
| 886 | |||
| 887 | return vlan; | ||
| 888 | } | ||
| 889 | |||
| 736 | /** | 890 | /** |
| 737 | * batadv_pre_doit() - Prepare batman-adv genl doit request | 891 | * batadv_pre_doit() - Prepare batman-adv genl doit request |
| 738 | * @ops: requested netlink operation | 892 | * @ops: requested netlink operation |
| @@ -747,16 +901,17 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, · 8 unmodified lines | |||
| 747 | struct net *net = genl_info_net(info); | 901 | struct net *net = genl_info_net(info); |
| 748 | struct batadv_hard_iface *hard_iface; | 902 | struct batadv_hard_iface *hard_iface; |
| 749 | struct batadv_priv *bat_priv = NULL; | 903 | struct batadv_priv *bat_priv = NULL; |
| 904 | struct batadv_softif_vlan *vlan; | ||
| 750 | struct net_device *soft_iface; | 905 | struct net_device *soft_iface; |
| 751 | u8 user_ptr1_flags; | 906 | u8 user_ptr1_flags; |
| 752 | u8 mesh_dep_flags; | 907 | u8 mesh_dep_flags; |
| 753 | int ret; | 908 | int ret; |
| 754 | 909 | ||
| 755 | user_ptr1_flags = BATADV_FLAG_NEED_HARDIF; | 910 | user_ptr1_flags = BATADV_FLAG_NEED_HARDIF | BATADV_FLAG_NEED_VLAN; |
| 756 | if (WARN_ON(hweight8(ops->internal_flags & user_ptr1_flags) > 1)) | 911 | if (WARN_ON(hweight8(ops->internal_flags & user_ptr1_flags) > 1)) |
| 757 | return -EINVAL; | 912 | return -EINVAL; |
| 758 | 913 | ||
| 759 | mesh_dep_flags = BATADV_FLAG_NEED_HARDIF; | 914 | mesh_dep_flags = BATADV_FLAG_NEED_HARDIF | BATADV_FLAG_NEED_VLAN; |
| 760 | if (WARN_ON((ops->internal_flags & mesh_dep_flags) && | 915 | if (WARN_ON((ops->internal_flags & mesh_dep_flags) && |
| 761 | (~ops->internal_flags & BATADV_FLAG_NEED_MESH))) | 916 | (~ops->internal_flags & BATADV_FLAG_NEED_MESH))) |
| 762 | return -EINVAL; | 917 | return -EINVAL; |
| @@ -780,6 +935,16 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, · 17 unmodified lines | |||
| 780 | info->user_ptr[1] = hard_iface; | 935 | info->user_ptr[1] = hard_iface; |
| 781 | } | 936 | } |
| 782 | 937 | ||
| 938 | if (ops->internal_flags & BATADV_FLAG_NEED_VLAN) { | ||
| 939 | vlan = batadv_get_vlan_from_info(bat_priv, net, info); | ||
| 940 | if (IS_ERR(vlan)) { | ||
| 941 | ret = PTR_ERR(vlan); | ||
| 942 | goto err_put_softif; | ||
| 943 | } | ||
| 944 | |||
| 945 | info->user_ptr[1] = vlan; | ||
| 946 | } | ||
| 947 | |||
| 783 | return 0; | 948 | return 0; |
| 784 | 949 | ||
| 785 | err_put_softif: | 950 | err_put_softif: |
| @@ -799,6 +964,7 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb, · 13 unmodified lines | |||
| 799 | struct genl_info *info) | 964 | struct genl_info *info) |
| 800 | { | 965 | { |
| 801 | struct batadv_hard_iface *hard_iface; | 966 | struct batadv_hard_iface *hard_iface; |
| 967 | struct batadv_softif_vlan *vlan; | ||
| 802 | struct batadv_priv *bat_priv; | 968 | struct batadv_priv *bat_priv; |
| 803 | 969 | ||
| 804 | if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF && | 970 | if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF && |
| @@ -808,6 +974,11 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb, · 3 unmodified lines | |||
| 808 | batadv_hardif_put(hard_iface); | 974 | batadv_hardif_put(hard_iface); |
| 809 | } | 975 | } |
| 810 | 976 | ||
| 977 | if (ops->internal_flags & BATADV_FLAG_NEED_VLAN && info->user_ptr[1]) { | ||
| 978 | vlan = info->user_ptr[1]; | ||
| 979 | batadv_softif_vlan_put(vlan); | ||
| 980 | } | ||
| 981 | |||
| 811 | if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) { | 982 | if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) { |
| 812 | bat_priv = info->user_ptr[0]; | 983 | bat_priv = info->user_ptr[0]; |
| 813 | dev_put(bat_priv->soft_iface); | 984 | dev_put(bat_priv->soft_iface); |
| @@ -920,6 +1091,22 @@ static const struct genl_ops batadv_netlink_ops[] = { · 106 unmodified lines | |||
| 920 | .internal_flags = BATADV_FLAG_NEED_MESH | | 1091 | .internal_flags = BATADV_FLAG_NEED_MESH | |
| 921 | BATADV_FLAG_NEED_HARDIF, | 1092 | BATADV_FLAG_NEED_HARDIF, |
| 922 | }, | 1093 | }, |
| 1094 | { | ||
| 1095 | .cmd = BATADV_CMD_GET_VLAN, | ||
| 1096 | /* can be retrieved by unprivileged users */ | ||
| 1097 | .policy = batadv_netlink_policy, | ||
| 1098 | .doit = batadv_netlink_get_vlan, | ||
| 1099 | .internal_flags = BATADV_FLAG_NEED_MESH | | ||
| 1100 | BATADV_FLAG_NEED_VLAN, | ||
| 1101 | }, | ||
| 1102 | { | ||
| 1103 | .cmd = BATADV_CMD_SET_VLAN, | ||
| 1104 | .flags = GENL_ADMIN_PERM, | ||
| 1105 | .policy = batadv_netlink_policy, | ||
| 1106 | .doit = batadv_netlink_set_vlan, | ||
| 1107 | .internal_flags = BATADV_FLAG_NEED_MESH | | ||
| 1108 | BATADV_FLAG_NEED_VLAN, | ||
| 1109 | }, | ||
| 923 | }; | 1110 | }; |
| 924 | 1111 | ||
| 925 | struct genl_family batadv_netlink_family __ro_after_init = { | 1112 | struct genl_family batadv_netlink_family __ro_after_init = { |