diff options
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 | ||