aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-12-18 20:03:34 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:59:51 -0500
commit5727ef1b2e797a1922f5bc239b6afb2b4cfb80bc (patch)
tree16fb0c8afcb1c5282fcc45ffa90c8e34b0daa6d4
parented1b6cc7f80f831e192704b05b9917f9cc37be15 (diff)
cfg80211/nl80211: station handling
This patch adds station handling to cfg80211/nl80211. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/nl80211.h68
-rw-r--r--include/net/cfg80211.h55
-rw-r--r--net/wireless/nl80211.c235
3 files changed, 358 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f1e455a8b4de..85e2d7d1f9e3 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -7,6 +7,18 @@
7 */ 7 */
8 8
9/** 9/**
10 * DOC: Station handling
11 *
12 * Stations are added per interface, but a special case exists with VLAN
13 * interfaces. When a station is bound to an AP interface, it may be moved
14 * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
15 * The station is still assumed to belong to the AP interface it was added
16 * to.
17 *
18 * TODO: need more info?
19 */
20
21/**
10 * enum nl80211_commands - supported nl80211 commands 22 * enum nl80211_commands - supported nl80211 commands
11 * 23 *
12 * @NL80211_CMD_UNSPEC: unspecified command to catch errors 24 * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -56,6 +68,16 @@
56 * parameters are like for %NL80211_CMD_SET_BEACON. 68 * parameters are like for %NL80211_CMD_SET_BEACON.
57 * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it 69 * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
58 * 70 *
71 * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
72 * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
73 * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
74 * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
75 * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
76 * the interface identified by %NL80211_ATTR_IFINDEX.
77 * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
78 * or, if no MAC address given, all stations, on the interface identified
79 * by %NL80211_ATTR_IFINDEX.
80 *
59 * @NL80211_CMD_MAX: highest used command number 81 * @NL80211_CMD_MAX: highest used command number
60 * @__NL80211_CMD_AFTER_LAST: internal use 82 * @__NL80211_CMD_AFTER_LAST: internal use
61 */ 83 */
@@ -83,6 +105,11 @@ enum nl80211_commands {
83 NL80211_CMD_NEW_BEACON, 105 NL80211_CMD_NEW_BEACON,
84 NL80211_CMD_DEL_BEACON, 106 NL80211_CMD_DEL_BEACON,
85 107
108 NL80211_CMD_GET_STATION,
109 NL80211_CMD_SET_STATION,
110 NL80211_CMD_NEW_STATION,
111 NL80211_CMD_DEL_STATION,
112
86 /* add commands here */ 113 /* add commands here */
87 114
88 /* used to define NL80211_CMD_MAX below */ 115 /* used to define NL80211_CMD_MAX below */
@@ -120,6 +147,17 @@ enum nl80211_commands {
120 * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE 147 * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
121 * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE 148 * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
122 * 149 *
150 * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
151 * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
152 * &enum nl80211_sta_flags.
153 * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
154 * IEEE 802.11 7.3.1.6 (u16).
155 * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
156 * rates as defined by IEEE 802.11 7.3.2.2 but without the length
157 * restriction (at most %NL80211_MAX_SUPP_RATES).
158 * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
159 * to, or the AP interface the station was originally added to to.
160 *
123 * @NL80211_ATTR_MAX: highest attribute number currently defined 161 * @NL80211_ATTR_MAX: highest attribute number currently defined
124 * @__NL80211_ATTR_AFTER_LAST: internal use 162 * @__NL80211_ATTR_AFTER_LAST: internal use
125 */ 163 */
@@ -147,12 +185,20 @@ enum nl80211_attrs {
147 NL80211_ATTR_BEACON_HEAD, 185 NL80211_ATTR_BEACON_HEAD,
148 NL80211_ATTR_BEACON_TAIL, 186 NL80211_ATTR_BEACON_TAIL,
149 187
188 NL80211_ATTR_STA_AID,
189 NL80211_ATTR_STA_FLAGS,
190 NL80211_ATTR_STA_LISTEN_INTERVAL,
191 NL80211_ATTR_STA_SUPPORTED_RATES,
192 NL80211_ATTR_STA_VLAN,
193
150 /* add attributes here, update the policy in nl80211.c */ 194 /* add attributes here, update the policy in nl80211.c */
151 195
152 __NL80211_ATTR_AFTER_LAST, 196 __NL80211_ATTR_AFTER_LAST,
153 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 197 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
154}; 198};
155 199
200#define NL80211_MAX_SUPP_RATES 32
201
156/** 202/**
157 * enum nl80211_iftype - (virtual) interface types 203 * enum nl80211_iftype - (virtual) interface types
158 * 204 *
@@ -184,4 +230,26 @@ enum nl80211_iftype {
184 NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 230 NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
185}; 231};
186 232
233/**
234 * enum nl80211_sta_flags - station flags
235 *
236 * Station flags. When a station is added to an AP interface, it is
237 * assumed to be already associated (and hence authenticated.)
238 *
239 * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
240 * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
241 * with short barker preamble
242 * @NL80211_STA_FLAG_WME: station is WME/QoS capable
243 */
244enum nl80211_sta_flags {
245 __NL80211_STA_FLAG_INVALID,
246 NL80211_STA_FLAG_AUTHORIZED,
247 NL80211_STA_FLAG_SHORT_PREAMBLE,
248 NL80211_STA_FLAG_WME,
249
250 /* keep last */
251 __NL80211_STA_FLAG_AFTER_LAST,
252 NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
253};
254
187#endif /* __LINUX_NL80211_H */ 255#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fc94852e967b..df650935e268 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -89,6 +89,47 @@ struct beacon_parameters {
89 int head_len, tail_len; 89 int head_len, tail_len;
90}; 90};
91 91
92/**
93 * enum station_flags - station flags
94 *
95 * Station capability flags. Note that these must be the bits
96 * according to the nl80211 flags.
97 *
98 * @STATION_FLAG_CHANGED: station flags were changed
99 * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
100 * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
101 * with short preambles
102 * @STATION_FLAG_WME: station is WME/QoS capable
103 */
104enum station_flags {
105 STATION_FLAG_CHANGED = 1<<0,
106 STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
107 STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
108 STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
109};
110
111/**
112 * struct station_parameters - station parameters
113 *
114 * Used to change and create a new station.
115 *
116 * @vlan: vlan interface station should belong to
117 * @supported_rates: supported rates in IEEE 802.11 format
118 * (or NULL for no change)
119 * @supported_rates_len: number of supported rates
120 * @station_flags: station flags (see &enum station_flags)
121 * @listen_interval: listen interval or -1 for no change
122 * @aid: AID or zero for no change
123 */
124struct station_parameters {
125 u8 *supported_rates;
126 struct net_device *vlan;
127 u32 station_flags;
128 int listen_interval;
129 u16 aid;
130 u8 supported_rates_len;
131};
132
92/* from net/wireless.h */ 133/* from net/wireless.h */
93struct wiphy; 134struct wiphy;
94 135
@@ -130,6 +171,12 @@ struct wiphy;
130 * interface. This should reject the call when no beacon has been 171 * interface. This should reject the call when no beacon has been
131 * configured. 172 * configured.
132 * @del_beacon: Remove beacon configuration and stop sending the beacon. 173 * @del_beacon: Remove beacon configuration and stop sending the beacon.
174 *
175 * @add_station: Add a new station.
176 *
177 * @del_station: Remove a station; @mac may be NULL to remove all stations.
178 *
179 * @change_station: Modify a given station.
133 */ 180 */
134struct cfg80211_ops { 181struct cfg80211_ops {
135 int (*add_virtual_intf)(struct wiphy *wiphy, char *name, 182 int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -155,6 +202,14 @@ struct cfg80211_ops {
155 int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, 202 int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
156 struct beacon_parameters *info); 203 struct beacon_parameters *info);
157 int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); 204 int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
205
206
207 int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
208 u8 *mac, struct station_parameters *params);
209 int (*del_station)(struct wiphy *wiphy, struct net_device *dev,
210 u8 *mac);
211 int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
212 u8 *mac, struct station_parameters *params);
158}; 213};
159 214
160#endif /* __NET_CFG80211_H */ 215#endif /* __NET_CFG80211_H */
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 */