~ubuntu-branches/ubuntu/natty/linux-backports-modules-2.6.38/natty-updates

« back to all changes in this revision

Viewing changes to updates/cw-2.6.39/drivers/net/wireless/libertas/mesh.c

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner, Tim Gardner
  • Date: 2011-06-08 10:44:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110608104409-fnl8carkdo15bwsz
Tags: 2.6.38-10.6
[ Tim Gardner ]

Shorten compat-wireless package name to cw to accomodate
CDROM file name length restrictions.

Show diffs side-by-side

added added

removed removed

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