blob: 3309a9c3cfef3f66c84f5f1cb67388dda176c5e6 [file] [log] [blame]
Javier Cardona15dbaac2008-05-17 21:01:24 -07001#include <linux/moduleparam.h>
2#include <linux/delay.h>
3#include <linux/etherdevice.h>
4#include <linux/netdevice.h>
5#include <linux/if_arp.h>
6#include <linux/kthread.h>
7#include <linux/kfifo.h>
8
9#include "host.h"
10#include "decl.h"
11#include "dev.h"
12#include "wext.h"
13#include "debugfs.h"
14#include "scan.h"
15#include "assoc.h"
16#include "cmd.h"
17
18static int mesh_get_default_parameters(struct device *dev,
19 struct mrvl_mesh_defaults *defs)
20{
21 struct lbs_private *priv = to_net_dev(dev)->priv;
22 struct cmd_ds_mesh_config cmd;
23 int ret;
24
25 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
26 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
27 CMD_TYPE_MESH_GET_DEFAULTS);
28
29 if (ret)
30 return -EOPNOTSUPP;
31
32 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
33
34 return 0;
35}
36
37/**
38 * @brief Get function for sysfs attribute bootflag
39 */
40static ssize_t bootflag_get(struct device *dev,
41 struct device_attribute *attr, char *buf)
42{
43 struct mrvl_mesh_defaults defs;
44 int ret;
45
46 ret = mesh_get_default_parameters(dev, &defs);
47
48 if (ret)
49 return ret;
50
Brian Cavagnolofb904902008-07-16 12:15:26 -070051 return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
Javier Cardona15dbaac2008-05-17 21:01:24 -070052}
53
54/**
55 * @brief Set function for sysfs attribute bootflag
56 */
57static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
58 const char *buf, size_t count)
59{
60 struct lbs_private *priv = to_net_dev(dev)->priv;
61 struct cmd_ds_mesh_config cmd;
62 uint32_t datum;
63 int ret;
64
65 memset(&cmd, 0, sizeof(cmd));
Brian Cavagnolofb904902008-07-16 12:15:26 -070066 ret = sscanf(buf, "%d", &datum);
67 if ((ret != 1) || (datum > 1))
Javier Cardona15dbaac2008-05-17 21:01:24 -070068 return -EINVAL;
69
70 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
71 cmd.length = cpu_to_le16(sizeof(uint32_t));
72 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
73 CMD_TYPE_MESH_SET_BOOTFLAG);
74 if (ret)
75 return ret;
76
77 return strlen(buf);
78}
79
80/**
81 * @brief Get function for sysfs attribute boottime
82 */
83static ssize_t boottime_get(struct device *dev,
84 struct device_attribute *attr, char *buf)
85{
86 struct mrvl_mesh_defaults defs;
87 int ret;
88
89 ret = mesh_get_default_parameters(dev, &defs);
90
91 if (ret)
92 return ret;
93
Brian Cavagnolofb904902008-07-16 12:15:26 -070094 return snprintf(buf, 12, "%d\n", defs.boottime);
Javier Cardona15dbaac2008-05-17 21:01:24 -070095}
96
97/**
98 * @brief Set function for sysfs attribute boottime
99 */
100static ssize_t boottime_set(struct device *dev,
101 struct device_attribute *attr, const char *buf, size_t count)
102{
103 struct lbs_private *priv = to_net_dev(dev)->priv;
104 struct cmd_ds_mesh_config cmd;
105 uint32_t datum;
106 int ret;
107
108 memset(&cmd, 0, sizeof(cmd));
Brian Cavagnolofb904902008-07-16 12:15:26 -0700109 ret = sscanf(buf, "%d", &datum);
110 if ((ret != 1) || (datum > 255))
Javier Cardona15dbaac2008-05-17 21:01:24 -0700111 return -EINVAL;
112
113 /* A too small boot time will result in the device booting into
114 * standalone (no-host) mode before the host can take control of it,
115 * so the change will be hard to revert. This may be a desired
116 * feature (e.g to configure a very fast boot time for devices that
117 * will not be attached to a host), but dangerous. So I'm enforcing a
118 * lower limit of 20 seconds: remove and recompile the driver if this
119 * does not work for you.
120 */
121 datum = (datum < 20) ? 20 : datum;
122 cmd.data[0] = datum;
123 cmd.length = cpu_to_le16(sizeof(uint8_t));
124 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
125 CMD_TYPE_MESH_SET_BOOTTIME);
126 if (ret)
127 return ret;
128
129 return strlen(buf);
130}
131
132/**
Javier Cardonab679aeb2008-05-20 15:18:49 -0700133 * @brief Get function for sysfs attribute channel
134 */
135static ssize_t channel_get(struct device *dev,
136 struct device_attribute *attr, char *buf)
137{
138 struct mrvl_mesh_defaults defs;
139 int ret;
140
141 ret = mesh_get_default_parameters(dev, &defs);
142
143 if (ret)
144 return ret;
145
Brian Cavagnolofb904902008-07-16 12:15:26 -0700146 return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
Javier Cardonab679aeb2008-05-20 15:18:49 -0700147}
148
149/**
150 * @brief Set function for sysfs attribute channel
151 */
152static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
153 const char *buf, size_t count)
154{
155 struct lbs_private *priv = to_net_dev(dev)->priv;
156 struct cmd_ds_mesh_config cmd;
Brian Cavagnolofb904902008-07-16 12:15:26 -0700157 uint32_t datum;
Javier Cardonab679aeb2008-05-20 15:18:49 -0700158 int ret;
159
160 memset(&cmd, 0, sizeof(cmd));
Brian Cavagnolofb904902008-07-16 12:15:26 -0700161 ret = sscanf(buf, "%d", &datum);
Javier Cardonab679aeb2008-05-20 15:18:49 -0700162 if (ret != 1 || datum < 1 || datum > 11)
163 return -EINVAL;
164
165 *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
166 cmd.length = cpu_to_le16(sizeof(uint16_t));
167 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
168 CMD_TYPE_MESH_SET_DEF_CHANNEL);
169 if (ret)
170 return ret;
171
172 return strlen(buf);
173}
174
175/**
Javier Cardona15dbaac2008-05-17 21:01:24 -0700176 * @brief Get function for sysfs attribute mesh_id
177 */
178static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
179 char *buf)
180{
181 struct mrvl_mesh_defaults defs;
182 int maxlen;
183 int ret;
184
185 ret = mesh_get_default_parameters(dev, &defs);
186
187 if (ret)
188 return ret;
189
190 if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
Holger Schurigdf349f92008-05-23 12:16:51 +0200191 lbs_pr_err("inconsistent mesh ID length");
Javier Cardona15dbaac2008-05-17 21:01:24 -0700192 defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
193 }
194
195 /* SSID not null terminated: reserve room for \0 + \n */
196 maxlen = defs.meshie.val.mesh_id_len + 2;
197 maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
198
199 defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
200
201 return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
202}
203
204/**
205 * @brief Set function for sysfs attribute mesh_id
206 */
207static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
208 const char *buf, size_t count)
209{
210 struct cmd_ds_mesh_config cmd;
211 struct mrvl_mesh_defaults defs;
212 struct mrvl_meshie *ie;
213 struct lbs_private *priv = to_net_dev(dev)->priv;
214 int len;
215 int ret;
216
217 if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
218 return -EINVAL;
219
220 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
221 ie = (struct mrvl_meshie *) &cmd.data[0];
222
223 /* fetch all other Information Element parameters */
224 ret = mesh_get_default_parameters(dev, &defs);
225
226 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
227
228 /* transfer IE elements */
229 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
230
231 len = count - 1;
232 memcpy(ie->val.mesh_id, buf, len);
233 /* SSID len */
234 ie->val.mesh_id_len = len;
235 /* IE len */
236 ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
237
238 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
239 CMD_TYPE_MESH_SET_MESH_IE);
240 if (ret)
241 return ret;
242
243 return strlen(buf);
244}
245
246/**
247 * @brief Get function for sysfs attribute protocol_id
248 */
249static ssize_t protocol_id_get(struct device *dev,
250 struct device_attribute *attr, char *buf)
251{
252 struct mrvl_mesh_defaults defs;
253 int ret;
254
255 ret = mesh_get_default_parameters(dev, &defs);
256
257 if (ret)
258 return ret;
259
260 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
261}
262
263/**
264 * @brief Set function for sysfs attribute protocol_id
265 */
266static ssize_t protocol_id_set(struct device *dev,
267 struct device_attribute *attr, const char *buf, size_t count)
268{
269 struct cmd_ds_mesh_config cmd;
270 struct mrvl_mesh_defaults defs;
271 struct mrvl_meshie *ie;
272 struct lbs_private *priv = to_net_dev(dev)->priv;
273 uint32_t datum;
274 int ret;
275
276 memset(&cmd, 0, sizeof(cmd));
Brian Cavagnolofb904902008-07-16 12:15:26 -0700277 ret = sscanf(buf, "%d", &datum);
278 if ((ret != 1) || (datum > 255))
Javier Cardona15dbaac2008-05-17 21:01:24 -0700279 return -EINVAL;
280
281 /* fetch all other Information Element parameters */
282 ret = mesh_get_default_parameters(dev, &defs);
283
284 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
285
286 /* transfer IE elements */
287 ie = (struct mrvl_meshie *) &cmd.data[0];
288 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
289 /* update protocol id */
290 ie->val.active_protocol_id = datum;
291
292 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
293 CMD_TYPE_MESH_SET_MESH_IE);
294 if (ret)
295 return ret;
296
297 return strlen(buf);
298}
299
300/**
301 * @brief Get function for sysfs attribute metric_id
302 */
303static ssize_t metric_id_get(struct device *dev,
304 struct device_attribute *attr, char *buf)
305{
306 struct mrvl_mesh_defaults defs;
307 int ret;
308
309 ret = mesh_get_default_parameters(dev, &defs);
310
311 if (ret)
312 return ret;
313
314 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
315}
316
317/**
318 * @brief Set function for sysfs attribute metric_id
319 */
320static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
321 const char *buf, size_t count)
322{
323 struct cmd_ds_mesh_config cmd;
324 struct mrvl_mesh_defaults defs;
325 struct mrvl_meshie *ie;
326 struct lbs_private *priv = to_net_dev(dev)->priv;
327 uint32_t datum;
328 int ret;
329
330 memset(&cmd, 0, sizeof(cmd));
Brian Cavagnolofb904902008-07-16 12:15:26 -0700331 ret = sscanf(buf, "%d", &datum);
332 if ((ret != 1) || (datum > 255))
Javier Cardona15dbaac2008-05-17 21:01:24 -0700333 return -EINVAL;
334
335 /* fetch all other Information Element parameters */
336 ret = mesh_get_default_parameters(dev, &defs);
337
338 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
339
340 /* transfer IE elements */
341 ie = (struct mrvl_meshie *) &cmd.data[0];
342 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
343 /* update metric id */
344 ie->val.active_metric_id = datum;
345
346 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
347 CMD_TYPE_MESH_SET_MESH_IE);
348 if (ret)
349 return ret;
350
351 return strlen(buf);
352}
353
354/**
355 * @brief Get function for sysfs attribute capability
356 */
357static ssize_t capability_get(struct device *dev,
358 struct device_attribute *attr, char *buf)
359{
360 struct mrvl_mesh_defaults defs;
361 int ret;
362
363 ret = mesh_get_default_parameters(dev, &defs);
364
365 if (ret)
366 return ret;
367
368 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
369}
370
371/**
372 * @brief Set function for sysfs attribute capability
373 */
374static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
375 const char *buf, size_t count)
376{
377 struct cmd_ds_mesh_config cmd;
378 struct mrvl_mesh_defaults defs;
379 struct mrvl_meshie *ie;
380 struct lbs_private *priv = to_net_dev(dev)->priv;
381 uint32_t datum;
382 int ret;
383
384 memset(&cmd, 0, sizeof(cmd));
Brian Cavagnolofb904902008-07-16 12:15:26 -0700385 ret = sscanf(buf, "%d", &datum);
386 if ((ret != 1) || (datum > 255))
Javier Cardona15dbaac2008-05-17 21:01:24 -0700387 return -EINVAL;
388
389 /* fetch all other Information Element parameters */
390 ret = mesh_get_default_parameters(dev, &defs);
391
392 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
393
394 /* transfer IE elements */
395 ie = (struct mrvl_meshie *) &cmd.data[0];
396 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
397 /* update value */
398 ie->val.mesh_capability = datum;
399
400 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
401 CMD_TYPE_MESH_SET_MESH_IE);
402 if (ret)
403 return ret;
404
405 return strlen(buf);
406}
407
408
409static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
410static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
Javier Cardonab679aeb2008-05-20 15:18:49 -0700411static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
Javier Cardona15dbaac2008-05-17 21:01:24 -0700412static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
413static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
414static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
415static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
416
417static struct attribute *boot_opts_attrs[] = {
418 &dev_attr_bootflag.attr,
419 &dev_attr_boottime.attr,
Javier Cardonab679aeb2008-05-20 15:18:49 -0700420 &dev_attr_channel.attr,
Javier Cardona15dbaac2008-05-17 21:01:24 -0700421 NULL
422};
423
424static struct attribute_group boot_opts_group = {
425 .name = "boot_options",
426 .attrs = boot_opts_attrs,
427};
428
429static struct attribute *mesh_ie_attrs[] = {
430 &dev_attr_mesh_id.attr,
431 &dev_attr_protocol_id.attr,
432 &dev_attr_metric_id.attr,
433 &dev_attr_capability.attr,
434 NULL
435};
436
437static struct attribute_group mesh_ie_group = {
438 .name = "mesh_ie",
439 .attrs = mesh_ie_attrs,
440};
441
442void lbs_persist_config_init(struct net_device *dev)
443{
444 int ret;
445 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
446 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
447}
448
449void lbs_persist_config_remove(struct net_device *dev)
450{
451 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
452 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
453}