diff options
author | Luis Carlos Cobo <luisca@cozybit.com> | 2007-08-02 13:16:55 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:50:13 -0400 |
commit | 965f8bbc6c92233600b176f4c80299f6766df9bd (patch) | |
tree | 85043fb97112a148d69171b744568fa78de2e05d /drivers/net/wireless/libertas/main.c | |
parent | 9483f03150cbfa1f706355b7f9d218d6086c6fce (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.c | 153 |
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" |
26 | const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION | 27 | const 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 | ||
250 | int libertas_add_rtap(wlan_private *priv); | ||
251 | void libertas_remove_rtap(wlan_private *priv); | ||
252 | |||
253 | /** | ||
254 | * Get function for sysfs attribute rtap | ||
255 | */ | ||
256 | static 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 | */ | ||
267 | static 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 | */ | ||
307 | static 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 | */ |
495 | static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) | 560 | static 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 | ||
1174 | err_kzalloc: | 1248 | err_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 | |||
1620 | static int libertas_rtap_open(struct net_device *dev) | ||
1621 | { | ||
1622 | netif_carrier_off(dev); | ||
1623 | netif_stop_queue(dev); | ||
1624 | return 0; | ||
1625 | } | ||
1626 | |||
1627 | static int libertas_rtap_stop(struct net_device *dev) | ||
1628 | { | ||
1629 | return 0; | ||
1630 | } | ||
1631 | |||
1632 | static 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 | |||
1638 | static 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 | |||
1645 | void 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 | |||
1654 | int 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 | |||
1540 | module_init(libertas_init_module); | 1691 | module_init(libertas_init_module); |
1541 | module_exit(libertas_exit_module); | 1692 | module_exit(libertas_exit_module); |
1542 | 1693 | ||