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