aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/main.c
diff options
context:
space:
mode:
authorLuis Carlos Cobo <luisca@cozybit.com>2007-08-02 13:16:55 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:50:13 -0400
commit965f8bbc6c92233600b176f4c80299f6766df9bd (patch)
tree85043fb97112a148d69171b744568fa78de2e05d /drivers/net/wireless/libertas/main.c
parent9483f03150cbfa1f706355b7f9d218d6086c6fce (diff)
[PATCH] libertas: monitor mode support for OLPC firmware
Driver support for the monitor mode support that will be available in the next OLPC 'bleeding edge' Marvell firmware release (most likely, 5.110.16.p2). To activate monitor mode, echo mode > /sys/class/net/{ethX,mshX}/device/libertas_rtap where mode is the hex mask that specifies which frames to sniff (in short, 0x1 for data, 0x2 for all management but beacons, 0x4 for beacons). Any non zero mode will activate the monitor mode, inhibiting transmission in ethX and mshX interfaces and routing all the incoming traffic to a new rtapX interface that will output the packets in 802.11+radiotap headers format. Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r--drivers/net/wireless/libertas/main.c153
1 files changed, 152 insertions, 1 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index a3a17caae439..9a46339ce47e 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -21,6 +21,7 @@
21#include "wext.h" 21#include "wext.h"
22#include "debugfs.h" 22#include "debugfs.h"
23#include "assoc.h" 23#include "assoc.h"
24#include "join.h"
24 25
25#define DRIVER_RELEASE_VERSION "322.p1" 26#define DRIVER_RELEASE_VERSION "322.p1"
26const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION 27const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
@@ -246,6 +247,66 @@ static ssize_t libertas_anycast_set(struct device * dev,
246 return strlen(buf); 247 return strlen(buf);
247} 248}
248 249
250int libertas_add_rtap(wlan_private *priv);
251void libertas_remove_rtap(wlan_private *priv);
252
253/**
254 * Get function for sysfs attribute rtap
255 */
256static ssize_t libertas_rtap_get(struct device * dev,
257 struct device_attribute *attr, char * buf)
258{
259 wlan_private *priv = (wlan_private *) dev->driver_data;
260 wlan_adapter *adapter = priv->adapter;
261 return snprintf(buf, 5, "0x%X\n", adapter->monitormode);
262}
263
264/**
265 * Set function for sysfs attribute rtap
266 */
267static ssize_t libertas_rtap_set(struct device * dev,
268 struct device_attribute *attr, const char * buf, size_t count)
269{
270 int monitor_mode;
271 wlan_private *priv = (wlan_private *) dev->driver_data;
272 wlan_adapter *adapter = priv->adapter;
273
274 sscanf(buf, "%x", &monitor_mode);
275 if (monitor_mode != WLAN_MONITOR_OFF) {
276 if(adapter->monitormode == monitor_mode)
277 return strlen(buf);
278 if (adapter->monitormode == WLAN_MONITOR_OFF) {
279 if (adapter->mode == IW_MODE_INFRA)
280 libertas_send_deauthentication(priv);
281 else if (adapter->mode == IW_MODE_ADHOC)
282 libertas_stop_adhoc_network(priv);
283 libertas_add_rtap(priv);
284 }
285 adapter->monitormode = monitor_mode;
286 }
287
288 else {
289 if(adapter->monitormode == WLAN_MONITOR_OFF)
290 return strlen(buf);
291 adapter->monitormode = WLAN_MONITOR_OFF;
292 libertas_remove_rtap(priv);
293 netif_wake_queue(priv->dev);
294 netif_wake_queue(priv->mesh_dev);
295 }
296
297 libertas_prepare_and_send_command(priv,
298 CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
299 CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode);
300 return strlen(buf);
301}
302
303/**
304 * libertas_rtap attribute to be exported per mshX interface
305 * through sysfs (/sys/class/net/mshX/libertas-rtap)
306 */
307static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get,
308 libertas_rtap_set );
309
249/** 310/**
250 * anycast_mask attribute to be exported per mshX interface 311 * anycast_mask attribute to be exported per mshX interface
251 * through sysfs (/sys/class/net/mshX/anycast_mask) 312 * through sysfs (/sys/class/net/mshX/anycast_mask)
@@ -480,6 +541,10 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
480 int ret; 541 int ret;
481 542
482 lbs_deb_enter(LBS_DEB_MESH); 543 lbs_deb_enter(LBS_DEB_MESH);
544 if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
545 netif_stop_queue(dev);
546 return -EOPNOTSUPP;
547 }
483 548
484 SET_MESH_FRAME(skb); 549 SET_MESH_FRAME(skb);
485 550
@@ -494,10 +559,16 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
494 */ 559 */
495static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) 560static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
496{ 561{
562 wlan_private *priv = dev->priv;
497 int ret; 563 int ret;
498 564
499 lbs_deb_enter(LBS_DEB_NET); 565 lbs_deb_enter(LBS_DEB_NET);
500 566
567 if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
568 netif_stop_queue(dev);
569 return -EOPNOTSUPP;
570 }
571
501 UNSET_MESH_FRAME(skb); 572 UNSET_MESH_FRAME(skb);
502 573
503 ret = libertas_hard_start_xmit(skb, dev); 574 ret = libertas_hard_start_xmit(skb, dev);
@@ -517,7 +588,7 @@ static void libertas_tx_timeout(struct net_device *dev)
517 dev->trans_start = jiffies; 588 dev->trans_start = jiffies;
518 589
519 if (priv->adapter->currenttxskb) { 590 if (priv->adapter->currenttxskb) {
520 if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { 591 if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
521 /* If we are here, we have not received feedback from 592 /* If we are here, we have not received feedback from
522 the previous packet. Assume TX_FAIL and move on. */ 593 the previous packet. Assume TX_FAIL and move on. */
523 priv->adapter->eventcause = 0x01000000; 594 priv->adapter->eventcause = 0x01000000;
@@ -1169,6 +1240,9 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
1169 spin_lock_init(&priv->adapter->driver_lock); 1240 spin_lock_init(&priv->adapter->driver_lock);
1170 init_waitqueue_head(&priv->adapter->cmd_pending); 1241 init_waitqueue_head(&priv->adapter->cmd_pending);
1171 priv->adapter->nr_cmd_pending = 0; 1242 priv->adapter->nr_cmd_pending = 0;
1243 priv->rtap_net_dev = NULL;
1244 if (device_create_file(dmdev, &dev_attr_libertas_rtap))
1245 goto err_kzalloc;
1172 goto done; 1246 goto done;
1173 1247
1174err_kzalloc: 1248err_kzalloc:
@@ -1333,6 +1407,7 @@ int libertas_remove_card(wlan_private *priv)
1333 1407
1334 lbs_deb_enter(LBS_DEB_NET); 1408 lbs_deb_enter(LBS_DEB_NET);
1335 1409
1410 libertas_remove_rtap(priv);
1336 if (!priv) 1411 if (!priv)
1337 goto out; 1412 goto out;
1338 1413
@@ -1342,6 +1417,7 @@ int libertas_remove_card(wlan_private *priv)
1342 goto out; 1417 goto out;
1343 1418
1344 dev = priv->dev; 1419 dev = priv->dev;
1420 device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
1345 1421
1346 netif_stop_queue(priv->dev); 1422 netif_stop_queue(priv->dev);
1347 netif_carrier_off(priv->dev); 1423 netif_carrier_off(priv->dev);
@@ -1537,6 +1613,81 @@ static void libertas_exit_module(void)
1537 lbs_deb_leave(LBS_DEB_MAIN); 1613 lbs_deb_leave(LBS_DEB_MAIN);
1538} 1614}
1539 1615
1616/*
1617 * rtap interface support fuctions
1618 */
1619
1620static int libertas_rtap_open(struct net_device *dev)
1621{
1622 netif_carrier_off(dev);
1623 netif_stop_queue(dev);
1624 return 0;
1625}
1626
1627static int libertas_rtap_stop(struct net_device *dev)
1628{
1629 return 0;
1630}
1631
1632static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
1633{
1634 netif_stop_queue(dev);
1635 return -EOPNOTSUPP;
1636}
1637
1638static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev)
1639{
1640 wlan_private *priv = dev->priv;
1641 return &priv->ieee->stats;
1642}
1643
1644
1645void libertas_remove_rtap(wlan_private *priv)
1646{
1647 if (priv->rtap_net_dev == NULL)
1648 return;
1649 unregister_netdev(priv->rtap_net_dev);
1650 free_ieee80211(priv->rtap_net_dev);
1651 priv->rtap_net_dev = NULL;
1652}
1653
1654int libertas_add_rtap(wlan_private *priv)
1655{
1656 int rc = 0;
1657
1658 if (priv->rtap_net_dev)
1659 return -EPERM;
1660
1661 priv->rtap_net_dev = alloc_ieee80211(0);
1662 if (priv->rtap_net_dev == NULL)
1663 return -ENOMEM;
1664
1665
1666 priv->ieee = netdev_priv(priv->rtap_net_dev);
1667
1668 strcpy(priv->rtap_net_dev->name, "rtap%d");
1669
1670 priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
1671 priv->rtap_net_dev->open = libertas_rtap_open;
1672 priv->rtap_net_dev->stop = libertas_rtap_stop;
1673 priv->rtap_net_dev->get_stats = libertas_rtap_get_stats;
1674 priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit;
1675 priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list;
1676 priv->rtap_net_dev->priv = priv;
1677
1678 priv->ieee->iw_mode = IW_MODE_MONITOR;
1679
1680 rc = register_netdev(priv->rtap_net_dev);
1681 if (rc) {
1682 free_ieee80211(priv->rtap_net_dev);
1683 priv->rtap_net_dev = NULL;
1684 return rc;
1685 }
1686
1687 return 0;
1688}
1689
1690
1540module_init(libertas_init_module); 1691module_init(libertas_init_module);
1541module_exit(libertas_exit_module); 1692module_exit(libertas_exit_module);
1542 1693