• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #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 
mesh_get_default_parameters(struct device * dev,struct mrvl_mesh_defaults * defs)18 static int mesh_get_default_parameters(struct device *dev,
19 				       struct mrvl_mesh_defaults *defs)
20 {
21 	struct lbs_private *priv = to_net_dev(dev)->ml_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  */
bootflag_get(struct device * dev,struct device_attribute * attr,char * buf)40 static 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 
51 	return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
52 }
53 
54 /**
55  * @brief Set function for sysfs attribute bootflag
56  */
bootflag_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)57 static 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)->ml_priv;
61 	struct cmd_ds_mesh_config cmd;
62 	uint32_t datum;
63 	int ret;
64 
65 	memset(&cmd, 0, sizeof(cmd));
66 	ret = sscanf(buf, "%d", &datum);
67 	if ((ret != 1) || (datum > 1))
68 		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  */
boottime_get(struct device * dev,struct device_attribute * attr,char * buf)83 static 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 
94 	return snprintf(buf, 12, "%d\n", defs.boottime);
95 }
96 
97 /**
98  * @brief Set function for sysfs attribute boottime
99  */
boottime_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)100 static 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)->ml_priv;
104 	struct cmd_ds_mesh_config cmd;
105 	uint32_t datum;
106 	int ret;
107 
108 	memset(&cmd, 0, sizeof(cmd));
109 	ret = sscanf(buf, "%d", &datum);
110 	if ((ret != 1) || (datum > 255))
111 		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 /**
133  * @brief Get function for sysfs attribute channel
134  */
channel_get(struct device * dev,struct device_attribute * attr,char * buf)135 static 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 
146 	return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
147 }
148 
149 /**
150  * @brief Set function for sysfs attribute channel
151  */
channel_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)152 static 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)->ml_priv;
156 	struct cmd_ds_mesh_config cmd;
157 	uint32_t datum;
158 	int ret;
159 
160 	memset(&cmd, 0, sizeof(cmd));
161 	ret = sscanf(buf, "%d", &datum);
162 	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 /**
176  * @brief Get function for sysfs attribute mesh_id
177  */
mesh_id_get(struct device * dev,struct device_attribute * attr,char * buf)178 static 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) {
191 		lbs_pr_err("inconsistent mesh ID length");
192 		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  */
mesh_id_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)207 static 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)->ml_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->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  */
protocol_id_get(struct device * dev,struct device_attribute * attr,char * buf)249 static 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  */
protocol_id_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)266 static 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)->ml_priv;
273 	uint32_t datum;
274 	int ret;
275 
276 	memset(&cmd, 0, sizeof(cmd));
277 	ret = sscanf(buf, "%d", &datum);
278 	if ((ret != 1) || (datum > 255))
279 		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  */
metric_id_get(struct device * dev,struct device_attribute * attr,char * buf)303 static 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  */
metric_id_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)320 static 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)->ml_priv;
327 	uint32_t datum;
328 	int ret;
329 
330 	memset(&cmd, 0, sizeof(cmd));
331 	ret = sscanf(buf, "%d", &datum);
332 	if ((ret != 1) || (datum > 255))
333 		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  */
capability_get(struct device * dev,struct device_attribute * attr,char * buf)357 static 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  */
capability_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)374 static 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)->ml_priv;
381 	uint32_t datum;
382 	int ret;
383 
384 	memset(&cmd, 0, sizeof(cmd));
385 	ret = sscanf(buf, "%d", &datum);
386 	if ((ret != 1) || (datum > 255))
387 		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 
409 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
410 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
411 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
412 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
413 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
414 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
415 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
416 
417 static struct attribute *boot_opts_attrs[] = {
418 	&dev_attr_bootflag.attr,
419 	&dev_attr_boottime.attr,
420 	&dev_attr_channel.attr,
421 	NULL
422 };
423 
424 static struct attribute_group boot_opts_group = {
425 	.name = "boot_options",
426 	.attrs = boot_opts_attrs,
427 };
428 
429 static 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 
437 static struct attribute_group mesh_ie_group = {
438 	.name = "mesh_ie",
439 	.attrs = mesh_ie_attrs,
440 };
441 
lbs_persist_config_init(struct net_device * dev)442 void 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 
lbs_persist_config_remove(struct net_device * dev)449 void 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 }
454