aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2011-07-22 17:51:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-22 17:51:16 -0400
commit41bf37117b47fc5ce2aae91f6a108e7e42e0b046 (patch)
treed5c8f24075313edfe548256dd931527f1569921e /drivers/net/wireless/libertas
parent415b3334a21aa67806c52d1acf4e72e14f7f402f (diff)
parent6e6e8c510a84fe3237ef02b954e58cca6a3f4b1a (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/dev.h2
-rw-r--r--drivers/net/wireless/libertas/main.c2
-rw-r--r--drivers/net/wireless/libertas/mesh.c972
-rw-r--r--drivers/net/wireless/libertas/mesh.h31
-rw-r--r--drivers/net/wireless/libertas/tx.c2
5 files changed, 391 insertions, 618 deletions
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 76d018beebf4..adb3490e3cf5 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -44,9 +44,7 @@ struct lbs_private {
44 /* Mesh */ 44 /* Mesh */
45 struct net_device *mesh_dev; /* Virtual device */ 45 struct net_device *mesh_dev; /* Virtual device */
46#ifdef CONFIG_LIBERTAS_MESH 46#ifdef CONFIG_LIBERTAS_MESH
47 u32 mesh_connect_status;
48 struct lbs_mesh_stats mstats; 47 struct lbs_mesh_stats mstats;
49 int mesh_open;
50 uint16_t mesh_tlv; 48 uint16_t mesh_tlv;
51 u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; 49 u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
52 u8 mesh_ssid_len; 50 u8 mesh_ssid_len;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index c79aac4b1dae..94652c5a25de 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -512,7 +512,7 @@ static int lbs_thread(void *data)
512 if (priv->connect_status == LBS_CONNECTED) 512 if (priv->connect_status == LBS_CONNECTED)
513 netif_wake_queue(priv->dev); 513 netif_wake_queue(priv->dev);
514 if (priv->mesh_dev && 514 if (priv->mesh_dev &&
515 lbs_mesh_connected(priv)) 515 netif_running(priv->mesh_dev))
516 netif_wake_queue(priv->mesh_dev); 516 netif_wake_queue(priv->mesh_dev);
517 } 517 }
518 } 518 }
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 7969d104189d..be72c08ea2a7 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -15,6 +15,121 @@
15#include "cmd.h" 15#include "cmd.h"
16 16
17 17
18static int lbs_add_mesh(struct lbs_private *priv);
19
20/***************************************************************************
21 * Mesh command handling
22 */
23
24static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
25 struct cmd_ds_mesh_access *cmd)
26{
27 int ret;
28
29 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
30
31 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
32 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
33 cmd->hdr.result = 0;
34
35 cmd->action = cpu_to_le16(cmd_action);
36
37 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
38
39 lbs_deb_leave(LBS_DEB_CMD);
40 return ret;
41}
42
43static int __lbs_mesh_config_send(struct lbs_private *priv,
44 struct cmd_ds_mesh_config *cmd,
45 uint16_t action, uint16_t type)
46{
47 int ret;
48 u16 command = CMD_MESH_CONFIG_OLD;
49
50 lbs_deb_enter(LBS_DEB_CMD);
51
52 /*
53 * Command id is 0xac for v10 FW along with mesh interface
54 * id in bits 14-13-12.
55 */
56 if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
57 command = CMD_MESH_CONFIG |
58 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
59
60 cmd->hdr.command = cpu_to_le16(command);
61 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
62 cmd->hdr.result = 0;
63
64 cmd->type = cpu_to_le16(type);
65 cmd->action = cpu_to_le16(action);
66
67 ret = lbs_cmd_with_response(priv, command, cmd);
68
69 lbs_deb_leave(LBS_DEB_CMD);
70 return ret;
71}
72
73static int lbs_mesh_config_send(struct lbs_private *priv,
74 struct cmd_ds_mesh_config *cmd,
75 uint16_t action, uint16_t type)
76{
77 int ret;
78
79 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
80 return -EOPNOTSUPP;
81
82 ret = __lbs_mesh_config_send(priv, cmd, action, type);
83 return ret;
84}
85
86/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
87 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
88 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
89 * lbs_mesh_config_send.
90 */
91static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
92 uint16_t chan)
93{
94 struct cmd_ds_mesh_config cmd;
95 struct mrvl_meshie *ie;
96 DECLARE_SSID_BUF(ssid);
97
98 memset(&cmd, 0, sizeof(cmd));
99 cmd.channel = cpu_to_le16(chan);
100 ie = (struct mrvl_meshie *)cmd.data;
101
102 switch (action) {
103 case CMD_ACT_MESH_CONFIG_START:
104 ie->id = WLAN_EID_GENERIC;
105 ie->val.oui[0] = 0x00;
106 ie->val.oui[1] = 0x50;
107 ie->val.oui[2] = 0x43;
108 ie->val.type = MARVELL_MESH_IE_TYPE;
109 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
110 ie->val.version = MARVELL_MESH_IE_VERSION;
111 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
112 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
113 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
114 ie->val.mesh_id_len = priv->mesh_ssid_len;
115 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
116 ie->len = sizeof(struct mrvl_meshie_val) -
117 IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
118 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
119 break;
120 case CMD_ACT_MESH_CONFIG_STOP:
121 break;
122 default:
123 return -1;
124 }
125 lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
126 action, priv->mesh_tlv, chan,
127 print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
128
129 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
130}
131
132
18/*************************************************************************** 133/***************************************************************************
19 * Mesh sysfs support 134 * Mesh sysfs support
20 */ 135 */
@@ -155,17 +270,11 @@ static ssize_t lbs_mesh_set(struct device *dev,
155{ 270{
156 struct lbs_private *priv = to_net_dev(dev)->ml_priv; 271 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
157 int enable; 272 int enable;
158 int ret, action = CMD_ACT_MESH_CONFIG_STOP;
159 273
160 sscanf(buf, "%x", &enable); 274 sscanf(buf, "%x", &enable);
161 enable = !!enable; 275 enable = !!enable;
162 if (enable == !!priv->mesh_dev) 276 if (enable == !!priv->mesh_dev)
163 return count; 277 return count;
164 if (enable)
165 action = CMD_ACT_MESH_CONFIG_START;
166 ret = lbs_mesh_config(priv, action, priv->channel);
167 if (ret)
168 return ret;
169 278
170 if (enable) 279 if (enable)
171 lbs_add_mesh(priv); 280 lbs_add_mesh(priv);
@@ -200,582 +309,11 @@ static struct attribute *lbs_mesh_sysfs_entries[] = {
200 NULL, 309 NULL,
201}; 310};
202 311
203static struct attribute_group lbs_mesh_attr_group = { 312static const struct attribute_group lbs_mesh_attr_group = {
204 .attrs = lbs_mesh_sysfs_entries, 313 .attrs = lbs_mesh_sysfs_entries,
205}; 314};
206 315
207 316
208
209/***************************************************************************
210 * Initializing and starting, stopping mesh
211 */
212
213/*
214 * Check mesh FW version and appropriately send the mesh start
215 * command
216 */
217int lbs_init_mesh(struct lbs_private *priv)
218{
219 struct net_device *dev = priv->dev;
220 int ret = 0;
221
222 lbs_deb_enter(LBS_DEB_MESH);
223
224 priv->mesh_connect_status = LBS_DISCONNECTED;
225
226 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
227 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
228 /* 5.110.22 have mesh command with 0xa3 command id */
229 /* 10.0.0.p0 FW brings in mesh config command with different id */
230 /* Check FW version MSB and initialize mesh_fw_ver */
231 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
232 /* Enable mesh, if supported, and work out which TLV it uses.
233 0x100 + 291 is an unofficial value used in 5.110.20.pXX
234 0x100 + 37 is the official value used in 5.110.21.pXX
235 but we check them in that order because 20.pXX doesn't
236 give an error -- it just silently fails. */
237
238 /* 5.110.20.pXX firmware will fail the command if the channel
239 doesn't match the existing channel. But only if the TLV
240 is correct. If the channel is wrong, _BOTH_ versions will
241 give an error to 0x100+291, and allow 0x100+37 to succeed.
242 It's just that 5.110.20.pXX will not have done anything
243 useful */
244
245 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
246 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
247 priv->channel)) {
248 priv->mesh_tlv = TLV_TYPE_MESH_ID;
249 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
250 priv->channel))
251 priv->mesh_tlv = 0;
252 }
253 } else
254 if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
255 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
256 /* 10.0.0.pXX new firmwares should succeed with TLV
257 * 0x100+37; Do not invoke command with old TLV.
258 */
259 priv->mesh_tlv = TLV_TYPE_MESH_ID;
260 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
261 priv->channel))
262 priv->mesh_tlv = 0;
263 }
264
265
266 if (priv->mesh_tlv) {
267 sprintf(priv->mesh_ssid, "mesh");
268 priv->mesh_ssid_len = 4;
269
270 lbs_add_mesh(priv);
271
272 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
273 netdev_err(dev, "cannot register lbs_mesh attribute\n");
274
275 ret = 1;
276 }
277
278 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
279 return ret;
280}
281
282
283int lbs_deinit_mesh(struct lbs_private *priv)
284{
285 struct net_device *dev = priv->dev;
286 int ret = 0;
287
288 lbs_deb_enter(LBS_DEB_MESH);
289
290 if (priv->mesh_tlv) {
291 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
292 ret = 1;
293 }
294
295 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
296 return ret;
297}
298
299
300/**
301 * lbs_mesh_stop - close the mshX interface
302 *
303 * @dev: A pointer to &net_device structure
304 * returns: 0
305 */
306static int lbs_mesh_stop(struct net_device *dev)
307{
308 struct lbs_private *priv = dev->ml_priv;
309
310 lbs_deb_enter(LBS_DEB_MESH);
311 spin_lock_irq(&priv->driver_lock);
312
313 priv->mesh_open = 0;
314 priv->mesh_connect_status = LBS_DISCONNECTED;
315
316 netif_stop_queue(dev);
317 netif_carrier_off(dev);
318
319 spin_unlock_irq(&priv->driver_lock);
320
321 schedule_work(&priv->mcast_work);
322
323 lbs_deb_leave(LBS_DEB_MESH);
324 return 0;
325}
326
327/**
328 * lbs_mesh_dev_open - open the mshX interface
329 *
330 * @dev: A pointer to &net_device structure
331 * returns: 0 or -EBUSY if monitor mode active
332 */
333static int lbs_mesh_dev_open(struct net_device *dev)
334{
335 struct lbs_private *priv = dev->ml_priv;
336 int ret = 0;
337
338 lbs_deb_enter(LBS_DEB_NET);
339
340 spin_lock_irq(&priv->driver_lock);
341
342 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
343 ret = -EBUSY;
344 goto out;
345 }
346
347 priv->mesh_open = 1;
348 priv->mesh_connect_status = LBS_CONNECTED;
349 netif_carrier_on(dev);
350
351 if (!priv->tx_pending_len)
352 netif_wake_queue(dev);
353 out:
354
355 spin_unlock_irq(&priv->driver_lock);
356 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
357 return ret;
358}
359
360static const struct net_device_ops mesh_netdev_ops = {
361 .ndo_open = lbs_mesh_dev_open,
362 .ndo_stop = lbs_mesh_stop,
363 .ndo_start_xmit = lbs_hard_start_xmit,
364 .ndo_set_mac_address = lbs_set_mac_address,
365 .ndo_set_multicast_list = lbs_set_multicast_list,
366};
367
368/**
369 * lbs_add_mesh - add mshX interface
370 *
371 * @priv: A pointer to the &struct lbs_private structure
372 * returns: 0 if successful, -X otherwise
373 */
374int lbs_add_mesh(struct lbs_private *priv)
375{
376 struct net_device *mesh_dev = NULL;
377 int ret = 0;
378
379 lbs_deb_enter(LBS_DEB_MESH);
380
381 /* Allocate a virtual mesh device */
382 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
383 if (!mesh_dev) {
384 lbs_deb_mesh("init mshX device failed\n");
385 ret = -ENOMEM;
386 goto done;
387 }
388 mesh_dev->ml_priv = priv;
389 priv->mesh_dev = mesh_dev;
390
391 mesh_dev->netdev_ops = &mesh_netdev_ops;
392 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
393 memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
394
395 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
396
397 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
398 /* Register virtual mesh interface */
399 ret = register_netdev(mesh_dev);
400 if (ret) {
401 pr_err("cannot register mshX virtual interface\n");
402 goto err_free;
403 }
404
405 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
406 if (ret)
407 goto err_unregister;
408
409 lbs_persist_config_init(mesh_dev);
410
411 /* Everything successful */
412 ret = 0;
413 goto done;
414
415err_unregister:
416 unregister_netdev(mesh_dev);
417
418err_free:
419 free_netdev(mesh_dev);
420
421done:
422 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
423 return ret;
424}
425
426void lbs_remove_mesh(struct lbs_private *priv)
427{
428 struct net_device *mesh_dev;
429
430 mesh_dev = priv->mesh_dev;
431 if (!mesh_dev)
432 return;
433
434 lbs_deb_enter(LBS_DEB_MESH);
435 netif_stop_queue(mesh_dev);
436 netif_carrier_off(mesh_dev);
437 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
438 lbs_persist_config_remove(mesh_dev);
439 unregister_netdev(mesh_dev);
440 priv->mesh_dev = NULL;
441 free_netdev(mesh_dev);
442 lbs_deb_leave(LBS_DEB_MESH);
443}
444
445
446
447/***************************************************************************
448 * Sending and receiving
449 */
450struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
451 struct net_device *dev, struct rxpd *rxpd)
452{
453 if (priv->mesh_dev) {
454 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
455 if (rxpd->rx_control & RxPD_MESH_FRAME)
456 dev = priv->mesh_dev;
457 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
458 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
459 dev = priv->mesh_dev;
460 }
461 }
462 return dev;
463}
464
465
466void lbs_mesh_set_txpd(struct lbs_private *priv,
467 struct net_device *dev, struct txpd *txpd)
468{
469 if (dev == priv->mesh_dev) {
470 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
471 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
472 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
473 txpd->u.bss.bss_num = MESH_IFACE_ID;
474 }
475}
476
477
478/***************************************************************************
479 * Mesh command handling
480 */
481
482/**
483 * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries
484 *
485 * @priv: A pointer to &struct lbs_private structure
486 * @add: TRUE to add the entry, FALSE to delete it
487 * @addr1: Destination address to blind or unblind
488 *
489 * returns: 0 on success, error on failure
490 */
491int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
492{
493 struct cmd_ds_bt_access cmd;
494 int ret = 0;
495
496 lbs_deb_enter(LBS_DEB_CMD);
497
498 BUG_ON(addr1 == NULL);
499
500 memset(&cmd, 0, sizeof(cmd));
501 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
502 memcpy(cmd.addr1, addr1, ETH_ALEN);
503 if (add) {
504 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_ADD);
505 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
506 addr1, ETH_ALEN);
507 } else {
508 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_DEL);
509 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
510 addr1, ETH_ALEN);
511 }
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 * lbs_mesh_bt_reset - Reset/clear the mesh blinding table
521 *
522 * @priv: A pointer to &struct lbs_private structure
523 *
524 * returns: 0 on success, error on failure
525 */
526int lbs_mesh_bt_reset(struct lbs_private *priv)
527{
528 struct cmd_ds_bt_access cmd;
529 int ret = 0;
530
531 lbs_deb_enter(LBS_DEB_CMD);
532
533 memset(&cmd, 0, sizeof(cmd));
534 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
535 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_RESET);
536
537 ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
538
539 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
540 return ret;
541}
542
543/**
544 * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh
545 * blinding table
546 *
547 * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
548 * table, but an inverted table allows *only* traffic from nodes listed in
549 * the table.
550 *
551 * @priv: A pointer to &struct lbs_private structure
552 * @inverted: On success, TRUE if the blinding table is inverted,
553 * FALSE if it is not inverted
554 *
555 * returns: 0 on success, error on failure
556 */
557int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
558{
559 struct cmd_ds_bt_access cmd;
560 int ret = 0;
561
562 lbs_deb_enter(LBS_DEB_CMD);
563
564 BUG_ON(inverted == NULL);
565
566 memset(&cmd, 0, sizeof(cmd));
567 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
568 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_GET_INVERT);
569
570 ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
571 if (ret == 0)
572 *inverted = !!cmd.id;
573
574 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
575 return ret;
576}
577
578/**
579 * lbs_mesh_bt_set_inverted - Sets the inverted status of the mesh
580 * blinding table
581 *
582 * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
583 * table, but an inverted table allows *only* traffic from nodes listed in
584 * the table.
585 *
586 * @priv: A pointer to &struct lbs_private structure
587 * @inverted: TRUE to invert the blinding table (only traffic from
588 * listed nodes allowed), FALSE to return it
589 * to normal state (listed nodes ignored)
590 *
591 * returns: 0 on success, error on failure
592 */
593int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
594{
595 struct cmd_ds_bt_access cmd;
596 int ret = 0;
597
598 lbs_deb_enter(LBS_DEB_CMD);
599
600 memset(&cmd, 0, sizeof(cmd));
601 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
602 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
603 cmd.id = cpu_to_le32(!!inverted);
604
605 ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
606
607 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
608 return ret;
609}
610
611/**
612 * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table
613 *
614 * @priv: A pointer to &struct lbs_private structure
615 * @id: The ID of the entry to list
616 * @addr1: MAC address associated with the table entry
617 *
618 * returns: 0 on success, error on failure
619 */
620int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
621{
622 struct cmd_ds_bt_access cmd;
623 int ret = 0;
624
625 lbs_deb_enter(LBS_DEB_CMD);
626
627 BUG_ON(addr1 == NULL);
628
629 memset(&cmd, 0, sizeof(cmd));
630 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
631 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
632 cmd.id = cpu_to_le32(id);
633
634 ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
635 if (ret == 0)
636 memcpy(addr1, cmd.addr1, sizeof(cmd.addr1));
637
638 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
639 return ret;
640}
641
642/**
643 * lbs_cmd_fwt_access - Access the mesh forwarding table
644 *
645 * @priv: A pointer to &struct lbs_private structure
646 * @cmd_action: The forwarding table action to perform
647 * @cmd: The pre-filled FWT_ACCESS command
648 *
649 * returns: 0 on success and 'cmd' will be filled with the
650 * firmware's response
651 */
652int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
653 struct cmd_ds_fwt_access *cmd)
654{
655 int ret;
656
657 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
658
659 cmd->hdr.command = cpu_to_le16(CMD_FWT_ACCESS);
660 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access));
661 cmd->hdr.result = 0;
662 cmd->action = cpu_to_le16(cmd_action);
663
664 ret = lbs_cmd_with_response(priv, CMD_FWT_ACCESS, cmd);
665
666 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
667 return 0;
668}
669
670int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
671 struct cmd_ds_mesh_access *cmd)
672{
673 int ret;
674
675 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
676
677 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
678 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
679 cmd->hdr.result = 0;
680
681 cmd->action = cpu_to_le16(cmd_action);
682
683 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
684
685 lbs_deb_leave(LBS_DEB_CMD);
686 return ret;
687}
688
689static int __lbs_mesh_config_send(struct lbs_private *priv,
690 struct cmd_ds_mesh_config *cmd,
691 uint16_t action, uint16_t type)
692{
693 int ret;
694 u16 command = CMD_MESH_CONFIG_OLD;
695
696 lbs_deb_enter(LBS_DEB_CMD);
697
698 /*
699 * Command id is 0xac for v10 FW along with mesh interface
700 * id in bits 14-13-12.
701 */
702 if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
703 command = CMD_MESH_CONFIG |
704 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
705
706 cmd->hdr.command = cpu_to_le16(command);
707 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
708 cmd->hdr.result = 0;
709
710 cmd->type = cpu_to_le16(type);
711 cmd->action = cpu_to_le16(action);
712
713 ret = lbs_cmd_with_response(priv, command, cmd);
714
715 lbs_deb_leave(LBS_DEB_CMD);
716 return ret;
717}
718
719int lbs_mesh_config_send(struct lbs_private *priv,
720 struct cmd_ds_mesh_config *cmd,
721 uint16_t action, uint16_t type)
722{
723 int ret;
724
725 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
726 return -EOPNOTSUPP;
727
728 ret = __lbs_mesh_config_send(priv, cmd, action, type);
729 return ret;
730}
731
732/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
733 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
734 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
735 * lbs_mesh_config_send.
736 */
737int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
738{
739 struct cmd_ds_mesh_config cmd;
740 struct mrvl_meshie *ie;
741 DECLARE_SSID_BUF(ssid);
742
743 memset(&cmd, 0, sizeof(cmd));
744 cmd.channel = cpu_to_le16(chan);
745 ie = (struct mrvl_meshie *)cmd.data;
746
747 switch (action) {
748 case CMD_ACT_MESH_CONFIG_START:
749 ie->id = WLAN_EID_GENERIC;
750 ie->val.oui[0] = 0x00;
751 ie->val.oui[1] = 0x50;
752 ie->val.oui[2] = 0x43;
753 ie->val.type = MARVELL_MESH_IE_TYPE;
754 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
755 ie->val.version = MARVELL_MESH_IE_VERSION;
756 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
757 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
758 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
759 ie->val.mesh_id_len = priv->mesh_ssid_len;
760 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
761 ie->len = sizeof(struct mrvl_meshie_val) -
762 IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
763 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
764 break;
765 case CMD_ACT_MESH_CONFIG_STOP:
766 break;
767 default:
768 return -1;
769 }
770 lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
771 action, priv->mesh_tlv, chan,
772 print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
773
774 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
775}
776
777
778
779/*************************************************************************** 317/***************************************************************************
780 * Persistent configuration support 318 * Persistent configuration support
781 */ 319 */
@@ -1232,7 +770,7 @@ static struct attribute *boot_opts_attrs[] = {
1232 NULL 770 NULL
1233}; 771};
1234 772
1235static struct attribute_group boot_opts_group = { 773static const struct attribute_group boot_opts_group = {
1236 .name = "boot_options", 774 .name = "boot_options",
1237 .attrs = boot_opts_attrs, 775 .attrs = boot_opts_attrs,
1238}; 776};
@@ -1245,31 +783,299 @@ static struct attribute *mesh_ie_attrs[] = {
1245 NULL 783 NULL
1246}; 784};
1247 785
1248static struct attribute_group mesh_ie_group = { 786static const struct attribute_group mesh_ie_group = {
1249 .name = "mesh_ie", 787 .name = "mesh_ie",
1250 .attrs = mesh_ie_attrs, 788 .attrs = mesh_ie_attrs,
1251}; 789};
1252 790
1253void lbs_persist_config_init(struct net_device *dev) 791static void lbs_persist_config_init(struct net_device *dev)
1254{ 792{
1255 int ret; 793 int ret;
1256 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group); 794 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
1257 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group); 795 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
1258} 796}
1259 797
1260void lbs_persist_config_remove(struct net_device *dev) 798static void lbs_persist_config_remove(struct net_device *dev)
1261{ 799{
1262 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); 800 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
1263 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); 801 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
1264} 802}
1265 803
1266 804
805/***************************************************************************
806 * Initializing and starting, stopping mesh
807 */
808
809/*
810 * Check mesh FW version and appropriately send the mesh start
811 * command
812 */
813int lbs_init_mesh(struct lbs_private *priv)
814{
815 struct net_device *dev = priv->dev;
816 int ret = 0;
817
818 lbs_deb_enter(LBS_DEB_MESH);
819
820 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
821 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
822 /* 5.110.22 have mesh command with 0xa3 command id */
823 /* 10.0.0.p0 FW brings in mesh config command with different id */
824 /* Check FW version MSB and initialize mesh_fw_ver */
825 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
826 /* Enable mesh, if supported, and work out which TLV it uses.
827 0x100 + 291 is an unofficial value used in 5.110.20.pXX
828 0x100 + 37 is the official value used in 5.110.21.pXX
829 but we check them in that order because 20.pXX doesn't
830 give an error -- it just silently fails. */
831
832 /* 5.110.20.pXX firmware will fail the command if the channel
833 doesn't match the existing channel. But only if the TLV
834 is correct. If the channel is wrong, _BOTH_ versions will
835 give an error to 0x100+291, and allow 0x100+37 to succeed.
836 It's just that 5.110.20.pXX will not have done anything
837 useful */
838
839 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
840 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
841 priv->channel)) {
842 priv->mesh_tlv = TLV_TYPE_MESH_ID;
843 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
844 priv->channel))
845 priv->mesh_tlv = 0;
846 }
847 } else
848 if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
849 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
850 /* 10.0.0.pXX new firmwares should succeed with TLV
851 * 0x100+37; Do not invoke command with old TLV.
852 */
853 priv->mesh_tlv = TLV_TYPE_MESH_ID;
854 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
855 priv->channel))
856 priv->mesh_tlv = 0;
857 }
858
859 /* Stop meshing until interface is brought up */
860 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
861
862 if (priv->mesh_tlv) {
863 sprintf(priv->mesh_ssid, "mesh");
864 priv->mesh_ssid_len = 4;
865
866 lbs_add_mesh(priv);
867
868 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
869 netdev_err(dev, "cannot register lbs_mesh attribute\n");
870
871 ret = 1;
872 }
873
874 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
875 return ret;
876}
877
878
879int lbs_deinit_mesh(struct lbs_private *priv)
880{
881 struct net_device *dev = priv->dev;
882 int ret = 0;
883
884 lbs_deb_enter(LBS_DEB_MESH);
885
886 if (priv->mesh_tlv) {
887 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
888 ret = 1;
889 }
890
891 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
892 return ret;
893}
894
895
896/**
897 * lbs_mesh_stop - close the mshX interface
898 *
899 * @dev: A pointer to &net_device structure
900 * returns: 0
901 */
902static int lbs_mesh_stop(struct net_device *dev)
903{
904 struct lbs_private *priv = dev->ml_priv;
905
906 lbs_deb_enter(LBS_DEB_MESH);
907 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
908
909 spin_lock_irq(&priv->driver_lock);
910
911 netif_stop_queue(dev);
912 netif_carrier_off(dev);
913
914 spin_unlock_irq(&priv->driver_lock);
915
916 schedule_work(&priv->mcast_work);
917
918 lbs_deb_leave(LBS_DEB_MESH);
919 return 0;
920}
921
922/**
923 * lbs_mesh_dev_open - open the mshX interface
924 *
925 * @dev: A pointer to &net_device structure
926 * returns: 0 or -EBUSY if monitor mode active
927 */
928static int lbs_mesh_dev_open(struct net_device *dev)
929{
930 struct lbs_private *priv = dev->ml_priv;
931 int ret = 0;
932
933 lbs_deb_enter(LBS_DEB_NET);
934
935 spin_lock_irq(&priv->driver_lock);
936
937 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
938 ret = -EBUSY;
939 spin_unlock_irq(&priv->driver_lock);
940 goto out;
941 }
942
943 netif_carrier_on(dev);
944
945 if (!priv->tx_pending_len)
946 netif_wake_queue(dev);
947
948 spin_unlock_irq(&priv->driver_lock);
949
950 ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel);
951
952out:
953 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
954 return ret;
955}
956
957static const struct net_device_ops mesh_netdev_ops = {
958 .ndo_open = lbs_mesh_dev_open,
959 .ndo_stop = lbs_mesh_stop,
960 .ndo_start_xmit = lbs_hard_start_xmit,
961 .ndo_set_mac_address = lbs_set_mac_address,
962 .ndo_set_multicast_list = lbs_set_multicast_list,
963};
964
965/**
966 * lbs_add_mesh - add mshX interface
967 *
968 * @priv: A pointer to the &struct lbs_private structure
969 * returns: 0 if successful, -X otherwise
970 */
971static int lbs_add_mesh(struct lbs_private *priv)
972{
973 struct net_device *mesh_dev = NULL;
974 int ret = 0;
975
976 lbs_deb_enter(LBS_DEB_MESH);
977
978 /* Allocate a virtual mesh device */
979 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
980 if (!mesh_dev) {
981 lbs_deb_mesh("init mshX device failed\n");
982 ret = -ENOMEM;
983 goto done;
984 }
985 mesh_dev->ml_priv = priv;
986 priv->mesh_dev = mesh_dev;
987
988 mesh_dev->netdev_ops = &mesh_netdev_ops;
989 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
990 memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
991
992 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
993
994 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
995 /* Register virtual mesh interface */
996 ret = register_netdev(mesh_dev);
997 if (ret) {
998 pr_err("cannot register mshX virtual interface\n");
999 goto err_free;
1000 }
1001
1002 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1003 if (ret)
1004 goto err_unregister;
1005
1006 lbs_persist_config_init(mesh_dev);
1007
1008 /* Everything successful */
1009 ret = 0;
1010 goto done;
1011
1012err_unregister:
1013 unregister_netdev(mesh_dev);
1014
1015err_free:
1016 free_netdev(mesh_dev);
1017
1018done:
1019 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
1020 return ret;
1021}
1022
1023void lbs_remove_mesh(struct lbs_private *priv)
1024{
1025 struct net_device *mesh_dev;
1026
1027 mesh_dev = priv->mesh_dev;
1028 if (!mesh_dev)
1029 return;
1030
1031 lbs_deb_enter(LBS_DEB_MESH);
1032 netif_stop_queue(mesh_dev);
1033 netif_carrier_off(mesh_dev);
1034 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1035 lbs_persist_config_remove(mesh_dev);
1036 unregister_netdev(mesh_dev);
1037 priv->mesh_dev = NULL;
1038 free_netdev(mesh_dev);
1039 lbs_deb_leave(LBS_DEB_MESH);
1040}
1041
1042
1043/***************************************************************************
1044 * Sending and receiving
1045 */
1046struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1047 struct net_device *dev, struct rxpd *rxpd)
1048{
1049 if (priv->mesh_dev) {
1050 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1051 if (rxpd->rx_control & RxPD_MESH_FRAME)
1052 dev = priv->mesh_dev;
1053 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1054 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1055 dev = priv->mesh_dev;
1056 }
1057 }
1058 return dev;
1059}
1060
1061
1062void lbs_mesh_set_txpd(struct lbs_private *priv,
1063 struct net_device *dev, struct txpd *txpd)
1064{
1065 if (dev == priv->mesh_dev) {
1066 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1067 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1068 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1069 txpd->u.bss.bss_num = MESH_IFACE_ID;
1070 }
1071}
1072
1267 1073
1268/*************************************************************************** 1074/***************************************************************************
1269 * Ethtool related 1075 * Ethtool related
1270 */ 1076 */
1271 1077
1272static const char *mesh_stat_strings[] = { 1078static const char * const mesh_stat_strings[] = {
1273 "drop_duplicate_bcast", 1079 "drop_duplicate_bcast",
1274 "drop_ttl_zero", 1080 "drop_ttl_zero",
1275 "drop_no_fwd_route", 1081 "drop_no_fwd_route",
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index ee95c73ed5f4..50144913f2ab 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -31,7 +31,6 @@ struct lbs_private;
31int lbs_init_mesh(struct lbs_private *priv); 31int lbs_init_mesh(struct lbs_private *priv);
32int lbs_deinit_mesh(struct lbs_private *priv); 32int lbs_deinit_mesh(struct lbs_private *priv);
33 33
34int lbs_add_mesh(struct lbs_private *priv);
35void lbs_remove_mesh(struct lbs_private *priv); 34void lbs_remove_mesh(struct lbs_private *priv);
36 35
37 36
@@ -52,29 +51,6 @@ struct cmd_ds_command;
52struct cmd_ds_mesh_access; 51struct cmd_ds_mesh_access;
53struct cmd_ds_mesh_config; 52struct cmd_ds_mesh_config;
54 53
55int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1);
56int lbs_mesh_bt_reset(struct lbs_private *priv);
57int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted);
58int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted);
59int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1);
60
61int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
62 struct cmd_ds_fwt_access *cmd);
63
64int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
65 struct cmd_ds_mesh_access *cmd);
66int lbs_mesh_config_send(struct lbs_private *priv,
67 struct cmd_ds_mesh_config *cmd,
68 uint16_t action, uint16_t type);
69int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
70
71
72
73/* Persistent configuration */
74
75void lbs_persist_config_init(struct net_device *net);
76void lbs_persist_config_remove(struct net_device *net);
77
78 54
79/* Ethtool statistics */ 55/* Ethtool statistics */
80 56
@@ -87,11 +63,6 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
87 uint32_t stringset, uint8_t *s); 63 uint32_t stringset, uint8_t *s);
88 64
89 65
90/* Accessors */
91
92#define lbs_mesh_open(priv) (priv->mesh_open)
93#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED)
94
95#else 66#else
96 67
97#define lbs_init_mesh(priv) 68#define lbs_init_mesh(priv)
@@ -101,8 +72,6 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
101#define lbs_mesh_set_dev(priv, dev, rxpd) (dev) 72#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
102#define lbs_mesh_set_txpd(priv, dev, txpd) 73#define lbs_mesh_set_txpd(priv, dev, txpd)
103#define lbs_mesh_config(priv, enable, chan) 74#define lbs_mesh_config(priv, enable, chan)
104#define lbs_mesh_open(priv) (0)
105#define lbs_mesh_connected(priv) (0)
106 75
107#endif 76#endif
108 77
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index f19495b178f6..a6e85134cfe1 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -199,7 +199,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
199 if (priv->connect_status == LBS_CONNECTED) 199 if (priv->connect_status == LBS_CONNECTED)
200 netif_wake_queue(priv->dev); 200 netif_wake_queue(priv->dev);
201 201
202 if (priv->mesh_dev && lbs_mesh_connected(priv)) 202 if (priv->mesh_dev && netif_running(priv->mesh_dev))
203 netif_wake_queue(priv->mesh_dev); 203 netif_wake_queue(priv->mesh_dev);
204} 204}
205EXPORT_SYMBOL_GPL(lbs_send_tx_feedback); 205EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);