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 | 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 | 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 | 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 | 485 | /* add new commands above here */ |
| 469 | 486 | |
| 470 | 487 | /** |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #include <linux/genetlink.h> |
| 31 | 31 | #include <linux/gfp.h> |
| 32 | 32 | #include <linux/if_ether.h> |
| 33 | +#include <linux/if_vlan.h> | |
| 33 | 34 | #include <linux/init.h> |
| 34 | 35 | #include <linux/kernel.h> |
| 35 | 36 | #include <linux/list.h> |
| @@ -84,6 +85,13 @@ enum batadv_genl_ops_flags { · 48 unmodified lines | ||
| 84 | 85 | * saved in info->user_ptr[1] |
| 85 | 86 | */ |
| 86 | 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 | 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 | 138 | [BATADV_ATTR_DAT_CACHE_VID] = { .type = NLA_U16 }, |
| 131 | 139 | [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, |
| 132 | 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 | 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 | 783 | * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes |
| 658 | 784 | * @net: the applicable net namespace |
| @@ -733,6 +859,34 @@ err_put_harddev: · 74 unmodified lines | ||
| 733 | 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 | 891 | * batadv_pre_doit() - Prepare batman-adv genl doit request |
| 738 | 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 | 901 | struct net *net = genl_info_net(info); |
| 748 | 902 | struct batadv_hard_iface *hard_iface; |
| 749 | 903 | struct batadv_priv *bat_priv = NULL; |
| 904 | + struct batadv_softif_vlan *vlan; | |
| 750 | 905 | struct net_device *soft_iface; |
| 751 | 906 | u8 user_ptr1_flags; |
| 752 | 907 | u8 mesh_dep_flags; |
| 753 | 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 | 911 | if (WARN_ON(hweight8(ops->internal_flags & user_ptr1_flags) > 1)) |
| 757 | 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 | 915 | if (WARN_ON((ops->internal_flags & mesh_dep_flags) && |
| 761 | 916 | (~ops->internal_flags & BATADV_FLAG_NEED_MESH))) |
| 762 | 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 | 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 | 948 | return 0; |
| 784 | 949 | |
| 785 | 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 | 964 | struct genl_info *info) |
| 800 | 965 | { |
| 801 | 966 | struct batadv_hard_iface *hard_iface; |
| 967 | + struct batadv_softif_vlan *vlan; | |
| 802 | 968 | struct batadv_priv *bat_priv; |
| 803 | 969 | |
| 804 | 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 | 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 | 982 | if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) { |
| 812 | 983 | bat_priv = info->user_ptr[0]; |
| 813 | 984 | dev_put(bat_priv->soft_iface); |
| @@ -920,6 +1091,22 @@ static const struct genl_ops batadv_netlink_ops[] = { · 106 unmodified lines | ||
| 920 | 1091 | .internal_flags = BATADV_FLAG_NEED_MESH | |
| 921 | 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 | 1112 | struct genl_family batadv_netlink_family __ro_after_init = { |