* connecting ieee80211_hw and net_device
@ 2010-11-09 20:31 Zoltan Herczeg
2010-11-10 0:26 ` Johannes Berg
0 siblings, 1 reply; 5+ messages in thread
From: Zoltan Herczeg @ 2010-11-09 20:31 UTC (permalink / raw)
To: linux-wireless
Hi,
I am developing a wireless driver for a cycle accurate energy simulator,
and cannot solve the following issue:
I can allocate a "wlan0" and "wlan1" platform device with
ieee80211_alloc_hw, and can initialize it in Ad-Hoc mode. However, I
realized this is not enough to have a wireless interface, since it has no
receive operation, only transfer. Looking at the other drivers, I found
that they allocate a net_device with the common alloc_etherdev.
Unfortunately the register_netdev registers a new eth interface in my
case, and this interface is not connected to the wlan interface. I set
wireless_handlers and ieee80211_ptr for this device, still it is totally
independent from the wlan interface.
Am I missing something? (Sorry if this is a trivial question, I tried
google but no luck so far)
Thanks in advance
Zoltan
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: connecting ieee80211_hw and net_device
2010-11-09 20:31 connecting ieee80211_hw and net_device Zoltan Herczeg
@ 2010-11-10 0:26 ` Johannes Berg
2010-11-11 14:20 ` Zoltan Herczeg
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2010-11-10 0:26 UTC (permalink / raw)
To: Zoltan Herczeg; +Cc: linux-wireless
On Tue, 2010-11-09 at 21:31 +0100, Zoltan Herczeg wrote:
> I can allocate a "wlan0" and "wlan1" platform device with
> ieee80211_alloc_hw, and can initialize it in Ad-Hoc mode. However, I
> realized this is not enough to have a wireless interface, since it has no
> receive operation, only transfer. Looking at the other drivers, I found
> that they allocate a net_device with the common alloc_etherdev.
> Unfortunately the register_netdev registers a new eth interface in my
> case, and this interface is not connected to the wlan interface. I set
> wireless_handlers and ieee80211_ptr for this device, still it is totally
> independent from the wlan interface.
>
> Am I missing something? (Sorry if this is a trivial question, I tried
> google but no luck so far)
Your question doesn't make any sense. You never need wlan0/1, you only
need alloc_hw/register_hw and then the interfaces will be managed by
mac80211. You should post the code so people can help you.
johannes
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: connecting ieee80211_hw and net_device
2010-11-10 0:26 ` Johannes Berg
@ 2010-11-11 14:20 ` Zoltan Herczeg
2010-11-12 22:33 ` Zoltan Herczeg
0 siblings, 1 reply; 5+ messages in thread
From: Zoltan Herczeg @ 2010-11-11 14:20 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 1827 bytes --]
Hi,
thanks for you reply. I was thinking and realized probably the
alloc_etherdev() calls have a different purpose and removed them (and
found an ieee80211_rx_irqsafe function, which pass the received messages
to 80211). My plan is to run the network in ad-hoc mode (passing 1 to
SIOCSIWMODE ioctl command). Unfortunately it is still not working, because
rx.sta = sta_info_get(local, hdr->addr2) in rx.c returns with NULL, and
the received messages are eventually dropped. I tried to understand the
code, and I think messages called "beacons" are needed to make
sta_info_get() work. These messages can be created by
ieee80211_beacon_get, but it also returns with NULL in my case, because
rcu_dereference(ifibss->presp) returns with NULL. Could you help me?
The code is attached to this mail.
Thanks in advance,
Zoltan
> On Tue, 2010-11-09 at 21:31 +0100, Zoltan Herczeg wrote:
>
>> I can allocate a "wlan0" and "wlan1" platform device with
>> ieee80211_alloc_hw, and can initialize it in Ad-Hoc mode. However, I
>> realized this is not enough to have a wireless interface, since it has
>> no
>> receive operation, only transfer. Looking at the other drivers, I found
>> that they allocate a net_device with the common alloc_etherdev.
>> Unfortunately the register_netdev registers a new eth interface in my
>> case, and this interface is not connected to the wlan interface. I set
>> wireless_handlers and ieee80211_ptr for this device, still it is totally
>> independent from the wlan interface.
>>
>> Am I missing something? (Sorry if this is a trivial question, I tried
>> google but no luck so far)
>
> Your question doesn't make any sense. You never need wlan0/1, you only
> need alloc_hw/register_hw and then the interfaces will be managed by
> mac80211. You should post the code so people can help you.
>
> johannes
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: xeemu_wireless.c --]
[-- Type: text/x-csrc; name="xeemu_wireless.c", Size: 11117 bytes --]
/*
* linux/drivers/net/wireless/xeemu_wireless.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <net/mac80211.h>
#define DRV_MODULE_NAME "xeemu-wlan"
#define DRV_MODULE_VERSION "1.0"
#define MAX_PACKET_SIZE 1518
struct xeemu_hw_priv {
spinlock_t device_lock;
unsigned long base_addr;
int irq;
struct ieee80211_vif *vif;
struct ieee80211_channel *channel;
struct cfg80211_scan_request *req;
struct ieee80211_supported_band bands[2];
};
struct xeemu_vif_priv {
u8 bssid[ETH_ALEN];
bool assoc;
};
struct xeemu_sta_priv {
u32 dummy;
};
#define CHAN2G(_freq) { \
.band = IEEE80211_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_freq), \
.max_power = 20, \
}
#define CHAN5G(_freq) { \
.band = IEEE80211_BAND_5GHZ, \
.center_freq = (_freq), \
.hw_value = (_freq), \
.max_power = 20, \
}
static struct ieee80211_channel xeemu_channels_2ghz[] = {
CHAN2G(2412), /* Channel 1 */
CHAN2G(2417), /* Channel 2 */
CHAN2G(2422), /* Channel 3 */
CHAN2G(2427), /* Channel 4 */
CHAN2G(2432), /* Channel 5 */
CHAN2G(2437), /* Channel 6 */
CHAN2G(2442), /* Channel 7 */
CHAN2G(2447), /* Channel 8 */
CHAN2G(2452), /* Channel 9 */
CHAN2G(2457), /* Channel 10 */
CHAN2G(2462), /* Channel 11 */
CHAN2G(2467), /* Channel 12 */
CHAN2G(2472), /* Channel 13 */
CHAN2G(2484), /* Channel 14 */
};
static struct ieee80211_channel xeemu_channels_5ghz[] = {
CHAN5G(5180), /* Channel 36 */
CHAN5G(5200), /* Channel 40 */
CHAN5G(5220), /* Channel 44 */
CHAN5G(5240), /* Channel 48 */
CHAN5G(5260), /* Channel 52 */
CHAN5G(5280), /* Channel 56 */
CHAN5G(5300), /* Channel 60 */
CHAN5G(5320), /* Channel 64 */
CHAN5G(5500), /* Channel 100 */
CHAN5G(5520), /* Channel 104 */
CHAN5G(5540), /* Channel 108 */
CHAN5G(5560), /* Channel 112 */
CHAN5G(5580), /* Channel 116 */
CHAN5G(5600), /* Channel 120 */
CHAN5G(5620), /* Channel 124 */
CHAN5G(5640), /* Channel 128 */
CHAN5G(5660), /* Channel 132 */
CHAN5G(5680), /* Channel 136 */
CHAN5G(5700), /* Channel 140 */
CHAN5G(5745), /* Channel 149 */
CHAN5G(5765), /* Channel 153 */
CHAN5G(5785), /* Channel 157 */
CHAN5G(5805), /* Channel 161 */
CHAN5G(5825), /* Channel 165 */
};
static struct ieee80211_rate xeemu_rates[] = {
{ .bitrate = 10 },
{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 60 },
{ .bitrate = 90 },
{ .bitrate = 120 },
{ .bitrate = 180 },
{ .bitrate = 240 },
{ .bitrate = 360 },
{ .bitrate = 480 },
{ .bitrate = 540 }
};
// ----------------------------------------------------------------------
static void xeemu_rx(struct ieee80211_hw *hw, int packet_length)
{
int i;
unsigned long flags;
struct sk_buff *skb;
char buf[MAX_PACKET_SIZE];
struct xeemu_hw_priv *hp = hw->priv;
struct ieee80211_rx_status rx_status;
spin_lock_irqsave(&hp->device_lock, flags);
for (i = 0; i < packet_length; ++i) {
outl(1, hp->base_addr + 4);
buf[i] = inl(hp->base_addr + 4);
}
spin_unlock_irqrestore(&hp->device_lock, flags);
memset(&rx_status, 0, sizeof(rx_status));
rx_status.freq = hp->channel->center_freq;
rx_status.band = hp->channel->band;
rx_status.signal = -50;
skb = dev_alloc_skb(packet_length + NET_IP_ALIGN);
if (unlikely(!skb))
return;
skb_reserve(skb, NET_IP_ALIGN);
memcpy(skb_put(skb, packet_length), buf, packet_length);
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
ieee80211_rx_irqsafe(hw, skb);
}
static int xeemu_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
int i;
unsigned long flags;
struct xeemu_hw_priv *hp = hw->priv;
struct ieee80211_tx_info *txi;
if (unlikely(skb->len > MAX_PACKET_SIZE)) {
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
spin_lock_irqsave(&hp->device_lock, flags);
outl(skb->len, hp->base_addr);
for (i = 0; i < skb->len; ++i)
outl(skb->data[i], hp->base_addr);
spin_unlock_irqrestore(&hp->device_lock, flags);
txi = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(txi);
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK))
txi->flags |= IEEE80211_TX_STAT_ACK;
printk(KERN_INFO "xeemu_tx: %d\n", skb->len);
dev_kfree_skb(skb);
return 0;
}
static int xeemu_tx_beacon(struct ieee80211_hw *hw)
{
struct xeemu_hw_priv *hp = hw->priv;
struct sk_buff *skb = ieee80211_beacon_get(hw, hp->vif);
if (!skb)
return -ENOMEM;
return xeemu_tx(hw, skb);
}
static irqreturn_t xeemu_irq(int irq, void *dev_instance)
{
struct ieee80211_hw *hw = (struct ieee80211_hw*)dev_instance;
struct xeemu_hw_priv *hp = hw->priv;
int packet_length;
if (hp->req)
ieee80211_scan_completed(hw, false);
while (true) {
// Check available packets
outl(0, hp->base_addr + 4);
packet_length = inl(hp->base_addr + 4);
if (!packet_length)
break;
xeemu_rx(hw, packet_length);
}
return IRQ_HANDLED;
}
static int xeemu_start(struct ieee80211_hw *hw)
{
int err;
struct xeemu_hw_priv *hp = hw->priv;
err = request_irq(hp->irq, xeemu_irq, IRQF_SHARED, "wlan", hw);
if (err)
return err;
spin_lock_init(&hp->device_lock);
return 0;
}
static void xeemu_stop(struct ieee80211_hw *hw)
{
struct xeemu_hw_priv *hp = hw->priv;
free_irq(hp->irq, hw);
}
static int xeemu_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct xeemu_hw_priv *hp = hw->priv;
hp->vif = conf->vif;
return 0;
}
static void xeemu_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
}
static int xeemu_config(struct ieee80211_hw *hw, u32 changed)
{
struct xeemu_hw_priv *hp = hw->priv;
hp->channel = hw->conf.channel;
printk(KERN_INFO "xeemu_config 0x%x\n", changed);
return 0;
}
static void xeemu_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u32 changed)
{
struct xeemu_vif_priv *vp = (void *)vif->drv_priv;
if (changed & BSS_CHANGED_BSSID)
memcpy(vp->bssid, info->bssid, ETH_ALEN);
if (changed & BSS_CHANGED_ASSOC)
vp->assoc = info->assoc;
printk(KERN_INFO "xeemu_bss_info_changed 0x%x\n", changed);
}
static void xeemu_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
*total_flags = *total_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI);
printk(KERN_INFO "xeemu_configure_filter 0x%x 0x%x\n", changed_flags, *total_flags);
}
static int xeemu_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req)
{
struct xeemu_hw_priv *hp = hw->priv;
if (hp->req)
return -EINVAL;
hp->req = req;
// ieee80211_scan_completed must be called
outl(5, hp->base_addr + 4);
return 0;
}
static int xeemu_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
return 0;
}
static void xeemu_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
{
}
static int xeemu_tx_last_beacon(struct ieee80211_hw *hw)
{
return 0;
}
static void xeemu_rfkill_poll(struct ieee80211_hw *hw)
{
}
static const struct ieee80211_ops xeemu_wireless_ops = {
.tx = xeemu_tx,
.start = xeemu_start,
.stop = xeemu_stop,
.add_interface = xeemu_add_interface,
.remove_interface = xeemu_remove_interface,
.config = xeemu_config,
.bss_info_changed = xeemu_bss_info_changed,
.configure_filter = xeemu_configure_filter,
.hw_scan = xeemu_hw_scan,
.set_rts_threshold = xeemu_set_rts_threshold,
.sta_notify = xeemu_sta_notify,
.tx_last_beacon = xeemu_tx_last_beacon,
.rfkill_poll = xeemu_rfkill_poll
};
// ----------------------------------------------------------------------
static int xeemu_wlan_probe(struct platform_device *pdev)
{
/* default mac address */
static uint8_t mac_addrs[2][6] = {
{ 0x00, 0xF5, 0x2A, 0x10, 0x71, 0x00 },
{ 0x00, 0xF5, 0x2A, 0x15, 0xB2, 0x01 },
};
int i, band, err;
struct resource* resource;
struct ieee80211_hw *hw;
struct xeemu_hw_priv *hp;
unsigned long base_addr;
int irq;
resource = pdev->resource;
for (i = 0; i < (pdev->num_resources >> 1); i++) {
irq = resource->start;
resource++;
base_addr = resource->start;
resource++;
// Query the client_id based mac addr
outl(2, base_addr + 4);
mac_addrs[i][5] = inl(base_addr + 4);
hw = ieee80211_alloc_hw(sizeof(struct xeemu_hw_priv), &xeemu_wireless_ops);
if (hw == NULL) {
dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
return -ENOMEM;
}
SET_IEEE80211_DEV(hw, &pdev->dev);
platform_set_drvdata(pdev, hw);
hw->channel_change_time = 1;
hw->queues = 4;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT);
hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct xeemu_vif_priv);
hw->sta_data_size = sizeof(struct xeemu_sta_priv);
SET_IEEE80211_PERM_ADDR(hw, mac_addrs[i]);
hp = hw->priv;
hp->base_addr = base_addr;
hp->irq = irq;
hp->req = NULL;
for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband = &hp->bands[band];
switch (band) {
case IEEE80211_BAND_2GHZ:
sband->channels = xeemu_channels_2ghz;
sband->n_channels = ARRAY_SIZE(xeemu_channels_2ghz);
sband->bitrates = xeemu_rates;
sband->n_bitrates = ARRAY_SIZE(xeemu_rates);
break;
case IEEE80211_BAND_5GHZ:
sband->channels = xeemu_channels_5ghz;
sband->n_channels = ARRAY_SIZE(xeemu_channels_5ghz);
sband->bitrates = xeemu_rates + 4;
sband->n_bitrates = ARRAY_SIZE(xeemu_rates) - 4;
}
sband->ht_cap.ht_supported = false;
hw->wiphy->bands[band] = sband;
}
err = ieee80211_register_hw(hw);
if (err < 0) {
ieee80211_free_hw(hw);
dev_err(&pdev->dev, "cannot register ieee80211_hw (%d)\n", err);
return err;
}
printk(KERN_INFO "xeemu wlan%d (irq: %d base: 0x%lx mac[5]: %d) registered\n", i, irq, base_addr, mac_addrs[i][5]);
}
return 0;
}
static int __devexit xeemu_wlan_remove(struct platform_device *pdev)
{
struct ieee80211_hw *hw;
hw = platform_get_drvdata(pdev);
if (hw == NULL)
return 0;
ieee80211_free_hw(hw);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver xeemu_wlan_driver = {
.probe = xeemu_wlan_probe,
.remove = __devexit_p(xeemu_wlan_remove),
.driver = {
.name = "xeemu_wireless",
.owner = THIS_MODULE,
},
};
static int __init xeemu_wlan_init_module(void)
{
return platform_driver_register(&xeemu_wlan_driver);
}
static void __exit xeemu_wlan_cleanup_module(void)
{
platform_driver_unregister(&xeemu_wlan_driver);
}
module_init(xeemu_wlan_init_module);
module_exit(xeemu_wlan_cleanup_module);
MODULE_LICENSE("GPL");
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: connecting ieee80211_hw and net_device
2010-11-11 14:20 ` Zoltan Herczeg
@ 2010-11-12 22:33 ` Zoltan Herczeg
2010-11-16 17:50 ` some questions Zoltan Herczeg
0 siblings, 1 reply; 5+ messages in thread
From: Zoltan Herczeg @ 2010-11-12 22:33 UTC (permalink / raw)
To: Zoltan Herczeg; +Cc: linux-wireless
Hi,
is the presp means probe response? In ibss.c, there is a pair of
functions: ieee80211_rx_mgmt_probe_req and ieee80211_rx_mgmt_probe_resp,
but both are for receiving such messages. Shall I create them like
b43legacy_generate_probe_resp?
Thanks in advance
Zoltan
> Hi,
>
> thanks for you reply. I was thinking and realized probably the
> alloc_etherdev() calls have a different purpose and removed them (and
> found an ieee80211_rx_irqsafe function, which pass the received messages
> to 80211). My plan is to run the network in ad-hoc mode (passing 1 to
> SIOCSIWMODE ioctl command). Unfortunately it is still not working, because
> rx.sta = sta_info_get(local, hdr->addr2) in rx.c returns with NULL, and
> the received messages are eventually dropped. I tried to understand the
> code, and I think messages called "beacons" are needed to make
> sta_info_get() work. These messages can be created by
> ieee80211_beacon_get, but it also returns with NULL in my case, because
> rcu_dereference(ifibss->presp) returns with NULL. Could you help me?
>
> The code is attached to this mail.
>
> Thanks in advance,
> Zoltan
>
>> On Tue, 2010-11-09 at 21:31 +0100, Zoltan Herczeg wrote:
>>
>>> I can allocate a "wlan0" and "wlan1" platform device with
>>> ieee80211_alloc_hw, and can initialize it in Ad-Hoc mode. However, I
>>> realized this is not enough to have a wireless interface, since it has
>>> no
>>> receive operation, only transfer. Looking at the other drivers, I found
>>> that they allocate a net_device with the common alloc_etherdev.
>>> Unfortunately the register_netdev registers a new eth interface in my
>>> case, and this interface is not connected to the wlan interface. I set
>>> wireless_handlers and ieee80211_ptr for this device, still it is
>>> totally
>>> independent from the wlan interface.
>>>
>>> Am I missing something? (Sorry if this is a trivial question, I tried
>>> google but no luck so far)
>>
>> Your question doesn't make any sense. You never need wlan0/1, you only
>> need alloc_hw/register_hw and then the interfaces will be managed by
>> mac80211. You should post the code so people can help you.
>>
>> johannes
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* some questions
2010-11-12 22:33 ` Zoltan Herczeg
@ 2010-11-16 17:50 ` Zoltan Herczeg
0 siblings, 0 replies; 5+ messages in thread
From: Zoltan Herczeg @ 2010-11-16 17:50 UTC (permalink / raw)
To: linux-wireless
Hi,
I have finished my work on the diver for the simulator, and it works fine.
I am still wondering about some questions, though:
1) can I set the bssid of an ad-hoc network (using ioctl or netlink)? The
bssid is generated by get_random_bytes in mac80211/ibss.c, and if two
devices start the join in the same time (in ms), they will create
different bssids, even if their ssid are the same (another solution: the
bssid could be generated by a hash function from the ssid).
2) if we have two networks, with the same ibss ssid but different bssid,
and all nodes are brought to the same place (they can communicate with
each other now, which was not possible before), how would be the two
networks merge into one, which use the same bssid? How much time does it
need?
Regards,
Zoltan
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-11-16 17:50 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-11-09 20:31 connecting ieee80211_hw and net_device Zoltan Herczeg
2010-11-10 0:26 ` Johannes Berg
2010-11-11 14:20 ` Zoltan Herczeg
2010-11-12 22:33 ` Zoltan Herczeg
2010-11-16 17:50 ` some questions Zoltan Herczeg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).