net: remove use of ndo_set_multicast_list in drivers
[deliverable/linux.git] / drivers / net / wireless / libertas / mesh.c
CommitLineData
0e4e06ae
JP
1#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2
15dbaac0
JC
3#include <linux/delay.h>
4#include <linux/etherdevice.h>
a6b7a407 5#include <linux/hardirq.h>
15dbaac0 6#include <linux/netdevice.h>
1f044931 7#include <linux/if_ether.h>
15dbaac0
JC
8#include <linux/if_arp.h>
9#include <linux/kthread.h>
10#include <linux/kfifo.h>
e86dc1ca 11#include <net/cfg80211.h>
15dbaac0 12
e0e42da3 13#include "mesh.h"
15dbaac0 14#include "decl.h"
15dbaac0
JC
15#include "cmd.h"
16
e0e42da3 17
3db4f989
DD
18static int lbs_add_mesh(struct lbs_private *priv);
19
20/***************************************************************************
21 * Mesh command handling
22 */
23
24static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
25 struct cmd_ds_mesh_access *cmd)
26{
27 int ret;
28
29 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
30
31 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
32 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
33 cmd->hdr.result = 0;
34
35 cmd->action = cpu_to_le16(cmd_action);
36
37 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
38
39 lbs_deb_leave(LBS_DEB_CMD);
40 return ret;
41}
42
43static int __lbs_mesh_config_send(struct lbs_private *priv,
44 struct cmd_ds_mesh_config *cmd,
45 uint16_t action, uint16_t type)
46{
47 int ret;
48 u16 command = CMD_MESH_CONFIG_OLD;
49
50 lbs_deb_enter(LBS_DEB_CMD);
51
52 /*
53 * Command id is 0xac for v10 FW along with mesh interface
54 * id in bits 14-13-12.
55 */
56 if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
57 command = CMD_MESH_CONFIG |
58 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
59
60 cmd->hdr.command = cpu_to_le16(command);
61 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
62 cmd->hdr.result = 0;
63
64 cmd->type = cpu_to_le16(type);
65 cmd->action = cpu_to_le16(action);
66
67 ret = lbs_cmd_with_response(priv, command, cmd);
68
69 lbs_deb_leave(LBS_DEB_CMD);
70 return ret;
71}
72
73static int lbs_mesh_config_send(struct lbs_private *priv,
74 struct cmd_ds_mesh_config *cmd,
75 uint16_t action, uint16_t type)
76{
77 int ret;
78
79 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
80 return -EOPNOTSUPP;
81
82 ret = __lbs_mesh_config_send(priv, cmd, action, type);
83 return ret;
84}
85
86/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
87 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
88 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
89 * lbs_mesh_config_send.
90 */
91static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
92 uint16_t chan)
93{
94 struct cmd_ds_mesh_config cmd;
95 struct mrvl_meshie *ie;
96 DECLARE_SSID_BUF(ssid);
97
98 memset(&cmd, 0, sizeof(cmd));
99 cmd.channel = cpu_to_le16(chan);
100 ie = (struct mrvl_meshie *)cmd.data;
101
102 switch (action) {
103 case CMD_ACT_MESH_CONFIG_START:
104 ie->id = WLAN_EID_GENERIC;
105 ie->val.oui[0] = 0x00;
106 ie->val.oui[1] = 0x50;
107 ie->val.oui[2] = 0x43;
108 ie->val.type = MARVELL_MESH_IE_TYPE;
109 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
110 ie->val.version = MARVELL_MESH_IE_VERSION;
111 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
112 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
113 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
114 ie->val.mesh_id_len = priv->mesh_ssid_len;
115 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
116 ie->len = sizeof(struct mrvl_meshie_val) -
117 IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
118 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
119 break;
120 case CMD_ACT_MESH_CONFIG_STOP:
121 break;
122 default:
123 return -1;
124 }
125 lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
126 action, priv->mesh_tlv, chan,
127 print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
128
129 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
130}
131
132
e0e42da3
HS
133/***************************************************************************
134 * Mesh sysfs support
135 */
136
8973a6e7 137/*
e0e42da3
HS
138 * Attributes exported through sysfs
139 */
140
141/**
8973a6e7
RD
142 * lbs_anycast_get - Get function for sysfs attribute anycast_mask
143 * @dev: the &struct device
144 * @attr: device attributes
145 * @buf: buffer where data will be returned
e0e42da3
HS
146 */
147static ssize_t lbs_anycast_get(struct device *dev,
148 struct device_attribute *attr, char * buf)
149{
150 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
151 struct cmd_ds_mesh_access mesh_access;
152 int ret;
153
154 memset(&mesh_access, 0, sizeof(mesh_access));
155
156 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
157 if (ret)
158 return ret;
159
160 return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
161}
162
163/**
8973a6e7
RD
164 * lbs_anycast_set - Set function for sysfs attribute anycast_mask
165 * @dev: the &struct device
166 * @attr: device attributes
167 * @buf: buffer that contains new attribute value
168 * @count: size of buffer
e0e42da3
HS
169 */
170static ssize_t lbs_anycast_set(struct device *dev,
171 struct device_attribute *attr, const char * buf, size_t count)
172{
173 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
174 struct cmd_ds_mesh_access mesh_access;
175 uint32_t datum;
176 int ret;
177
178 memset(&mesh_access, 0, sizeof(mesh_access));
179 sscanf(buf, "%x", &datum);
180 mesh_access.data[0] = cpu_to_le32(datum);
181
182 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
183 if (ret)
184 return ret;
185
186 return strlen(buf);
187}
188
189/**
8973a6e7
RD
190 * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
191 * @dev: the &struct device
192 * @attr: device attributes
193 * @buf: buffer where data will be returned
e0e42da3
HS
194 */
195static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
196 struct device_attribute *attr, char *buf)
197{
198 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
199 struct cmd_ds_mesh_access mesh_access;
200 int ret;
201 u32 retry_limit;
202
203 memset(&mesh_access, 0, sizeof(mesh_access));
204 mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
205
206 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
207 &mesh_access);
208 if (ret)
209 return ret;
210
211 retry_limit = le32_to_cpu(mesh_access.data[1]);
212 return snprintf(buf, 10, "%d\n", retry_limit);
213}
214
215/**
8973a6e7
RD
216 * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
217 * @dev: the &struct device
218 * @attr: device attributes
219 * @buf: buffer that contains new attribute value
220 * @count: size of buffer
e0e42da3
HS
221 */
222static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
223 struct device_attribute *attr, const char *buf, size_t count)
224{
225 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
226 struct cmd_ds_mesh_access mesh_access;
227 int ret;
228 unsigned long retry_limit;
229
230 memset(&mesh_access, 0, sizeof(mesh_access));
231 mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
232
233 if (!strict_strtoul(buf, 10, &retry_limit))
234 return -ENOTSUPP;
235 if (retry_limit > 15)
236 return -ENOTSUPP;
237
238 mesh_access.data[1] = cpu_to_le32(retry_limit);
239
240 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
241 &mesh_access);
242 if (ret)
243 return ret;
244
245 return strlen(buf);
246}
247
248/**
8973a6e7
RD
249 * lbs_mesh_get - Get function for sysfs attribute mesh
250 * @dev: the &struct device
251 * @attr: device attributes
252 * @buf: buffer where data will be returned
e0e42da3
HS
253 */
254static ssize_t lbs_mesh_get(struct device *dev,
255 struct device_attribute *attr, char * buf)
256{
257 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
258 return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
259}
260
261/**
8973a6e7
RD
262 * lbs_mesh_set - Set function for sysfs attribute mesh
263 * @dev: the &struct device
264 * @attr: device attributes
265 * @buf: buffer that contains new attribute value
266 * @count: size of buffer
e0e42da3
HS
267 */
268static ssize_t lbs_mesh_set(struct device *dev,
269 struct device_attribute *attr, const char * buf, size_t count)
270{
271 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
272 int enable;
e0e42da3
HS
273
274 sscanf(buf, "%x", &enable);
275 enable = !!enable;
276 if (enable == !!priv->mesh_dev)
277 return count;
e0e42da3
HS
278
279 if (enable)
280 lbs_add_mesh(priv);
281 else
282 lbs_remove_mesh(priv);
283
284 return count;
285}
286
8973a6e7 287/*
e0e42da3
HS
288 * lbs_mesh attribute to be exported per ethX interface
289 * through sysfs (/sys/class/net/ethX/lbs_mesh)
290 */
291static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
292
8973a6e7 293/*
e0e42da3
HS
294 * anycast_mask attribute to be exported per mshX interface
295 * through sysfs (/sys/class/net/mshX/anycast_mask)
296 */
297static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
298
8973a6e7 299/*
e0e42da3
HS
300 * prb_rsp_limit attribute to be exported per mshX interface
301 * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
302 */
303static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
304 lbs_prb_rsp_limit_set);
305
306static struct attribute *lbs_mesh_sysfs_entries[] = {
307 &dev_attr_anycast_mask.attr,
308 &dev_attr_prb_rsp_limit.attr,
309 NULL,
310};
311
3db4f989 312static const struct attribute_group lbs_mesh_attr_group = {
e0e42da3
HS
313 .attrs = lbs_mesh_sysfs_entries,
314};
315
316
e0e42da3 317/***************************************************************************
3db4f989 318 * Persistent configuration support
e0e42da3
HS
319 */
320
3db4f989
DD
321static int mesh_get_default_parameters(struct device *dev,
322 struct mrvl_mesh_defaults *defs)
e0e42da3 323{
3db4f989
DD
324 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
325 struct cmd_ds_mesh_config cmd;
326 int ret;
e0e42da3 327
3db4f989
DD
328 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
329 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
330 CMD_TYPE_MESH_GET_DEFAULTS);
e0e42da3 331
3db4f989
DD
332 if (ret)
333 return -EOPNOTSUPP;
c24ef46e 334
3db4f989 335 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
c24ef46e 336
3db4f989
DD
337 return 0;
338}
e4da1a81 339
3db4f989
DD
340/**
341 * bootflag_get - Get function for sysfs attribute bootflag
342 * @dev: the &struct device
343 * @attr: device attributes
344 * @buf: buffer where data will be returned
345 */
346static ssize_t bootflag_get(struct device *dev,
347 struct device_attribute *attr, char *buf)
348{
349 struct mrvl_mesh_defaults defs;
350 int ret;
e0e42da3 351
3db4f989 352 ret = mesh_get_default_parameters(dev, &defs);
e0e42da3 353
3db4f989
DD
354 if (ret)
355 return ret;
e0e42da3 356
3db4f989 357 return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
e0e42da3
HS
358}
359
3db4f989
DD
360/**
361 * bootflag_set - Set function for sysfs attribute bootflag
362 * @dev: the &struct device
363 * @attr: device attributes
364 * @buf: buffer that contains new attribute value
365 * @count: size of buffer
366 */
367static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
368 const char *buf, size_t count)
e0e42da3 369{
3db4f989
DD
370 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
371 struct cmd_ds_mesh_config cmd;
372 uint32_t datum;
373 int ret;
e0e42da3 374
3db4f989
DD
375 memset(&cmd, 0, sizeof(cmd));
376 ret = sscanf(buf, "%d", &datum);
377 if ((ret != 1) || (datum > 1))
378 return -EINVAL;
e0e42da3 379
3db4f989
DD
380 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
381 cmd.length = cpu_to_le16(sizeof(uint32_t));
382 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
383 CMD_TYPE_MESH_SET_BOOTFLAG);
384 if (ret)
385 return ret;
e0e42da3 386
3db4f989 387 return strlen(buf);
e0e42da3
HS
388}
389
e0e42da3 390/**
3db4f989
DD
391 * boottime_get - Get function for sysfs attribute boottime
392 * @dev: the &struct device
393 * @attr: device attributes
394 * @buf: buffer where data will be returned
e0e42da3 395 */
3db4f989
DD
396static ssize_t boottime_get(struct device *dev,
397 struct device_attribute *attr, char *buf)
e0e42da3 398{
3db4f989
DD
399 struct mrvl_mesh_defaults defs;
400 int ret;
e0e42da3 401
3db4f989 402 ret = mesh_get_default_parameters(dev, &defs);
e0e42da3 403
3db4f989
DD
404 if (ret)
405 return ret;
15dbaac0 406
fb904907 407 return snprintf(buf, 12, "%d\n", defs.boottime);
15dbaac0
JC
408}
409
410/**
8973a6e7
RD
411 * boottime_set - Set function for sysfs attribute boottime
412 * @dev: the &struct device
413 * @attr: device attributes
414 * @buf: buffer that contains new attribute value
415 * @count: size of buffer
15dbaac0
JC
416 */
417static ssize_t boottime_set(struct device *dev,
418 struct device_attribute *attr, const char *buf, size_t count)
419{
ab65f649 420 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
15dbaac0
JC
421 struct cmd_ds_mesh_config cmd;
422 uint32_t datum;
423 int ret;
424
425 memset(&cmd, 0, sizeof(cmd));
fb904907
BC
426 ret = sscanf(buf, "%d", &datum);
427 if ((ret != 1) || (datum > 255))
15dbaac0
JC
428 return -EINVAL;
429
430 /* A too small boot time will result in the device booting into
431 * standalone (no-host) mode before the host can take control of it,
432 * so the change will be hard to revert. This may be a desired
433 * feature (e.g to configure a very fast boot time for devices that
434 * will not be attached to a host), but dangerous. So I'm enforcing a
435 * lower limit of 20 seconds: remove and recompile the driver if this
436 * does not work for you.
437 */
438 datum = (datum < 20) ? 20 : datum;
439 cmd.data[0] = datum;
440 cmd.length = cpu_to_le16(sizeof(uint8_t));
441 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
442 CMD_TYPE_MESH_SET_BOOTTIME);
443 if (ret)
444 return ret;
445
446 return strlen(buf);
447}
448
b679aeb3 449/**
8973a6e7
RD
450 * channel_get - Get function for sysfs attribute channel
451 * @dev: the &struct device
452 * @attr: device attributes
453 * @buf: buffer where data will be returned
b679aeb3
JC
454 */
455static ssize_t channel_get(struct device *dev,
456 struct device_attribute *attr, char *buf)
457{
458 struct mrvl_mesh_defaults defs;
459 int ret;
460
461 ret = mesh_get_default_parameters(dev, &defs);
462
463 if (ret)
464 return ret;
465
fb904907 466 return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
b679aeb3
JC
467}
468
469/**
8973a6e7
RD
470 * channel_set - Set function for sysfs attribute channel
471 * @dev: the &struct device
472 * @attr: device attributes
473 * @buf: buffer that contains new attribute value
474 * @count: size of buffer
b679aeb3
JC
475 */
476static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
477 const char *buf, size_t count)
478{
ab65f649 479 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
b679aeb3 480 struct cmd_ds_mesh_config cmd;
fb904907 481 uint32_t datum;
b679aeb3
JC
482 int ret;
483
484 memset(&cmd, 0, sizeof(cmd));
fb904907 485 ret = sscanf(buf, "%d", &datum);
b679aeb3
JC
486 if (ret != 1 || datum < 1 || datum > 11)
487 return -EINVAL;
488
489 *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
490 cmd.length = cpu_to_le16(sizeof(uint16_t));
491 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
492 CMD_TYPE_MESH_SET_DEF_CHANNEL);
493 if (ret)
494 return ret;
495
496 return strlen(buf);
497}
498
15dbaac0 499/**
8973a6e7
RD
500 * mesh_id_get - Get function for sysfs attribute mesh_id
501 * @dev: the &struct device
502 * @attr: device attributes
503 * @buf: buffer where data will be returned
15dbaac0
JC
504 */
505static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
506 char *buf)
507{
508 struct mrvl_mesh_defaults defs;
15dbaac0
JC
509 int ret;
510
511 ret = mesh_get_default_parameters(dev, &defs);
512
513 if (ret)
514 return ret;
515
243e84e9 516 if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
f3a57fd1 517 dev_err(dev, "inconsistent mesh ID length\n");
243e84e9 518 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
15dbaac0
JC
519 }
520
d89dba7a
DC
521 memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
522 buf[defs.meshie.val.mesh_id_len] = '\n';
523 buf[defs.meshie.val.mesh_id_len + 1] = '\0';
15dbaac0 524
d89dba7a 525 return defs.meshie.val.mesh_id_len + 1;
15dbaac0
JC
526}
527
528/**
8973a6e7
RD
529 * mesh_id_set - Set function for sysfs attribute mesh_id
530 * @dev: the &struct device
531 * @attr: device attributes
532 * @buf: buffer that contains new attribute value
533 * @count: size of buffer
15dbaac0
JC
534 */
535static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
536 const char *buf, size_t count)
537{
538 struct cmd_ds_mesh_config cmd;
539 struct mrvl_mesh_defaults defs;
540 struct mrvl_meshie *ie;
ab65f649 541 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
15dbaac0
JC
542 int len;
543 int ret;
544
243e84e9 545 if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
15dbaac0
JC
546 return -EINVAL;
547
548 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
549 ie = (struct mrvl_meshie *) &cmd.data[0];
550
551 /* fetch all other Information Element parameters */
552 ret = mesh_get_default_parameters(dev, &defs);
553
554 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
555
556 /* transfer IE elements */
557 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
558
559 len = count - 1;
560 memcpy(ie->val.mesh_id, buf, len);
561 /* SSID len */
562 ie->val.mesh_id_len = len;
563 /* IE len */
243e84e9 564 ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
15dbaac0
JC
565
566 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
567 CMD_TYPE_MESH_SET_MESH_IE);
568 if (ret)
569 return ret;
570
571 return strlen(buf);
572}
573
574/**
8973a6e7
RD
575 * protocol_id_get - Get function for sysfs attribute protocol_id
576 * @dev: the &struct device
577 * @attr: device attributes
578 * @buf: buffer where data will be returned
15dbaac0
JC
579 */
580static ssize_t protocol_id_get(struct device *dev,
581 struct device_attribute *attr, char *buf)
582{
583 struct mrvl_mesh_defaults defs;
584 int ret;
585
586 ret = mesh_get_default_parameters(dev, &defs);
587
588 if (ret)
589 return ret;
590
591 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
592}
593
594/**
8973a6e7
RD
595 * protocol_id_set - Set function for sysfs attribute protocol_id
596 * @dev: the &struct device
597 * @attr: device attributes
598 * @buf: buffer that contains new attribute value
599 * @count: size of buffer
15dbaac0
JC
600 */
601static ssize_t protocol_id_set(struct device *dev,
602 struct device_attribute *attr, const char *buf, size_t count)
603{
604 struct cmd_ds_mesh_config cmd;
605 struct mrvl_mesh_defaults defs;
606 struct mrvl_meshie *ie;
ab65f649 607 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
15dbaac0
JC
608 uint32_t datum;
609 int ret;
610
611 memset(&cmd, 0, sizeof(cmd));
fb904907
BC
612 ret = sscanf(buf, "%d", &datum);
613 if ((ret != 1) || (datum > 255))
15dbaac0
JC
614 return -EINVAL;
615
616 /* fetch all other Information Element parameters */
617 ret = mesh_get_default_parameters(dev, &defs);
618
619 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
620
621 /* transfer IE elements */
622 ie = (struct mrvl_meshie *) &cmd.data[0];
623 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
624 /* update protocol id */
625 ie->val.active_protocol_id = datum;
626
627 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
628 CMD_TYPE_MESH_SET_MESH_IE);
629 if (ret)
630 return ret;
631
632 return strlen(buf);
633}
634
635/**
8973a6e7
RD
636 * metric_id_get - Get function for sysfs attribute metric_id
637 * @dev: the &struct device
638 * @attr: device attributes
639 * @buf: buffer where data will be returned
15dbaac0
JC
640 */
641static ssize_t metric_id_get(struct device *dev,
642 struct device_attribute *attr, char *buf)
643{
3db4f989
DD
644 struct mrvl_mesh_defaults defs;
645 int ret;
646
647 ret = mesh_get_default_parameters(dev, &defs);
648
649 if (ret)
650 return ret;
651
652 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
653}
654
655/**
656 * metric_id_set - Set function for sysfs attribute metric_id
657 * @dev: the &struct device
658 * @attr: device attributes
659 * @buf: buffer that contains new attribute value
660 * @count: size of buffer
661 */
662static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
663 const char *buf, size_t count)
664{
665 struct cmd_ds_mesh_config cmd;
666 struct mrvl_mesh_defaults defs;
667 struct mrvl_meshie *ie;
668 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
669 uint32_t datum;
670 int ret;
671
672 memset(&cmd, 0, sizeof(cmd));
673 ret = sscanf(buf, "%d", &datum);
674 if ((ret != 1) || (datum > 255))
675 return -EINVAL;
676
677 /* fetch all other Information Element parameters */
678 ret = mesh_get_default_parameters(dev, &defs);
679
680 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
681
682 /* transfer IE elements */
683 ie = (struct mrvl_meshie *) &cmd.data[0];
684 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
685 /* update metric id */
686 ie->val.active_metric_id = datum;
687
688 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
689 CMD_TYPE_MESH_SET_MESH_IE);
690 if (ret)
691 return ret;
692
693 return strlen(buf);
694}
695
696/**
697 * capability_get - Get function for sysfs attribute capability
698 * @dev: the &struct device
699 * @attr: device attributes
700 * @buf: buffer where data will be returned
701 */
702static ssize_t capability_get(struct device *dev,
703 struct device_attribute *attr, char *buf)
704{
705 struct mrvl_mesh_defaults defs;
706 int ret;
707
708 ret = mesh_get_default_parameters(dev, &defs);
709
710 if (ret)
711 return ret;
712
713 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
714}
715
716/**
717 * capability_set - Set function for sysfs attribute capability
718 * @dev: the &struct device
719 * @attr: device attributes
720 * @buf: buffer that contains new attribute value
721 * @count: size of buffer
722 */
723static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
724 const char *buf, size_t count)
725{
726 struct cmd_ds_mesh_config cmd;
727 struct mrvl_mesh_defaults defs;
728 struct mrvl_meshie *ie;
729 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
730 uint32_t datum;
731 int ret;
732
733 memset(&cmd, 0, sizeof(cmd));
734 ret = sscanf(buf, "%d", &datum);
735 if ((ret != 1) || (datum > 255))
736 return -EINVAL;
737
738 /* fetch all other Information Element parameters */
739 ret = mesh_get_default_parameters(dev, &defs);
740
741 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
742
743 /* transfer IE elements */
744 ie = (struct mrvl_meshie *) &cmd.data[0];
745 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
746 /* update value */
747 ie->val.mesh_capability = datum;
748
749 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
750 CMD_TYPE_MESH_SET_MESH_IE);
751 if (ret)
752 return ret;
753
754 return strlen(buf);
755}
756
757
758static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
759static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
760static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
761static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
762static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
763static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
764static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
765
766static struct attribute *boot_opts_attrs[] = {
767 &dev_attr_bootflag.attr,
768 &dev_attr_boottime.attr,
769 &dev_attr_channel.attr,
770 NULL
771};
772
773static const struct attribute_group boot_opts_group = {
774 .name = "boot_options",
775 .attrs = boot_opts_attrs,
776};
777
778static struct attribute *mesh_ie_attrs[] = {
779 &dev_attr_mesh_id.attr,
780 &dev_attr_protocol_id.attr,
781 &dev_attr_metric_id.attr,
782 &dev_attr_capability.attr,
783 NULL
784};
785
786static const struct attribute_group mesh_ie_group = {
787 .name = "mesh_ie",
788 .attrs = mesh_ie_attrs,
789};
790
791static void lbs_persist_config_init(struct net_device *dev)
792{
793 int ret;
794 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
795 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
796}
797
798static void lbs_persist_config_remove(struct net_device *dev)
799{
800 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
801 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
802}
803
804
805/***************************************************************************
806 * Initializing and starting, stopping mesh
807 */
808
809/*
810 * Check mesh FW version and appropriately send the mesh start
811 * command
812 */
813int lbs_init_mesh(struct lbs_private *priv)
814{
815 struct net_device *dev = priv->dev;
816 int ret = 0;
817
818 lbs_deb_enter(LBS_DEB_MESH);
819
3db4f989
DD
820 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
821 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
822 /* 5.110.22 have mesh command with 0xa3 command id */
823 /* 10.0.0.p0 FW brings in mesh config command with different id */
824 /* Check FW version MSB and initialize mesh_fw_ver */
825 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
826 /* Enable mesh, if supported, and work out which TLV it uses.
827 0x100 + 291 is an unofficial value used in 5.110.20.pXX
828 0x100 + 37 is the official value used in 5.110.21.pXX
829 but we check them in that order because 20.pXX doesn't
830 give an error -- it just silently fails. */
831
832 /* 5.110.20.pXX firmware will fail the command if the channel
833 doesn't match the existing channel. But only if the TLV
834 is correct. If the channel is wrong, _BOTH_ versions will
835 give an error to 0x100+291, and allow 0x100+37 to succeed.
836 It's just that 5.110.20.pXX will not have done anything
837 useful */
838
839 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
840 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
841 priv->channel)) {
842 priv->mesh_tlv = TLV_TYPE_MESH_ID;
843 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
844 priv->channel))
845 priv->mesh_tlv = 0;
846 }
847 } else
848 if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
849 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
850 /* 10.0.0.pXX new firmwares should succeed with TLV
851 * 0x100+37; Do not invoke command with old TLV.
852 */
853 priv->mesh_tlv = TLV_TYPE_MESH_ID;
854 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
855 priv->channel))
856 priv->mesh_tlv = 0;
857 }
858
d9319986
DD
859 /* Stop meshing until interface is brought up */
860 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
3db4f989
DD
861
862 if (priv->mesh_tlv) {
863 sprintf(priv->mesh_ssid, "mesh");
864 priv->mesh_ssid_len = 4;
865
866 lbs_add_mesh(priv);
867
868 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
869 netdev_err(dev, "cannot register lbs_mesh attribute\n");
870
871 ret = 1;
872 }
873
874 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
875 return ret;
876}
877
878
879int lbs_deinit_mesh(struct lbs_private *priv)
880{
881 struct net_device *dev = priv->dev;
882 int ret = 0;
15dbaac0 883
3db4f989 884 lbs_deb_enter(LBS_DEB_MESH);
15dbaac0 885
3db4f989
DD
886 if (priv->mesh_tlv) {
887 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
888 ret = 1;
889 }
15dbaac0 890
3db4f989
DD
891 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
892 return ret;
15dbaac0
JC
893}
894
3db4f989 895
15dbaac0 896/**
3db4f989
DD
897 * lbs_mesh_stop - close the mshX interface
898 *
899 * @dev: A pointer to &net_device structure
900 * returns: 0
15dbaac0 901 */
3db4f989 902static int lbs_mesh_stop(struct net_device *dev)
15dbaac0 903{
3db4f989 904 struct lbs_private *priv = dev->ml_priv;
15dbaac0 905
3db4f989 906 lbs_deb_enter(LBS_DEB_MESH);
d9319986 907 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
15dbaac0 908
d9319986 909 spin_lock_irq(&priv->driver_lock);
15dbaac0 910
3db4f989
DD
911 netif_stop_queue(dev);
912 netif_carrier_off(dev);
15dbaac0 913
3db4f989 914 spin_unlock_irq(&priv->driver_lock);
15dbaac0 915
3db4f989 916 schedule_work(&priv->mcast_work);
15dbaac0 917
3db4f989
DD
918 lbs_deb_leave(LBS_DEB_MESH);
919 return 0;
15dbaac0
JC
920}
921
922/**
3db4f989
DD
923 * lbs_mesh_dev_open - open the mshX interface
924 *
925 * @dev: A pointer to &net_device structure
926 * returns: 0 or -EBUSY if monitor mode active
15dbaac0 927 */
3db4f989 928static int lbs_mesh_dev_open(struct net_device *dev)
15dbaac0 929{
3db4f989
DD
930 struct lbs_private *priv = dev->ml_priv;
931 int ret = 0;
15dbaac0 932
3db4f989 933 lbs_deb_enter(LBS_DEB_NET);
15dbaac0 934
3db4f989 935 spin_lock_irq(&priv->driver_lock);
15dbaac0 936
3db4f989
DD
937 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
938 ret = -EBUSY;
d9319986 939 spin_unlock_irq(&priv->driver_lock);
3db4f989
DD
940 goto out;
941 }
942
3db4f989
DD
943 netif_carrier_on(dev);
944
945 if (!priv->tx_pending_len)
946 netif_wake_queue(dev);
3db4f989
DD
947
948 spin_unlock_irq(&priv->driver_lock);
d9319986
DD
949
950 ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel);
951
952out:
3db4f989
DD
953 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
954 return ret;
15dbaac0
JC
955}
956
3db4f989
DD
957static const struct net_device_ops mesh_netdev_ops = {
958 .ndo_open = lbs_mesh_dev_open,
959 .ndo_stop = lbs_mesh_stop,
960 .ndo_start_xmit = lbs_hard_start_xmit,
961 .ndo_set_mac_address = lbs_set_mac_address,
afc4b13d 962 .ndo_set_rx_mode = lbs_set_multicast_list,
3db4f989
DD
963};
964
15dbaac0 965/**
3db4f989
DD
966 * lbs_add_mesh - add mshX interface
967 *
968 * @priv: A pointer to the &struct lbs_private structure
969 * returns: 0 if successful, -X otherwise
15dbaac0 970 */
3db4f989 971static int lbs_add_mesh(struct lbs_private *priv)
15dbaac0 972{
3db4f989
DD
973 struct net_device *mesh_dev = NULL;
974 int ret = 0;
15dbaac0 975
3db4f989 976 lbs_deb_enter(LBS_DEB_MESH);
15dbaac0 977
3db4f989
DD
978 /* Allocate a virtual mesh device */
979 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
980 if (!mesh_dev) {
981 lbs_deb_mesh("init mshX device failed\n");
982 ret = -ENOMEM;
983 goto done;
984 }
985 mesh_dev->ml_priv = priv;
986 priv->mesh_dev = mesh_dev;
15dbaac0 987
3db4f989
DD
988 mesh_dev->netdev_ops = &mesh_netdev_ops;
989 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
990 memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
15dbaac0 991
3db4f989 992 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
15dbaac0 993
3db4f989
DD
994 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
995 /* Register virtual mesh interface */
996 ret = register_netdev(mesh_dev);
997 if (ret) {
998 pr_err("cannot register mshX virtual interface\n");
999 goto err_free;
1000 }
1001
1002 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
15dbaac0 1003 if (ret)
3db4f989 1004 goto err_unregister;
15dbaac0 1005
3db4f989 1006 lbs_persist_config_init(mesh_dev);
15dbaac0 1007
3db4f989
DD
1008 /* Everything successful */
1009 ret = 0;
1010 goto done;
15dbaac0 1011
3db4f989
DD
1012err_unregister:
1013 unregister_netdev(mesh_dev);
15dbaac0 1014
3db4f989
DD
1015err_free:
1016 free_netdev(mesh_dev);
15dbaac0 1017
3db4f989
DD
1018done:
1019 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
1020 return ret;
1021}
15dbaac0 1022
3db4f989
DD
1023void lbs_remove_mesh(struct lbs_private *priv)
1024{
1025 struct net_device *mesh_dev;
15dbaac0 1026
3db4f989
DD
1027 mesh_dev = priv->mesh_dev;
1028 if (!mesh_dev)
1029 return;
15dbaac0 1030
3db4f989
DD
1031 lbs_deb_enter(LBS_DEB_MESH);
1032 netif_stop_queue(mesh_dev);
1033 netif_carrier_off(mesh_dev);
1034 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1035 lbs_persist_config_remove(mesh_dev);
1036 unregister_netdev(mesh_dev);
1037 priv->mesh_dev = NULL;
1038 free_netdev(mesh_dev);
1039 lbs_deb_leave(LBS_DEB_MESH);
15dbaac0
JC
1040}
1041
3db4f989
DD
1042
1043/***************************************************************************
1044 * Sending and receiving
1045 */
1046struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1047 struct net_device *dev, struct rxpd *rxpd)
15dbaac0 1048{
3db4f989
DD
1049 if (priv->mesh_dev) {
1050 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1051 if (rxpd->rx_control & RxPD_MESH_FRAME)
1052 dev = priv->mesh_dev;
1053 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1054 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1055 dev = priv->mesh_dev;
1056 }
1057 }
1058 return dev;
15dbaac0 1059}
c7fe64cf
HS
1060
1061
3db4f989
DD
1062void lbs_mesh_set_txpd(struct lbs_private *priv,
1063 struct net_device *dev, struct txpd *txpd)
1064{
1065 if (dev == priv->mesh_dev) {
1066 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1067 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1068 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1069 txpd->u.bss.bss_num = MESH_IFACE_ID;
1070 }
1071}
1072
c7fe64cf
HS
1073
1074/***************************************************************************
1075 * Ethtool related
1076 */
1077
3db4f989 1078static const char * const mesh_stat_strings[] = {
c7fe64cf
HS
1079 "drop_duplicate_bcast",
1080 "drop_ttl_zero",
1081 "drop_no_fwd_route",
1082 "drop_no_buffers",
1083 "fwded_unicast_cnt",
1084 "fwded_bcast_cnt",
1085 "drop_blind_table",
1086 "tx_failed_cnt"
1087};
1088
1089void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1090 struct ethtool_stats *stats, uint64_t *data)
1091{
1092 struct lbs_private *priv = dev->ml_priv;
1093 struct cmd_ds_mesh_access mesh_access;
1094 int ret;
1095
1096 lbs_deb_enter(LBS_DEB_ETHTOOL);
1097
1098 /* Get Mesh Statistics */
1099 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1100
1101 if (ret) {
1102 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1103 return;
1104 }
1105
1106 priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1107 priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1108 priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1109 priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1110 priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1111 priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1112 priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1113 priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1114
1115 data[0] = priv->mstats.fwd_drop_rbt;
1116 data[1] = priv->mstats.fwd_drop_ttl;
1117 data[2] = priv->mstats.fwd_drop_noroute;
1118 data[3] = priv->mstats.fwd_drop_nobuf;
1119 data[4] = priv->mstats.fwd_unicast_cnt;
1120 data[5] = priv->mstats.fwd_bcast_cnt;
1121 data[6] = priv->mstats.drop_blind;
1122 data[7] = priv->mstats.tx_failed_cnt;
1123
1124 lbs_deb_enter(LBS_DEB_ETHTOOL);
1125}
1126
1127int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1128{
1129 struct lbs_private *priv = dev->ml_priv;
1130
1131 if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1132 return MESH_STATS_NUM;
1133
1134 return -EOPNOTSUPP;
1135}
1136
1137void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1138 uint32_t stringset, uint8_t *s)
1139{
1140 int i;
1141
1142 lbs_deb_enter(LBS_DEB_ETHTOOL);
1143
1144 switch (stringset) {
1145 case ETH_SS_STATS:
1146 for (i = 0; i < MESH_STATS_NUM; i++) {
1147 memcpy(s + i * ETH_GSTRING_LEN,
1148 mesh_stat_strings[i],
1149 ETH_GSTRING_LEN);
1150 }
1151 break;
1152 }
1153 lbs_deb_enter(LBS_DEB_ETHTOOL);
1154}
This page took 1.730847 seconds and 5 git commands to generate.