aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/debugfs_netdev.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-12-01 07:37:02 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-22 13:31:16 -0500
commit0f78231bffb868a30e8533aace142213266bb811 (patch)
tree317f65dc6d89e9a89ad83f94fadd780dd1e0ca83 /net/mac80211/debugfs_netdev.c
parent18974b5b0b5e758d416c550553b143e5c8038281 (diff)
mac80211: enable spatial multiplexing powersave
Enable spatial multiplexing in mac80211 by telling the driver what to do and, where necessary, sending action frames to the AP to update the requested SMPS mode. Also includes a trivial implementation for hwsim that just logs the requested mode. For now, the userspace interface is in debugfs only, and let you toggle the requested mode at any time. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/debugfs_netdev.c')
-rw-r--r--net/mac80211/debugfs_netdev.c111
1 files changed, 108 insertions, 3 deletions
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 5d9c797635a9..355983503885 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -41,6 +41,30 @@ static ssize_t ieee80211_if_read(
41 return ret; 41 return ret;
42} 42}
43 43
44static ssize_t ieee80211_if_write(
45 struct ieee80211_sub_if_data *sdata,
46 const char __user *userbuf,
47 size_t count, loff_t *ppos,
48 ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
49{
50 u8 *buf;
51 ssize_t ret = -ENODEV;
52
53 buf = kzalloc(count, GFP_KERNEL);
54 if (!buf)
55 return -ENOMEM;
56
57 if (copy_from_user(buf, userbuf, count))
58 return -EFAULT;
59
60 rtnl_lock();
61 if (sdata->dev->reg_state == NETREG_REGISTERED)
62 ret = (*write)(sdata, buf, count);
63 rtnl_unlock();
64
65 return ret;
66}
67
44#define IEEE80211_IF_FMT(name, field, format_string) \ 68#define IEEE80211_IF_FMT(name, field, format_string) \
45static ssize_t ieee80211_if_fmt_##name( \ 69static ssize_t ieee80211_if_fmt_##name( \
46 const struct ieee80211_sub_if_data *sdata, char *buf, \ 70 const struct ieee80211_sub_if_data *sdata, char *buf, \
@@ -71,7 +95,7 @@ static ssize_t ieee80211_if_fmt_##name( \
71 return scnprintf(buf, buflen, "%pM\n", sdata->field); \ 95 return scnprintf(buf, buflen, "%pM\n", sdata->field); \
72} 96}
73 97
74#define __IEEE80211_IF_FILE(name) \ 98#define __IEEE80211_IF_FILE(name, _write) \
75static ssize_t ieee80211_if_read_##name(struct file *file, \ 99static ssize_t ieee80211_if_read_##name(struct file *file, \
76 char __user *userbuf, \ 100 char __user *userbuf, \
77 size_t count, loff_t *ppos) \ 101 size_t count, loff_t *ppos) \
@@ -82,12 +106,24 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \
82} \ 106} \
83static const struct file_operations name##_ops = { \ 107static const struct file_operations name##_ops = { \
84 .read = ieee80211_if_read_##name, \ 108 .read = ieee80211_if_read_##name, \
109 .write = (_write), \
85 .open = mac80211_open_file_generic, \ 110 .open = mac80211_open_file_generic, \
86} 111}
87 112
113#define __IEEE80211_IF_FILE_W(name) \
114static ssize_t ieee80211_if_write_##name(struct file *file, \
115 const char __user *userbuf, \
116 size_t count, loff_t *ppos) \
117{ \
118 return ieee80211_if_write(file->private_data, userbuf, count, \
119 ppos, ieee80211_if_parse_##name); \
120} \
121__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
122
123
88#define IEEE80211_IF_FILE(name, field, format) \ 124#define IEEE80211_IF_FILE(name, field, format) \
89 IEEE80211_IF_FMT_##format(name, field) \ 125 IEEE80211_IF_FMT_##format(name, field) \
90 __IEEE80211_IF_FILE(name) 126 __IEEE80211_IF_FILE(name, NULL)
91 127
92/* common attributes */ 128/* common attributes */
93IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); 129IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
@@ -99,6 +135,70 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
99IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); 135IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
100IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); 136IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
101 137
138static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
139 enum ieee80211_smps_mode smps_mode)
140{
141 struct ieee80211_local *local = sdata->local;
142 int err;
143
144 if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
145 smps_mode == IEEE80211_SMPS_STATIC)
146 return -EINVAL;
147
148 /* auto should be dynamic if in PS mode */
149 if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) &&
150 (smps_mode == IEEE80211_SMPS_DYNAMIC ||
151 smps_mode == IEEE80211_SMPS_AUTOMATIC))
152 return -EINVAL;
153
154 /* supported only on managed interfaces for now */
155 if (sdata->vif.type != NL80211_IFTYPE_STATION)
156 return -EOPNOTSUPP;
157
158 mutex_lock(&local->iflist_mtx);
159 err = __ieee80211_request_smps(sdata, smps_mode);
160 mutex_unlock(&local->iflist_mtx);
161
162 return err;
163}
164
165static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
166 [IEEE80211_SMPS_AUTOMATIC] = "auto",
167 [IEEE80211_SMPS_OFF] = "off",
168 [IEEE80211_SMPS_STATIC] = "static",
169 [IEEE80211_SMPS_DYNAMIC] = "dynamic",
170};
171
172static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
173 char *buf, int buflen)
174{
175 if (sdata->vif.type != NL80211_IFTYPE_STATION)
176 return -EOPNOTSUPP;
177
178 return snprintf(buf, buflen, "request: %s\nused: %s\n",
179 smps_modes[sdata->u.mgd.req_smps],
180 smps_modes[sdata->u.mgd.ap_smps]);
181}
182
183static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
184 const char *buf, int buflen)
185{
186 enum ieee80211_smps_mode mode;
187
188 for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
189 if (strncmp(buf, smps_modes[mode], buflen) == 0) {
190 int err = ieee80211_set_smps(sdata, mode);
191 if (!err)
192 return buflen;
193 return err;
194 }
195 }
196
197 return -EINVAL;
198}
199
200__IEEE80211_IF_FILE_W(smps);
201
102/* AP attributes */ 202/* AP attributes */
103IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); 203IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
104IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); 204IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
@@ -109,7 +209,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
109 return scnprintf(buf, buflen, "%u\n", 209 return scnprintf(buf, buflen, "%u\n",
110 skb_queue_len(&sdata->u.ap.ps_bc_buf)); 210 skb_queue_len(&sdata->u.ap.ps_bc_buf));
111} 211}
112__IEEE80211_IF_FILE(num_buffered_multicast); 212__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
113 213
114/* WDS attributes */ 214/* WDS attributes */
115IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); 215IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
@@ -158,6 +258,10 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
158 debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ 258 debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
159 sdata, &name##_ops); 259 sdata, &name##_ops);
160 260
261#define DEBUGFS_ADD_MODE(name, mode) \
262 debugfs_create_file(#name, mode, sdata->debugfs.dir, \
263 sdata, &name##_ops);
264
161static void add_sta_files(struct ieee80211_sub_if_data *sdata) 265static void add_sta_files(struct ieee80211_sub_if_data *sdata)
162{ 266{
163 DEBUGFS_ADD(drop_unencrypted, sta); 267 DEBUGFS_ADD(drop_unencrypted, sta);
@@ -167,6 +271,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
167 DEBUGFS_ADD(bssid, sta); 271 DEBUGFS_ADD(bssid, sta);
168 DEBUGFS_ADD(aid, sta); 272 DEBUGFS_ADD(aid, sta);
169 DEBUGFS_ADD(capab, sta); 273 DEBUGFS_ADD(capab, sta);
274 DEBUGFS_ADD_MODE(smps, 0600);
170} 275}
171 276
172static void add_ap_files(struct ieee80211_sub_if_data *sdata) 277static void add_ap_files(struct ieee80211_sub_if_data *sdata)