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>
14 /***************************************************************************
19 * Attributes exported through sysfs
23 * @brief Get function for sysfs attribute anycast_mask
25 static ssize_t
lbs_anycast_get(struct device
*dev
,
26 struct device_attribute
*attr
, char * buf
)
28 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
29 struct cmd_ds_mesh_access mesh_access
;
32 memset(&mesh_access
, 0, sizeof(mesh_access
));
34 ret
= lbs_mesh_access(priv
, CMD_ACT_MESH_GET_ANYCAST
, &mesh_access
);
38 return snprintf(buf
, 12, "0x%X\n", le32_to_cpu(mesh_access
.data
[0]));
42 * @brief Set function for sysfs attribute anycast_mask
44 static ssize_t
lbs_anycast_set(struct device
*dev
,
45 struct device_attribute
*attr
, const char * buf
, size_t count
)
47 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
48 struct cmd_ds_mesh_access mesh_access
;
52 memset(&mesh_access
, 0, sizeof(mesh_access
));
53 sscanf(buf
, "%x", &datum
);
54 mesh_access
.data
[0] = cpu_to_le32(datum
);
56 ret
= lbs_mesh_access(priv
, CMD_ACT_MESH_SET_ANYCAST
, &mesh_access
);
64 * @brief Get function for sysfs attribute prb_rsp_limit
66 static ssize_t
lbs_prb_rsp_limit_get(struct device
*dev
,
67 struct device_attribute
*attr
, char *buf
)
69 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
70 struct cmd_ds_mesh_access mesh_access
;
74 memset(&mesh_access
, 0, sizeof(mesh_access
));
75 mesh_access
.data
[0] = cpu_to_le32(CMD_ACT_GET
);
77 ret
= lbs_mesh_access(priv
, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT
,
82 retry_limit
= le32_to_cpu(mesh_access
.data
[1]);
83 return snprintf(buf
, 10, "%d\n", retry_limit
);
87 * @brief Set function for sysfs attribute prb_rsp_limit
89 static ssize_t
lbs_prb_rsp_limit_set(struct device
*dev
,
90 struct device_attribute
*attr
, const char *buf
, size_t count
)
92 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
93 struct cmd_ds_mesh_access mesh_access
;
95 unsigned long retry_limit
;
97 memset(&mesh_access
, 0, sizeof(mesh_access
));
98 mesh_access
.data
[0] = cpu_to_le32(CMD_ACT_SET
);
100 if (!strict_strtoul(buf
, 10, &retry_limit
))
102 if (retry_limit
> 15)
105 mesh_access
.data
[1] = cpu_to_le32(retry_limit
);
107 ret
= lbs_mesh_access(priv
, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT
,
116 * Get function for sysfs attribute mesh
118 static ssize_t
lbs_mesh_get(struct device
*dev
,
119 struct device_attribute
*attr
, char * buf
)
121 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
122 return snprintf(buf
, 5, "0x%X\n", !!priv
->mesh_dev
);
126 * Set function for sysfs attribute mesh
128 static ssize_t
lbs_mesh_set(struct device
*dev
,
129 struct device_attribute
*attr
, const char * buf
, size_t count
)
131 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
133 int ret
, action
= CMD_ACT_MESH_CONFIG_STOP
;
135 sscanf(buf
, "%x", &enable
);
137 if (enable
== !!priv
->mesh_dev
)
140 action
= CMD_ACT_MESH_CONFIG_START
;
141 ret
= lbs_mesh_config(priv
, action
, priv
->channel
);
148 lbs_remove_mesh(priv
);
154 * lbs_mesh attribute to be exported per ethX interface
155 * through sysfs (/sys/class/net/ethX/lbs_mesh)
157 static DEVICE_ATTR(lbs_mesh
, 0644, lbs_mesh_get
, lbs_mesh_set
);
160 * anycast_mask attribute to be exported per mshX interface
161 * through sysfs (/sys/class/net/mshX/anycast_mask)
163 static DEVICE_ATTR(anycast_mask
, 0644, lbs_anycast_get
, lbs_anycast_set
);
166 * prb_rsp_limit attribute to be exported per mshX interface
167 * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
169 static DEVICE_ATTR(prb_rsp_limit
, 0644, lbs_prb_rsp_limit_get
,
170 lbs_prb_rsp_limit_set
);
172 static struct attribute
*lbs_mesh_sysfs_entries
[] = {
173 &dev_attr_anycast_mask
.attr
,
174 &dev_attr_prb_rsp_limit
.attr
,
178 static struct attribute_group lbs_mesh_attr_group
= {
179 .attrs
= lbs_mesh_sysfs_entries
,
184 /***************************************************************************
185 * Initializing and starting, stopping mesh
189 * Check mesh FW version and appropriately send the mesh start
192 int lbs_init_mesh(struct lbs_private
*priv
)
194 struct net_device
*dev
= priv
->dev
;
197 lbs_deb_enter(LBS_DEB_MESH
);
199 if (priv
->mesh_fw_ver
== MESH_FW_OLD
) {
200 /* Enable mesh, if supported, and work out which TLV it uses.
201 0x100 + 291 is an unofficial value used in 5.110.20.pXX
202 0x100 + 37 is the official value used in 5.110.21.pXX
203 but we check them in that order because 20.pXX doesn't
204 give an error -- it just silently fails. */
206 /* 5.110.20.pXX firmware will fail the command if the channel
207 doesn't match the existing channel. But only if the TLV
208 is correct. If the channel is wrong, _BOTH_ versions will
209 give an error to 0x100+291, and allow 0x100+37 to succeed.
210 It's just that 5.110.20.pXX will not have done anything
213 priv
->mesh_tlv
= TLV_TYPE_OLD_MESH_ID
;
214 if (lbs_mesh_config(priv
, CMD_ACT_MESH_CONFIG_START
,
216 priv
->mesh_tlv
= TLV_TYPE_MESH_ID
;
217 if (lbs_mesh_config(priv
, CMD_ACT_MESH_CONFIG_START
,
221 } else if (priv
->mesh_fw_ver
== MESH_FW_NEW
) {
222 /* 10.0.0.pXX new firmwares should succeed with TLV
223 * 0x100+37; Do not invoke command with old TLV.
225 priv
->mesh_tlv
= TLV_TYPE_MESH_ID
;
226 if (lbs_mesh_config(priv
, CMD_ACT_MESH_CONFIG_START
,
230 if (priv
->mesh_tlv
) {
233 if (device_create_file(&dev
->dev
, &dev_attr_lbs_mesh
))
234 lbs_pr_err("cannot register lbs_mesh attribute\n");
239 lbs_deb_leave_args(LBS_DEB_MESH
, "ret %d", ret
);
244 int lbs_deinit_mesh(struct lbs_private
*priv
)
246 struct net_device
*dev
= priv
->dev
;
249 lbs_deb_enter(LBS_DEB_MESH
);
251 if (priv
->mesh_tlv
) {
252 device_remove_file(&dev
->dev
, &dev_attr_lbs_mesh
);
256 lbs_deb_leave_args(LBS_DEB_MESH
, "ret %d", ret
);
262 * @brief This function closes the mshX interface
264 * @param dev A pointer to net_device structure
267 static int lbs_mesh_stop(struct net_device
*dev
)
269 struct lbs_private
*priv
= dev
->ml_priv
;
271 lbs_deb_enter(LBS_DEB_MESH
);
272 spin_lock_irq(&priv
->driver_lock
);
275 priv
->mesh_connect_status
= LBS_DISCONNECTED
;
277 netif_stop_queue(dev
);
278 netif_carrier_off(dev
);
280 spin_unlock_irq(&priv
->driver_lock
);
282 schedule_work(&priv
->mcast_work
);
284 lbs_deb_leave(LBS_DEB_MESH
);
289 * @brief This function opens the mshX interface
291 * @param dev A pointer to net_device structure
292 * @return 0 or -EBUSY if monitor mode active
294 static int lbs_mesh_dev_open(struct net_device
*dev
)
296 struct lbs_private
*priv
= dev
->ml_priv
;
299 lbs_deb_enter(LBS_DEB_NET
);
301 spin_lock_irq(&priv
->driver_lock
);
303 if (priv
->monitormode
) {
309 priv
->mesh_connect_status
= LBS_CONNECTED
;
310 netif_carrier_on(dev
);
312 if (!priv
->tx_pending_len
)
313 netif_wake_queue(dev
);
316 spin_unlock_irq(&priv
->driver_lock
);
317 lbs_deb_leave_args(LBS_DEB_NET
, "ret %d", ret
);
321 static const struct net_device_ops mesh_netdev_ops
= {
322 .ndo_open
= lbs_mesh_dev_open
,
323 .ndo_stop
= lbs_mesh_stop
,
324 .ndo_start_xmit
= lbs_hard_start_xmit
,
325 .ndo_set_mac_address
= lbs_set_mac_address
,
326 .ndo_set_multicast_list
= lbs_set_multicast_list
,
330 * @brief This function adds mshX interface
332 * @param priv A pointer to the struct lbs_private structure
333 * @return 0 if successful, -X otherwise
335 int lbs_add_mesh(struct lbs_private
*priv
)
337 struct net_device
*mesh_dev
= NULL
;
340 lbs_deb_enter(LBS_DEB_MESH
);
342 /* Allocate a virtual mesh device */
343 mesh_dev
= alloc_netdev(0, "msh%d", ether_setup
);
345 lbs_deb_mesh("init mshX device failed\n");
349 mesh_dev
->ml_priv
= priv
;
350 priv
->mesh_dev
= mesh_dev
;
352 mesh_dev
->netdev_ops
= &mesh_netdev_ops
;
353 mesh_dev
->ethtool_ops
= &lbs_ethtool_ops
;
354 memcpy(mesh_dev
->dev_addr
, priv
->dev
->dev_addr
,
355 sizeof(priv
->dev
->dev_addr
));
357 SET_NETDEV_DEV(priv
->mesh_dev
, priv
->dev
->dev
.parent
);
360 mesh_dev
->wireless_handlers
= &mesh_handler_def
;
362 mesh_dev
->flags
|= IFF_BROADCAST
| IFF_MULTICAST
;
363 /* Register virtual mesh interface */
364 ret
= register_netdev(mesh_dev
);
366 lbs_pr_err("cannot register mshX virtual interface\n");
370 ret
= sysfs_create_group(&(mesh_dev
->dev
.kobj
), &lbs_mesh_attr_group
);
374 lbs_persist_config_init(mesh_dev
);
376 /* Everything successful */
381 unregister_netdev(mesh_dev
);
384 free_netdev(mesh_dev
);
387 lbs_deb_leave_args(LBS_DEB_MESH
, "ret %d", ret
);
391 void lbs_remove_mesh(struct lbs_private
*priv
)
393 struct net_device
*mesh_dev
;
395 mesh_dev
= priv
->mesh_dev
;
399 lbs_deb_enter(LBS_DEB_MESH
);
400 netif_stop_queue(mesh_dev
);
401 netif_carrier_off(mesh_dev
);
402 sysfs_remove_group(&(mesh_dev
->dev
.kobj
), &lbs_mesh_attr_group
);
403 lbs_persist_config_remove(mesh_dev
);
404 unregister_netdev(mesh_dev
);
405 priv
->mesh_dev
= NULL
;
406 free_netdev(mesh_dev
);
407 lbs_deb_leave(LBS_DEB_MESH
);
412 /***************************************************************************
413 * Sending and receiving
415 struct net_device
*lbs_mesh_set_dev(struct lbs_private
*priv
,
416 struct net_device
*dev
, struct rxpd
*rxpd
)
418 if (priv
->mesh_dev
) {
419 if (priv
->mesh_fw_ver
== MESH_FW_OLD
) {
420 if (rxpd
->rx_control
& RxPD_MESH_FRAME
)
421 dev
= priv
->mesh_dev
;
422 } else if (priv
->mesh_fw_ver
== MESH_FW_NEW
) {
423 if (rxpd
->u
.bss
.bss_num
== MESH_IFACE_ID
)
424 dev
= priv
->mesh_dev
;
431 void lbs_mesh_set_txpd(struct lbs_private
*priv
,
432 struct net_device
*dev
, struct txpd
*txpd
)
434 if (dev
== priv
->mesh_dev
) {
435 if (priv
->mesh_fw_ver
== MESH_FW_OLD
)
436 txpd
->tx_control
|= cpu_to_le32(TxPD_MESH_FRAME
);
437 else if (priv
->mesh_fw_ver
== MESH_FW_NEW
)
438 txpd
->u
.bss
.bss_num
= MESH_IFACE_ID
;
443 /***************************************************************************
444 * Persistent configuration support
447 static int mesh_get_default_parameters(struct device
*dev
,
448 struct mrvl_mesh_defaults
*defs
)
450 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
451 struct cmd_ds_mesh_config cmd
;
454 memset(&cmd
, 0, sizeof(struct cmd_ds_mesh_config
));
455 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_GET
,
456 CMD_TYPE_MESH_GET_DEFAULTS
);
461 memcpy(defs
, &cmd
.data
[0], sizeof(struct mrvl_mesh_defaults
));
467 * @brief Get function for sysfs attribute bootflag
469 static ssize_t
bootflag_get(struct device
*dev
,
470 struct device_attribute
*attr
, char *buf
)
472 struct mrvl_mesh_defaults defs
;
475 ret
= mesh_get_default_parameters(dev
, &defs
);
480 return snprintf(buf
, 12, "%d\n", le32_to_cpu(defs
.bootflag
));
484 * @brief Set function for sysfs attribute bootflag
486 static ssize_t
bootflag_set(struct device
*dev
, struct device_attribute
*attr
,
487 const char *buf
, size_t count
)
489 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
490 struct cmd_ds_mesh_config cmd
;
494 memset(&cmd
, 0, sizeof(cmd
));
495 ret
= sscanf(buf
, "%d", &datum
);
496 if ((ret
!= 1) || (datum
> 1))
499 *((__le32
*)&cmd
.data
[0]) = cpu_to_le32(!!datum
);
500 cmd
.length
= cpu_to_le16(sizeof(uint32_t));
501 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_SET
,
502 CMD_TYPE_MESH_SET_BOOTFLAG
);
510 * @brief Get function for sysfs attribute boottime
512 static ssize_t
boottime_get(struct device
*dev
,
513 struct device_attribute
*attr
, char *buf
)
515 struct mrvl_mesh_defaults defs
;
518 ret
= mesh_get_default_parameters(dev
, &defs
);
523 return snprintf(buf
, 12, "%d\n", defs
.boottime
);
527 * @brief Set function for sysfs attribute boottime
529 static ssize_t
boottime_set(struct device
*dev
,
530 struct device_attribute
*attr
, const char *buf
, size_t count
)
532 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
533 struct cmd_ds_mesh_config cmd
;
537 memset(&cmd
, 0, sizeof(cmd
));
538 ret
= sscanf(buf
, "%d", &datum
);
539 if ((ret
!= 1) || (datum
> 255))
542 /* A too small boot time will result in the device booting into
543 * standalone (no-host) mode before the host can take control of it,
544 * so the change will be hard to revert. This may be a desired
545 * feature (e.g to configure a very fast boot time for devices that
546 * will not be attached to a host), but dangerous. So I'm enforcing a
547 * lower limit of 20 seconds: remove and recompile the driver if this
548 * does not work for you.
550 datum
= (datum
< 20) ? 20 : datum
;
552 cmd
.length
= cpu_to_le16(sizeof(uint8_t));
553 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_SET
,
554 CMD_TYPE_MESH_SET_BOOTTIME
);
562 * @brief Get function for sysfs attribute channel
564 static ssize_t
channel_get(struct device
*dev
,
565 struct device_attribute
*attr
, char *buf
)
567 struct mrvl_mesh_defaults defs
;
570 ret
= mesh_get_default_parameters(dev
, &defs
);
575 return snprintf(buf
, 12, "%d\n", le16_to_cpu(defs
.channel
));
579 * @brief Set function for sysfs attribute channel
581 static ssize_t
channel_set(struct device
*dev
, struct device_attribute
*attr
,
582 const char *buf
, size_t count
)
584 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
585 struct cmd_ds_mesh_config cmd
;
589 memset(&cmd
, 0, sizeof(cmd
));
590 ret
= sscanf(buf
, "%d", &datum
);
591 if (ret
!= 1 || datum
< 1 || datum
> 11)
594 *((__le16
*)&cmd
.data
[0]) = cpu_to_le16(datum
);
595 cmd
.length
= cpu_to_le16(sizeof(uint16_t));
596 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_SET
,
597 CMD_TYPE_MESH_SET_DEF_CHANNEL
);
605 * @brief Get function for sysfs attribute mesh_id
607 static ssize_t
mesh_id_get(struct device
*dev
, struct device_attribute
*attr
,
610 struct mrvl_mesh_defaults defs
;
614 ret
= mesh_get_default_parameters(dev
, &defs
);
619 if (defs
.meshie
.val
.mesh_id_len
> IEEE80211_MAX_SSID_LEN
) {
620 lbs_pr_err("inconsistent mesh ID length");
621 defs
.meshie
.val
.mesh_id_len
= IEEE80211_MAX_SSID_LEN
;
624 /* SSID not null terminated: reserve room for \0 + \n */
625 maxlen
= defs
.meshie
.val
.mesh_id_len
+ 2;
626 maxlen
= (PAGE_SIZE
> maxlen
) ? maxlen
: PAGE_SIZE
;
628 defs
.meshie
.val
.mesh_id
[defs
.meshie
.val
.mesh_id_len
] = '\0';
630 return snprintf(buf
, maxlen
, "%s\n", defs
.meshie
.val
.mesh_id
);
634 * @brief Set function for sysfs attribute mesh_id
636 static ssize_t
mesh_id_set(struct device
*dev
, struct device_attribute
*attr
,
637 const char *buf
, size_t count
)
639 struct cmd_ds_mesh_config cmd
;
640 struct mrvl_mesh_defaults defs
;
641 struct mrvl_meshie
*ie
;
642 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
646 if (count
< 2 || count
> IEEE80211_MAX_SSID_LEN
+ 1)
649 memset(&cmd
, 0, sizeof(struct cmd_ds_mesh_config
));
650 ie
= (struct mrvl_meshie
*) &cmd
.data
[0];
652 /* fetch all other Information Element parameters */
653 ret
= mesh_get_default_parameters(dev
, &defs
);
655 cmd
.length
= cpu_to_le16(sizeof(struct mrvl_meshie
));
657 /* transfer IE elements */
658 memcpy(ie
, &defs
.meshie
, sizeof(struct mrvl_meshie
));
661 memcpy(ie
->val
.mesh_id
, buf
, len
);
663 ie
->val
.mesh_id_len
= len
;
665 ie
->len
= sizeof(struct mrvl_meshie_val
) - IEEE80211_MAX_SSID_LEN
+ len
;
667 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_SET
,
668 CMD_TYPE_MESH_SET_MESH_IE
);
676 * @brief Get function for sysfs attribute protocol_id
678 static ssize_t
protocol_id_get(struct device
*dev
,
679 struct device_attribute
*attr
, char *buf
)
681 struct mrvl_mesh_defaults defs
;
684 ret
= mesh_get_default_parameters(dev
, &defs
);
689 return snprintf(buf
, 5, "%d\n", defs
.meshie
.val
.active_protocol_id
);
693 * @brief Set function for sysfs attribute protocol_id
695 static ssize_t
protocol_id_set(struct device
*dev
,
696 struct device_attribute
*attr
, const char *buf
, size_t count
)
698 struct cmd_ds_mesh_config cmd
;
699 struct mrvl_mesh_defaults defs
;
700 struct mrvl_meshie
*ie
;
701 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
705 memset(&cmd
, 0, sizeof(cmd
));
706 ret
= sscanf(buf
, "%d", &datum
);
707 if ((ret
!= 1) || (datum
> 255))
710 /* fetch all other Information Element parameters */
711 ret
= mesh_get_default_parameters(dev
, &defs
);
713 cmd
.length
= cpu_to_le16(sizeof(struct mrvl_meshie
));
715 /* transfer IE elements */
716 ie
= (struct mrvl_meshie
*) &cmd
.data
[0];
717 memcpy(ie
, &defs
.meshie
, sizeof(struct mrvl_meshie
));
718 /* update protocol id */
719 ie
->val
.active_protocol_id
= datum
;
721 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_SET
,
722 CMD_TYPE_MESH_SET_MESH_IE
);
730 * @brief Get function for sysfs attribute metric_id
732 static ssize_t
metric_id_get(struct device
*dev
,
733 struct device_attribute
*attr
, char *buf
)
735 struct mrvl_mesh_defaults defs
;
738 ret
= mesh_get_default_parameters(dev
, &defs
);
743 return snprintf(buf
, 5, "%d\n", defs
.meshie
.val
.active_metric_id
);
747 * @brief Set function for sysfs attribute metric_id
749 static ssize_t
metric_id_set(struct device
*dev
, struct device_attribute
*attr
,
750 const char *buf
, size_t count
)
752 struct cmd_ds_mesh_config cmd
;
753 struct mrvl_mesh_defaults defs
;
754 struct mrvl_meshie
*ie
;
755 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
759 memset(&cmd
, 0, sizeof(cmd
));
760 ret
= sscanf(buf
, "%d", &datum
);
761 if ((ret
!= 1) || (datum
> 255))
764 /* fetch all other Information Element parameters */
765 ret
= mesh_get_default_parameters(dev
, &defs
);
767 cmd
.length
= cpu_to_le16(sizeof(struct mrvl_meshie
));
769 /* transfer IE elements */
770 ie
= (struct mrvl_meshie
*) &cmd
.data
[0];
771 memcpy(ie
, &defs
.meshie
, sizeof(struct mrvl_meshie
));
772 /* update metric id */
773 ie
->val
.active_metric_id
= datum
;
775 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_SET
,
776 CMD_TYPE_MESH_SET_MESH_IE
);
784 * @brief Get function for sysfs attribute capability
786 static ssize_t
capability_get(struct device
*dev
,
787 struct device_attribute
*attr
, char *buf
)
789 struct mrvl_mesh_defaults defs
;
792 ret
= mesh_get_default_parameters(dev
, &defs
);
797 return snprintf(buf
, 5, "%d\n", defs
.meshie
.val
.mesh_capability
);
801 * @brief Set function for sysfs attribute capability
803 static ssize_t
capability_set(struct device
*dev
, struct device_attribute
*attr
,
804 const char *buf
, size_t count
)
806 struct cmd_ds_mesh_config cmd
;
807 struct mrvl_mesh_defaults defs
;
808 struct mrvl_meshie
*ie
;
809 struct lbs_private
*priv
= to_net_dev(dev
)->ml_priv
;
813 memset(&cmd
, 0, sizeof(cmd
));
814 ret
= sscanf(buf
, "%d", &datum
);
815 if ((ret
!= 1) || (datum
> 255))
818 /* fetch all other Information Element parameters */
819 ret
= mesh_get_default_parameters(dev
, &defs
);
821 cmd
.length
= cpu_to_le16(sizeof(struct mrvl_meshie
));
823 /* transfer IE elements */
824 ie
= (struct mrvl_meshie
*) &cmd
.data
[0];
825 memcpy(ie
, &defs
.meshie
, sizeof(struct mrvl_meshie
));
827 ie
->val
.mesh_capability
= datum
;
829 ret
= lbs_mesh_config_send(priv
, &cmd
, CMD_ACT_MESH_CONFIG_SET
,
830 CMD_TYPE_MESH_SET_MESH_IE
);
838 static DEVICE_ATTR(bootflag
, 0644, bootflag_get
, bootflag_set
);
839 static DEVICE_ATTR(boottime
, 0644, boottime_get
, boottime_set
);
840 static DEVICE_ATTR(channel
, 0644, channel_get
, channel_set
);
841 static DEVICE_ATTR(mesh_id
, 0644, mesh_id_get
, mesh_id_set
);
842 static DEVICE_ATTR(protocol_id
, 0644, protocol_id_get
, protocol_id_set
);
843 static DEVICE_ATTR(metric_id
, 0644, metric_id_get
, metric_id_set
);
844 static DEVICE_ATTR(capability
, 0644, capability_get
, capability_set
);
846 static struct attribute
*boot_opts_attrs
[] = {
847 &dev_attr_bootflag
.attr
,
848 &dev_attr_boottime
.attr
,
849 &dev_attr_channel
.attr
,
853 static struct attribute_group boot_opts_group
= {
854 .name
= "boot_options",
855 .attrs
= boot_opts_attrs
,
858 static struct attribute
*mesh_ie_attrs
[] = {
859 &dev_attr_mesh_id
.attr
,
860 &dev_attr_protocol_id
.attr
,
861 &dev_attr_metric_id
.attr
,
862 &dev_attr_capability
.attr
,
866 static struct attribute_group mesh_ie_group
= {
868 .attrs
= mesh_ie_attrs
,
871 void lbs_persist_config_init(struct net_device
*dev
)
874 ret
= sysfs_create_group(&(dev
->dev
.kobj
), &boot_opts_group
);
875 ret
= sysfs_create_group(&(dev
->dev
.kobj
), &mesh_ie_group
);
878 void lbs_persist_config_remove(struct net_device
*dev
)
880 sysfs_remove_group(&(dev
->dev
.kobj
), &boot_opts_group
);
881 sysfs_remove_group(&(dev
->dev
.kobj
), &mesh_ie_group
);