diff options
author | Christian Lamparter <chunkeey@web.de> | 2008-10-18 17:19:00 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-10 15:10:16 -0500 |
commit | e5ea92a7528d304e8e327d0d261653e98b163e8a (patch) | |
tree | 5e625aae02461802f816a0063a6e6c24e8f82893 /drivers/net/wireless/p54/p54common.c | |
parent | 94585b090baf982a850678a1dc3395bce0c1e302 (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.c | 245 |
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 | ||
720 | static 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 | |||
714 | static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) | 749 | static 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 | } |
903 | EXPORT_SYMBOL_GPL(p54_read_eeprom); | 941 | EXPORT_SYMBOL_GPL(p54_read_eeprom); |
904 | 942 | ||
943 | static 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 | |||
963 | static 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 | |||
981 | static 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 | |||
905 | static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, | 1001 | static 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 | ||
1405 | static 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 | |||
1458 | static 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 | |||
1298 | static int p54_start(struct ieee80211_hw *dev) | 1487 | static 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 | } | ||
1645 | out: | ||
1414 | mutex_unlock(&priv->conf_mutex); | 1646 | mutex_unlock(&priv->conf_mutex); |
1415 | return 0; | 1647 | return ret; |
1416 | } | 1648 | } |
1417 | 1649 | ||
1418 | static void p54_configure_filter(struct ieee80211_hw *dev, | 1650 | static 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 */ |