aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/nl80211.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 306ae019ea81..431835126e88 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
76 .len = IEEE80211_MAX_DATA_LEN }, 76 .len = IEEE80211_MAX_DATA_LEN },
77 [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, 77 [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
78 .len = IEEE80211_MAX_DATA_LEN }, 78 .len = IEEE80211_MAX_DATA_LEN },
79 [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
80 [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
81 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
82 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
83 .len = NL80211_MAX_SUPP_RATES },
84 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
79}; 85};
80 86
81/* message building helper */ 87/* message building helper */
@@ -715,6 +721,210 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
715 return err; 721 return err;
716} 722}
717 723
724static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
725 [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
726 [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
727 [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
728};
729
730static int parse_station_flags(struct nlattr *nla, u32 *staflags)
731{
732 struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
733 int flag;
734
735 *staflags = 0;
736
737 if (!nla)
738 return 0;
739
740 if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
741 nla, sta_flags_policy))
742 return -EINVAL;
743
744 *staflags = STATION_FLAG_CHANGED;
745
746 for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
747 if (flags[flag])
748 *staflags |= (1<<flag);
749
750 return 0;
751}
752
753static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
754{
755 return -EOPNOTSUPP;
756}
757
758/*
759 * Get vlan interface making sure it is on the right wiphy.
760 */
761static int get_vlan(struct nlattr *vlanattr,
762 struct cfg80211_registered_device *rdev,
763 struct net_device **vlan)
764{
765 *vlan = NULL;
766
767 if (vlanattr) {
768 *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
769 if (!*vlan)
770 return -ENODEV;
771 if (!(*vlan)->ieee80211_ptr)
772 return -EINVAL;
773 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
774 return -EINVAL;
775 }
776 return 0;
777}
778
779static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
780{
781 struct cfg80211_registered_device *drv;
782 int err;
783 struct net_device *dev;
784 struct station_parameters params;
785 u8 *mac_addr = NULL;
786
787 memset(&params, 0, sizeof(params));
788
789 params.listen_interval = -1;
790
791 if (info->attrs[NL80211_ATTR_STA_AID])
792 return -EINVAL;
793
794 if (!info->attrs[NL80211_ATTR_MAC])
795 return -EINVAL;
796
797 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
798
799 if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
800 params.supported_rates =
801 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
802 params.supported_rates_len =
803 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
804 }
805
806 if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
807 params.listen_interval =
808 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
809
810 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
811 &params.station_flags))
812 return -EINVAL;
813
814 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
815 if (err)
816 return err;
817
818 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
819 if (err)
820 goto out;
821
822 if (!drv->ops->change_station) {
823 err = -EOPNOTSUPP;
824 goto out;
825 }
826
827 rtnl_lock();
828 err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
829 rtnl_unlock();
830
831 out:
832 if (params.vlan)
833 dev_put(params.vlan);
834 cfg80211_put_dev(drv);
835 dev_put(dev);
836 return err;
837}
838
839static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
840{
841 struct cfg80211_registered_device *drv;
842 int err;
843 struct net_device *dev;
844 struct station_parameters params;
845 u8 *mac_addr = NULL;
846
847 memset(&params, 0, sizeof(params));
848
849 if (!info->attrs[NL80211_ATTR_MAC])
850 return -EINVAL;
851
852 if (!info->attrs[NL80211_ATTR_STA_AID])
853 return -EINVAL;
854
855 if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
856 return -EINVAL;
857
858 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
859 return -EINVAL;
860
861 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
862 params.supported_rates =
863 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
864 params.supported_rates_len =
865 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
866 params.listen_interval =
867 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
868 params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
869
870 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
871 &params.station_flags))
872 return -EINVAL;
873
874 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
875 if (err)
876 return err;
877
878 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
879 if (err)
880 goto out;
881
882 if (!drv->ops->add_station) {
883 err = -EOPNOTSUPP;
884 goto out;
885 }
886
887 rtnl_lock();
888 err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
889 rtnl_unlock();
890
891 out:
892 if (params.vlan)
893 dev_put(params.vlan);
894 cfg80211_put_dev(drv);
895 dev_put(dev);
896 return err;
897}
898
899static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
900{
901 struct cfg80211_registered_device *drv;
902 int err;
903 struct net_device *dev;
904 u8 *mac_addr = NULL;
905
906 if (info->attrs[NL80211_ATTR_MAC])
907 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
908
909 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
910 if (err)
911 return err;
912
913 if (!drv->ops->del_station) {
914 err = -EOPNOTSUPP;
915 goto out;
916 }
917
918 rtnl_lock();
919 err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
920 rtnl_unlock();
921
922 out:
923 cfg80211_put_dev(drv);
924 dev_put(dev);
925 return err;
926}
927
718static struct genl_ops nl80211_ops[] = { 928static struct genl_ops nl80211_ops[] = {
719 { 929 {
720 .cmd = NL80211_CMD_GET_WIPHY, 930 .cmd = NL80211_CMD_GET_WIPHY,
@@ -796,6 +1006,31 @@ static struct genl_ops nl80211_ops[] = {
796 .flags = GENL_ADMIN_PERM, 1006 .flags = GENL_ADMIN_PERM,
797 .doit = nl80211_del_beacon, 1007 .doit = nl80211_del_beacon,
798 }, 1008 },
1009 {
1010 .cmd = NL80211_CMD_GET_STATION,
1011 .doit = nl80211_get_station,
1012 /* TODO: implement dumpit */
1013 .policy = nl80211_policy,
1014 .flags = GENL_ADMIN_PERM,
1015 },
1016 {
1017 .cmd = NL80211_CMD_SET_STATION,
1018 .doit = nl80211_set_station,
1019 .policy = nl80211_policy,
1020 .flags = GENL_ADMIN_PERM,
1021 },
1022 {
1023 .cmd = NL80211_CMD_NEW_STATION,
1024 .doit = nl80211_new_station,
1025 .policy = nl80211_policy,
1026 .flags = GENL_ADMIN_PERM,
1027 },
1028 {
1029 .cmd = NL80211_CMD_DEL_STATION,
1030 .doit = nl80211_del_station,
1031 .policy = nl80211_policy,
1032 .flags = GENL_ADMIN_PERM,
1033 },
799}; 1034};
800 1035
801/* multicast groups */ 1036/* multicast groups */