aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54/p54common.c
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2008-10-18 17:19:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-11-10 15:10:16 -0500
commite5ea92a7528d304e8e327d0d261653e98b163e8a (patch)
tree5e625aae02461802f816a0063a6e6c24e8f82893 /drivers/net/wireless/p54/p54common.c
parent94585b090baf982a850678a1dc3395bce0c1e302 (diff)
p54: AP & Ad-hoc testing
This patch finally adds all necessary code to test Ad-hoc & AP mode with p54. Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/p54common.c')
-rw-r--r--drivers/net/wireless/p54/p54common.c245
1 files changed, 240 insertions, 5 deletions
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index e93bca8263cd..8423c430b71b 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -626,6 +626,12 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
626 __skb_unlink(entry, &priv->tx_queue); 626 __skb_unlink(entry, &priv->tx_queue);
627 spin_unlock_irqrestore(&priv->tx_queue.lock, flags); 627 spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
628 628
629 if (unlikely(entry == priv->cached_beacon)) {
630 kfree_skb(entry);
631 priv->cached_beacon = NULL;
632 goto out;
633 }
634
629 /* 635 /*
630 * Clear manually, ieee80211_tx_info_clear_status would 636 * Clear manually, ieee80211_tx_info_clear_status would
631 * clear the counts too and we need them. 637 * clear the counts too and we need them.
@@ -711,6 +717,35 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
711 mod_timer(&priv->stats_timer, jiffies + 5 * HZ); 717 mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
712} 718}
713 719
720static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
721{
722 struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
723 struct p54_trap *trap = (struct p54_trap *) hdr->data;
724 u16 event = le16_to_cpu(trap->event);
725 u16 freq = le16_to_cpu(trap->frequency);
726
727 switch (event) {
728 case P54_TRAP_BEACON_TX:
729 break;
730 case P54_TRAP_RADAR:
731 printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
732 wiphy_name(dev->wiphy), freq);
733 break;
734 case P54_TRAP_NO_BEACON:
735 break;
736 case P54_TRAP_SCAN:
737 break;
738 case P54_TRAP_TBTT:
739 break;
740 case P54_TRAP_TIMER:
741 break;
742 default:
743 printk(KERN_INFO "%s: received event:%x freq:%d\n",
744 wiphy_name(dev->wiphy), event, freq);
745 break;
746 }
747}
748
714static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) 749static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
715{ 750{
716 struct p54_hdr *hdr = (struct p54_hdr *) skb->data; 751 struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
@@ -719,6 +754,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
719 case P54_CONTROL_TYPE_TXDONE: 754 case P54_CONTROL_TYPE_TXDONE:
720 p54_rx_frame_sent(dev, skb); 755 p54_rx_frame_sent(dev, skb);
721 break; 756 break;
757 case P54_CONTROL_TYPE_TRAP:
758 p54_rx_trap(dev, skb);
759 break;
722 case P54_CONTROL_TYPE_BBP: 760 case P54_CONTROL_TYPE_BBP:
723 break; 761 break;
724 case P54_CONTROL_TYPE_STAT_READBACK: 762 case P54_CONTROL_TYPE_STAT_READBACK:
@@ -902,6 +940,64 @@ free:
902} 940}
903EXPORT_SYMBOL_GPL(p54_read_eeprom); 941EXPORT_SYMBOL_GPL(p54_read_eeprom);
904 942
943static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
944 bool set)
945{
946 struct p54_common *priv = dev->priv;
947 struct sk_buff *skb;
948 struct p54_tim *tim;
949
950 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
951 sizeof(struct p54_hdr) + sizeof(*tim),
952 P54_CONTROL_TYPE_TIM, GFP_KERNEL);
953 if (!skb)
954 return -ENOMEM;
955
956 tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
957 tim->count = 1;
958 tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
959 priv->tx(dev, skb, 1);
960 return 0;
961}
962
963static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
964{
965 struct p54_common *priv = dev->priv;
966 struct sk_buff *skb;
967 struct p54_sta_unlock *sta;
968
969 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
970 sizeof(struct p54_hdr) + sizeof(*sta),
971 P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
972 if (!skb)
973 return -ENOMEM;
974
975 sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
976 memcpy(sta->addr, addr, ETH_ALEN);
977 priv->tx(dev, skb, 1);
978 return 0;
979}
980
981static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
982{
983 struct p54_common *priv = dev->priv;
984 struct sk_buff *skb;
985 struct p54_hdr *hdr;
986 struct p54_txcancel *cancel;
987
988 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
989 sizeof(struct p54_hdr) + sizeof(*cancel),
990 P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
991 if (!skb)
992 return -ENOMEM;
993
994 hdr = (void *)entry->data;
995 cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
996 cancel->req_id = hdr->req_id;
997 priv->tx(dev, skb, 1);
998 return 0;
999}
1000
905static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, 1001static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
906 struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, 1002 struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
907 u16 *flags, u16 *aid) 1003 u16 *flags, u16 *aid)
@@ -982,6 +1078,17 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
982 padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; 1078 padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
983 len = skb->len; 1079 len = skb->len;
984 1080
1081 if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) {
1082 if (info->control.sta)
1083 if (p54_sta_unlock(dev, info->control.sta->addr)) {
1084 if (current_queue) {
1085 current_queue->len--;
1086 current_queue->count--;
1087 }
1088 return NETDEV_TX_BUSY;
1089 }
1090 }
1091
985 txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); 1092 txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
986 hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); 1093 hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
987 1094
@@ -1295,6 +1402,88 @@ static int p54_init_stats(struct ieee80211_hw *dev)
1295 return 0; 1402 return 0;
1296} 1403}
1297 1404
1405static int p54_beacon_tim(struct sk_buff *skb)
1406{
1407 /*
1408 * the good excuse for this mess is ... the firmware.
1409 * The dummy TIM MUST be at the end of the beacon frame,
1410 * because it'll be overwritten!
1411 */
1412
1413 struct ieee80211_mgmt *mgmt = (void *)skb->data;
1414 u8 *pos, *end;
1415
1416 if (skb->len <= sizeof(mgmt)) {
1417 printk(KERN_ERR "p54: beacon is too short!\n");
1418 return -EINVAL;
1419 }
1420
1421 pos = (u8 *)mgmt->u.beacon.variable;
1422 end = skb->data + skb->len;
1423 while (pos < end) {
1424 if (pos + 2 + pos[1] > end) {
1425 printk(KERN_ERR "p54: parsing beacon failed\n");
1426 return -EINVAL;
1427 }
1428
1429 if (pos[0] == WLAN_EID_TIM) {
1430 u8 dtim_len = pos[1];
1431 u8 dtim_period = pos[3];
1432 u8 *next = pos + 2 + dtim_len;
1433
1434 if (dtim_len < 3) {
1435 printk(KERN_ERR "p54: invalid dtim len!\n");
1436 return -EINVAL;
1437 }
1438 memmove(pos, next, end - next);
1439
1440 if (dtim_len > 3)
1441 skb_trim(skb, skb->len - (dtim_len - 3));
1442
1443 pos = end - (dtim_len + 2);
1444
1445 /* add the dummy at the end */
1446 pos[0] = WLAN_EID_TIM;
1447 pos[1] = 3;
1448 pos[2] = 0;
1449 pos[3] = dtim_period;
1450 pos[4] = 0;
1451 return 0;
1452 }
1453 pos += 2 + pos[1];
1454 }
1455 return 0;
1456}
1457
1458static int p54_beacon_update(struct ieee80211_hw *dev,
1459 struct ieee80211_vif *vif)
1460{
1461 struct p54_common *priv = dev->priv;
1462 struct sk_buff *beacon;
1463 int ret;
1464
1465 if (priv->cached_beacon) {
1466 p54_tx_cancel(dev, priv->cached_beacon);
1467 /* wait for the last beacon the be freed */
1468 msleep(10);
1469 }
1470
1471 beacon = ieee80211_beacon_get(dev, vif);
1472 if (!beacon)
1473 return -ENOMEM;
1474 ret = p54_beacon_tim(beacon);
1475 if (ret)
1476 return ret;
1477 ret = p54_tx(dev, beacon);
1478 if (ret)
1479 return ret;
1480 priv->cached_beacon = beacon;
1481 priv->tsf_high32 = 0;
1482 priv->tsf_low32 = 0;
1483
1484 return 0;
1485}
1486
1298static int p54_start(struct ieee80211_hw *dev) 1487static int p54_start(struct ieee80211_hw *dev)
1299{ 1488{
1300 struct p54_common *priv = dev->priv; 1489 struct p54_common *priv = dev->priv;
@@ -1325,9 +1514,14 @@ static void p54_stop(struct ieee80211_hw *dev)
1325 del_timer(&priv->stats_timer); 1514 del_timer(&priv->stats_timer);
1326 p54_free_skb(dev, priv->cached_stats); 1515 p54_free_skb(dev, priv->cached_stats);
1327 priv->cached_stats = NULL; 1516 priv->cached_stats = NULL;
1517 if (priv->cached_beacon)
1518 p54_tx_cancel(dev, priv->cached_beacon);
1519
1328 while ((skb = skb_dequeue(&priv->tx_queue))) 1520 while ((skb = skb_dequeue(&priv->tx_queue)))
1329 kfree_skb(skb); 1521 kfree_skb(skb);
1330 1522
1523 kfree(priv->cached_beacon);
1524 priv->cached_beacon = NULL;
1331 priv->stop(dev); 1525 priv->stop(dev);
1332 priv->tsf_high32 = priv->tsf_low32 = 0; 1526 priv->tsf_high32 = priv->tsf_low32 = 0;
1333 priv->mode = NL80211_IFTYPE_UNSPECIFIED; 1527 priv->mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -1347,6 +1541,8 @@ static int p54_add_interface(struct ieee80211_hw *dev,
1347 1541
1348 switch (conf->type) { 1542 switch (conf->type) {
1349 case NL80211_IFTYPE_STATION: 1543 case NL80211_IFTYPE_STATION:
1544 case NL80211_IFTYPE_ADHOC:
1545 case NL80211_IFTYPE_AP:
1350 priv->mode = conf->type; 1546 priv->mode = conf->type;
1351 break; 1547 break;
1352 default: 1548 default:
@@ -1362,6 +1558,12 @@ static int p54_add_interface(struct ieee80211_hw *dev,
1362 case NL80211_IFTYPE_STATION: 1558 case NL80211_IFTYPE_STATION:
1363 p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL); 1559 p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL);
1364 break; 1560 break;
1561 case NL80211_IFTYPE_AP:
1562 p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr);
1563 break;
1564 case NL80211_IFTYPE_ADHOC:
1565 p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL);
1566 break;
1365 default: 1567 default:
1366 BUG(); /* impossible */ 1568 BUG(); /* impossible */
1367 break; 1569 break;
@@ -1379,6 +1581,8 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
1379 struct p54_common *priv = dev->priv; 1581 struct p54_common *priv = dev->priv;
1380 1582
1381 mutex_lock(&priv->conf_mutex); 1583 mutex_lock(&priv->conf_mutex);
1584 if (priv->cached_beacon)
1585 p54_tx_cancel(dev, priv->cached_beacon);
1382 p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); 1586 p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL);
1383 priv->mode = NL80211_IFTYPE_MONITOR; 1587 priv->mode = NL80211_IFTYPE_MONITOR;
1384 memset(priv->mac_addr, 0, ETH_ALEN); 1588 memset(priv->mac_addr, 0, ETH_ALEN);
@@ -1406,13 +1610,41 @@ static int p54_config_interface(struct ieee80211_hw *dev,
1406 struct ieee80211_if_conf *conf) 1610 struct ieee80211_if_conf *conf)
1407{ 1611{
1408 struct p54_common *priv = dev->priv; 1612 struct p54_common *priv = dev->priv;
1613 int ret = 0;
1409 1614
1410 mutex_lock(&priv->conf_mutex); 1615 mutex_lock(&priv->conf_mutex);
1411 p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); 1616 switch (priv->mode) {
1412 p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); 1617 case NL80211_IFTYPE_STATION:
1413 memcpy(priv->bssid, conf->bssid, ETH_ALEN); 1618 ret = p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid);
1619 if (ret)
1620 goto out;
1621 ret = p54_set_leds(dev, 1,
1622 !is_multicast_ether_addr(conf->bssid), 0);
1623 if (ret)
1624 goto out;
1625 memcpy(priv->bssid, conf->bssid, ETH_ALEN);
1626 break;
1627 case NL80211_IFTYPE_AP:
1628 case NL80211_IFTYPE_ADHOC:
1629 memcpy(priv->bssid, conf->bssid, ETH_ALEN);
1630 ret = p54_set_freq(dev, dev->conf.channel->center_freq);
1631 if (ret)
1632 goto out;
1633 ret = p54_setup_mac(dev, priv->mac_mode, priv->bssid);
1634 if (ret)
1635 goto out;
1636 if (conf->changed & IEEE80211_IFCC_BEACON) {
1637 ret = p54_beacon_update(dev, vif);
1638 if (ret)
1639 goto out;
1640 ret = p54_set_edcf(dev);
1641 if (ret)
1642 goto out;
1643 }
1644 }
1645out:
1414 mutex_unlock(&priv->conf_mutex); 1646 mutex_unlock(&priv->conf_mutex);
1415 return 0; 1647 return ret;
1416} 1648}
1417 1649
1418static void p54_configure_filter(struct ieee80211_hw *dev, 1650static void p54_configure_filter(struct ieee80211_hw *dev,
@@ -1541,6 +1773,7 @@ static const struct ieee80211_ops p54_ops = {
1541 .stop = p54_stop, 1773 .stop = p54_stop,
1542 .add_interface = p54_add_interface, 1774 .add_interface = p54_add_interface,
1543 .remove_interface = p54_remove_interface, 1775 .remove_interface = p54_remove_interface,
1776 .set_tim = p54_set_tim,
1544 .config = p54_config, 1777 .config = p54_config,
1545 .config_interface = p54_config_interface, 1778 .config_interface = p54_config_interface,
1546 .bss_info_changed = p54_bss_info_changed, 1779 .bss_info_changed = p54_bss_info_changed,
@@ -1566,7 +1799,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
1566 IEEE80211_HW_SIGNAL_DBM | 1799 IEEE80211_HW_SIGNAL_DBM |
1567 IEEE80211_HW_NOISE_DBM; 1800 IEEE80211_HW_NOISE_DBM;
1568 1801
1569 dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 1802 dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION |
1803 NL80211_IFTYPE_ADHOC |
1804 NL80211_IFTYPE_AP);
1570 1805
1571 dev->channel_change_time = 1000; /* TODO: find actual value */ 1806 dev->channel_change_time = 1000; /* TODO: find actual value */
1572 priv->tx_stats[0].limit = 1; /* Beacon queue */ 1807 priv->tx_stats[0].limit = 1; /* Beacon queue */