Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [RFC PATCH] b43: Implement LP-PHY baseband table initialization
From: Michael Buesch @ 2009-08-10 17:19 UTC (permalink / raw)
  To: Gábor Stefanik
  Cc: John Linville, Larry Finger, Johannes Berg, Broadcom Wireless,
	linux-wireless
In-Reply-To: <200908101452.50072.mb@bu3sch.de>

On Monday 10 August 2009 14:52:49 Michael Buesch wrote:
> On Monday 10 August 2009 14:49:31 Gábor Stefanik wrote:
> > 2009/8/10 Michael Buesch <mb@bu3sch.de>:
> > > On Monday 10 August 2009 03:00:46 Gábor Stefanik wrote:
> > >> +static const u16 lpphy_sw_control_table[] = {
> > >> +     0x0128,
> > >> +     0x0128,
> > >> +     0x0009,
> > >> +     0x0009,
> > >> +     0x0028,
> > >> +     0x0028,
> > >
> > > Is it possible to use more than one value per line for all these tables?
> > > Make sure to make best use of the 80 columns limit.
> > > This would significantly decrease the patch/file length. (linewise)
> > >
> > > --
> > > Greetings, Michael.
> > >
> > 
> > Well, I converted the tables directly from the Wikitext on
> > bcm-v4.sipsolutions.net using regex search&replace - if you know a
> > good regex to convert the tables to use multiple values on each line,
> > please post it.
> > 
> 
> I have some hacky python scripts to parse and reformat these tables.
> I will post them in a few hours. I'll have to leave now. brb.
> 

Hm, I don't seem to have the scripts anymore. But python re is fairly simple.
Here's a hacky script to parse a table, perform some transformations on it and
print out the C defines:

#!/usr/bin/env python

import re
import sys

d = file(sys.argv[1]).readlines()


for line in d:
	r = re.compile(r"\|\| `0x([0-9A-Fa-f]+)` \|\| ([\w\s\(\)/]+) \|\|")
	m = r.match(line)
	if m:
		offset = int(m.group(1), 16)
		name = m.group(2)
		name = name.replace("workAround", "workaround")

		origname = name

		name = name.replace("(", " ")
		name = name.replace(")", " ")

		name = name.upper()
		name = name.strip()

		name = name.replace(" ", "_")
		name = name.replace("/", "_")
		name = name.replace("CONTROL", "CTL")
		name = name.replace("COMMON", "COMM")
		name = name.replace("CALIBRATION", "CALIB")
		name = name.replace("DEBUG", "DBG")
		name = name.replace("COUNTER", "CNT")
		name = name.replace("POWER", "PWR")
		name = name.replace("B_PHY", "B")
		name = name.replace("ADDRESS", "ADDR")
		name = name.replace("OUT_ENABLE", "OUTEN")
		name = name.replace("THRESHOLD", "THRES")
		name = name.replace("STATUS", "STAT")
		name = name.replace("COEFFICIENT", "COEFF")
		name = name.replace("INTERVAL", "INT")
		name = name.replace("TIMEOUT", "TO")
		name = name.replace("VALUE", "VAL")
		name = name.replace("SAMPLE", "SMPL")

		name = "B43_LPPHY_" + name

		nr_tabs = 5 - (len(name) / 8)
		tabs = "\t" * nr_tabs

		comment = origname

		if (offset & 0x400):
			accessor = "B43_PHY_OFDM"
		else:
			accessor = "B43_PHY_CCK"
		offset &= ~0x400;
		if (offset & ~0xFF):
			print "offset ERROR %X" % offset
			sys.exit(1)
		sys.stdout.write("#define %s%s%s(0x%02X)" % (name, tabs, accessor, offset))
		if comment:
			sys.stdout.write(" /* %s */" % comment)
		sys.stdout.write("\n")
	else:
		pass
		print "NO match " + line

-- 
Greetings, Michael.

^ permalink raw reply

* Re: [PATCH] cfg80211: fix locking for SIWFREQ
From: reinette chatre @ 2009-08-10 16:55 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, Kalle Valo, linux-wireless
In-Reply-To: <1249722238.31670.17.camel@johannes.local>

On Sat, 2009-08-08 at 02:03 -0700, Johannes Berg wrote:
> "cfg80211: validate channel settings across interfaces"
> contained a locking bug -- in the managed-mode SIWFREQ
> call it would end up running into a lock recursion.
> 
> This fixes it by not checking that particular interface
> for a channel that it needs to stay on, which is as it
> should be as that's the interface we're setting the
> channel for.
> 
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Reported-by: Kalle Valo <kalle.valo@iki.fi>
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

Not sure if this is still needed, but for completeness:

Tested-by: Reinette Chatre <reinette.chatre@intel.com>

Thank you very much

Reinette



^ permalink raw reply

* Re: [PATCH] cfg80211: Set WEP ciphers
From: Dan Williams @ 2009-08-10 16:49 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: John W. Linville, Zhu, Yi, Johannes Berg, linux-wireless
In-Reply-To: <20090810090447.GA5421@sortiz.org>

On Mon, 2009-08-10 at 11:04 +0200, Samuel Ortiz wrote:
> Hi Dan,
> 
> On Fri, Aug 07, 2009 at 04:36:22PM -0500, Dan Williams wrote:
> > On Thu, 2009-08-06 at 21:04 +0200, Samuel Ortiz wrote:
> > > With iwconfig there is no way to properly set the ciphers when trying to
> > > connect to a WEP SSID. Although mac80211 based drivers dont need it, several
> > > fullmac drivers do.
> > > This patch basically sets the WEP ciphers whenever they're not set at all.
> > 
> > If you're talking about Dynamic WEP, that's what wpa_supplicant is for,
> > it will handle setting the ciphers through SIOCSIWENCODEEXT.
> No, I'm not talking about dynamic WEP, but rather about "iwconfig wlan0 key
> your_static_key".
> 
> 
> > If you're talking about static WEP, then the ciphers are determined by
> > the WEP keys that have been set with iwconfig, and you determine
> > WEP40/WEP104 based on the length of the current WEP TX index.
> In theory, yes, but our driver's UMAC wants to get the key cipher before
> having actually set the keys, and with the latest key handling rework we get
> our connect() handler called before keys are actually set.
> 
> 
> > You should *not* be trying to do Dynamic WEP via iwconfig (which it
> > seems is what you're doing below?)
> No, that's not what we're trying to do.

Thanks for the explanation, sorry for the noise then.

Dan

> Cheers,
> Samuel.
> 
> 
> > Dan
> > 
> > > Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> > > ---
> > >  net/wireless/sme.c |   18 ++++++++++++++++--
> > >  1 files changed, 16 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/net/wireless/sme.c b/net/wireless/sme.c
> > > index 8a7dcbf..b78a111 100644
> > > --- a/net/wireless/sme.c
> > > +++ b/net/wireless/sme.c
> > > @@ -638,14 +638,28 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
> > >  
> > >  	if (connkeys && connkeys->def >= 0) {
> > >  		int idx;
> > > +		u32 cipher;
> > >  
> > >  		idx = connkeys->def;
> > > +		cipher = connkeys->params[idx].cipher;
> > >  		/* If given a WEP key we may need it for shared key auth */
> > > -		if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
> > > -		    connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
> > > +		if (cipher == WLAN_CIPHER_SUITE_WEP40 ||
> > > +		    cipher == WLAN_CIPHER_SUITE_WEP104) {
> > >  			connect->key_idx = idx;
> > >  			connect->key = connkeys->params[idx].key;
> > >  			connect->key_len = connkeys->params[idx].key_len;
> > > +
> > > +			/*
> > > +			 * If ciphers are not set (e.g. when going through
> > > +			 * iwconfig), we have to set them appropriately here.
> > > +			 */
> > > +			if (connect->crypto.cipher_group == 0)
> > > +				connect->crypto.cipher_group = cipher;
> > > +
> > > +			if (connect->crypto.n_ciphers_pairwise == 0) {
> > > +				connect->crypto.n_ciphers_pairwise = 1;
> > > +				connect->crypto.ciphers_pairwise[0] = cipher;
> > > +			}					
> > >  		}
> > >  	}
> > >  
> > > -- 
> > > 1.6.3.1
> > > 
> > 
> 


^ permalink raw reply

* Re: [PATCH 2.6.30] iwl3945: fix rfkill switch
From: reinette chatre @ 2009-08-10 16:44 UTC (permalink / raw)
  To: Stanislaw Gruszka
  Cc: linux-wireless@vger.kernel.org, Zhu, Yi, John W. Linville,
	stable@kernel.org
In-Reply-To: <20090807063141.GA2523@dhcp-lab-161.englab.brq.redhat.com>

Hi Stanislaw,

On Thu, 2009-08-06 at 23:31 -0700, Stanislaw Gruszka wrote:
> On Thu, Aug 06, 2009 at 01:15:58PM -0700, reinette chatre wrote:
> > On Thu, 2009-08-06 at 00:19 -0700, Stanislaw Gruszka wrote:
> > > On Wed, Aug 05, 2009 at 03:51:49PM -0700, reinette chatre wrote:
> > > > On Tue, 2009-08-04 at 05:35 -0700, Stanislaw Gruszka wrote:
> > > > > Due to rfkill and iwlwifi mishmash of SW / HW killswitch representation,
> > > > > we have race conditions which make unable turn wifi radio on, after enable
> > > > > and disable again killswitch. I can observe this problem on my laptop
> > > > > with iwl3945 device.
> > > > > 
> > > > > In rfkill core HW switch and SW switch are separate 'states'. Device can
> > > > > be only in one of 3 states: RFKILL_STATE_SOFT_BLOCKED, RFKILL_STATE_UNBLOCKED,
> > > > > RFKILL_STATE_HARD_BLOCKED. Whereas in iwlwifi driver we have separate bits
> > > > > STATUS_RF_KILL_HW and STATUS_RF_KILL_SW for HW and SW switches - radio can be
> > > > > turned on, only if both bits are cleared.
> > > > > 
> > > > > In this particular race conditions, radio can not be turned on if in driver
> > > > > STATUS_RF_KILL_SW bit is set, and rfkill core is in state
> > > > > RFKILL_STATE_HARD_BLOCKED, because rfkill core is unable to call
> > > > > rfkill->toggle_radio(). This situation can be entered in case:
> > > > > 
> > > > 
> > > > I am trying to understand this race condition ...
> > > > 
> > > > > - killswitch is turned on
> > > > > - rfkill core 'see' button change first and move to RFKILL_STATE_SOFT_BLOCKED
> > > > >   also call ->toggle_radio() and STATE_RF_KILL_SW in driver is set
> > > > > - iwl3945 get info about button from hardware to set STATUS_RF_KILL_HW bit and
> > > > >   force rfkill to move to RFKILL_STATE_HARD_BLOCKED
> > > > 
> > > > ok - so at this point we have rfkill == RFKILL_STATE_HARD_BLOCKED, and
> > > > driver == STATE_RF_KILL_SW | STATE_RF_KILL_HW
> > > > 
> > > > > - killsiwtch is turend off
> > > 
> > > Here rfkill core routines are called. Rfkill wants to clear STATUS_RF_KILL_SW
> > > but it can not as state is RFKILL_STATE_HARD_BLOCKED.
> > > 
> > > > > - driver clear STATUS_RF_KILL_HW
> > > > 
> > > > at this point the driver should clear STATE_RF_KILL_HW and then call
> > > > iwl_rfkill_set_hw_state(). From what I can tell, in
> > > > iwl_rfkill_set_hw_state() the test for iwl_is_rfkill_sw() will cause the
> > > > driver to call rfkill_force_state for RFKILL_STATE_SOFT_BLOCKED
> > > > 
> > > > So, from what I understand after the above the status will be
> > > > 
> > > > rfkill == RFKILL_STATE_SOFT_BLOCKED, and driver == STATE_RF_KILL_SW 
> > > 
> > > Thats right. But rfkill core no longer wants to manipulate state via
> > > ->toggle_radio() and radio stays disabled.
> > >  
> > > > > - rfkill core is unable to clear STATUS_RF_KILL_SW in driver
> > > > 
> > > > I do not understand why this is a problem here. Could you please
> > > > highlight what I am missing?
> > > 
> > > In my description I miss the most important part, sorry. Race is when the
> > > switches are performed in that order:
> > > 
> > > Radio enabled 
> > > - rfkill SW on
> > > - driver HW on
> > > Radio disabled - ok
> > > - rfkill SW off <- problem not clearing STATUS_RF_KILL_SW

Yes. I assume that what happens here is that rfkill notifies user that
state changes to RFKILL_STATE_UNBLOCKED. In your new patch the driver
will now clear STATUS_RF_KILL_SW, with STATUS_RF_KILL_HW still being
set. So, in this run, after iwl_rfkill_soft_rf_kill is called there will
be a state mismatch with rfkill thinking the system is unblocked while
the driver has it as hard blocked. This is not right.

Can this be fixed by adding a iwl_rfkill_set_hw_state in this run?

> > > - driver HW off
> > > Radio disabled - wrong 
> > > 
> > > Everything is fine when actions are in that order:
> > > 
> > > Radio enabled
> > > - rfkill SW on
> > > - driver HW on
> > > Radio disabled - ok 
> > > - driver HW off
> > > - rfkill SW off
> > > Radio enabled - ok 
> > 
> > 
> > Thanks for the explanation.
> > 
> > > 
> > > > > 
> > > > > Additionally call to rfkill_epo() when STATUS_RF_KILL_HW in driver is set
> > > > > cause move to the same situation.
> > > > > 
> > > > > In 2.6.31 this problem is fixed due to _total_ rewrite of rfkill subsystem.
> > > > > This is a quite small fix for 2.6.30.x in iwl3945 driver. We disable
> > > > > STATUS_RF_KILL_SW bit regardless of HW bit state. Also report to rfkill
> > > > > subsystem SW switch bit before HW switch bit to move rfkill subsystem
> > > > > to SOFT_BLOCK rather than HARD_BLOCK.
> > > > > 
> > > > > Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
> > > > > ---
> > > > > I'm not sure if this is good candidate for stable as this is not backport
> > > > > of upstream commit. Also I did not test this patch with other iwlwifi devices,
> > > > > only with iwl3945.
> > > > > 
> > > > >  drivers/net/wireless/iwlwifi/iwl-rfkill.c |   24 ++++++++++++++----------
> > > > >  1 files changed, 14 insertions(+), 10 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
> > > > > index 2ad9faf..d6b6098 100644
> > > > > --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c
> > > > > +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
> > > > > @@ -54,21 +54,28 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
> > > > >  	case RFKILL_STATE_UNBLOCKED:
> > > > >  		if (iwl_is_rfkill_hw(priv)) {
> > > > >  			err = -EBUSY;
> > > > > -			goto out_unlock;
> > > > > +			/* pass error to rfkill core to make it state HARD
> > > > > +			 * BLOCKED and disable software kill switch */
> > > > >  		}
> > > > >  		iwl_radio_kill_sw_enable_radio(priv);
> > > > >  		break;
> > > > >  	case RFKILL_STATE_SOFT_BLOCKED:
> > > > >  		iwl_radio_kill_sw_disable_radio(priv);
> > > > > +		/* rfkill->mutex lock is taken */
> > > > > +		if (priv->rfkill->state == RFKILL_STATE_HARD_BLOCKED) {
> > > > > +			/* force rfkill core state to be SOFT BLOCKED,
> > > > > +			 * otherwise core will be unable to disable software
> > > > > +			 * kill switch */
> > > > > +			priv->rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
> > > > > +		}
> > > > 
> > > > I understand that you are directly changing the rfkill internals because
> > > > the mutex is taken ... but this really does not seem right to directly
> > > > modify the rfkill state in this way.
> > > 
> > > Agree this is dirty hack, but I did not find a better way. Eventually,
> > > if we add call to rfkill_uevent(), this would behave the same
> > > as rfkill_force_state() .
> > 
> > Sorry, but I really do not understand why this code is needed. From what
> > you say rfkill can be in one of three states: RFKILL_STATE_UNBLOCKED,
> > RFKILL_STATE_SOFT_BLOCKED, or RFKILL_STATE_HARD_BLOCKED. From what I
> > understand the above code is called when there is an rfkill state change
> > and the new state is provided. So, only _one_ of the three states will
> > be provided as parameter. This state is then tested - so in the case
> > that you modified here the state has already been tested to be
> > RFKILL_STATE_SOFT_BLOCKED. How is it thus possible that it can be
> > RFKILL_STATE_HARD_BLOCKED also?
> 
> Local variable state != priv->rfkill->state . See rfkill_toggle_radio()
> especially this part:
> 
> 	if (force || state != rfkill->state) {
> 		retval = rfkill->toggle_radio(rfkill->data, state);
> 		/* never allow a HARD->SOFT downgrade! */

This comment makes me even more concerned about this patch. It
explicitly states "never allow a HARD->SOFT downgrade!" and that is what
your patch now seems to do.

> 		if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
> 			rfkill->state = state;
> 	}
> 
> Without the change rfkill core will be in state RFKILL_STATE_HARD_BLOCKED and
> latter will not clear STATE_RF_KILL_SW.
>  
> All hunks from the patch are needed on my laptop (lenoveo T60) to make
> killswitch works as expected. Applying only some hunks from the patch helps
> is one case or other, but without all hunks there is still possible to have
> radio disabled when killswitch is off.

>From what I can tell this patch introduced a disagreement of rfkill
state between driver and rfkill system. Maybe if we can sort this out we
do not need all these hunks?

Reinette



^ permalink raw reply

* Re: [PATCH] Document pci_ids.h addition policy.
From: Jesse Barnes @ 2009-08-10 16:28 UTC (permalink / raw)
  To: Dave Jones
  Cc: Greg KH, Marcel Holtmann, Luis R. Rodriguez, linville,
	linux-kernel, linux-wireless, zhifeng.cai, stephen.chen,
	linux-usb, jbarnes
In-Reply-To: <20090806191359.GA4345@redhat.com>

On Thu, 6 Aug 2009 15:13:59 -0400
Dave Jones <davej@redhat.com> wrote:

> On Thu, Aug 06, 2009 at 11:33:26AM -0700, Greg Kroah-Hartman wrote:
>  
>  > > I agree. In fact, I'd go further, and say that the bulk of what
>  > > we have in pci_ids.h is also pointlessly shared. Only a tiny
>  > > fraction of the device entries in that file are used by multiple
>  > > files in the kernel.
>  > 
>  > I agree with that as well, which is why when I was PCI maintainer,
>  > I didn't allow any new additions to the pci_ids.h file, unless it
>  > was going to be an id that was shared by different drivers.  That
>  > cut the new additions down to about none :)
> 
> Perhaps documenting this is a good idea to prevent things being moved
> there, as it still seems to be happening judging from the git log.
> 
> Signed-off-by: Dave Jones <davej@redhat.com>
>  
> diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> index 73b46b6..f9156fd 100644
> --- a/include/linux/pci_ids.h
> +++ b/include/linux/pci_ids.h
> @@ -2,6 +2,9 @@
>   *	PCI Class, Vendor and Device IDs
>   *
>   *	Please keep sorted.
> + *
> + *	Do not add new entries to this file unless the definitions
> + *	are shared between multiple drivers.
>   */
>  
>  /* Device classes and subclasses */
> 

Applied to linux-next, thanks.  I'll try to be more strict about this
too (I've reminded a few people of this informal policy already).

-- 
Jesse Barnes, Intel Open Source Technology Center

^ permalink raw reply

* Re: [PATCH] cfg80211: add missing device list locking
From: Kalle Valo @ 2009-08-10 16:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, linux-wireless
In-Reply-To: <1249811489.4636.2.camel@johannes.local>

Johannes Berg <johannes@sipsolutions.net> writes:

> When calling into the wext code from the NETDEV_UP
> notifier, we need to hold the devlist_mtx mutex as
> the wext code ends up calling into channel checks.
>
> Reported-by: Kalle Valo <kalle.valo@iki.fi>
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

I have been testing with patch for a day now and no warnings anymore.

Tested-by: Kalle Valo <kalle.valo@iki.fi>

-- 
Kalle Valo

^ permalink raw reply

* Re: wireless regressions -- Re: 2.6.31-rc5-git5: Reported regressions from 2.6.30
From: Bob Copeland @ 2009-08-10 16:04 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: John W. Linville, Fabio Comolli, Rafael J. Wysocki,
	Linux Wireless List
In-Reply-To: <43e72e890908100850v1cbb4252j3136245ba4d316b6@mail.gmail.com>

On Mon, Aug 10, 2009 at 11:50 AM, Luis R. Rodriguez<mcgrof@gmail.com> wrote:
> On Mon, Aug 10, 2009 at 8:04 AM, John W. Linville<linville@tuxdriver.com> wrote:
>> On Sun, Aug 09, 2009 at 10:36:49PM +0200, Rafael J. Wysocki wrote:
>>> This message contains a list of some regressions from 2.6.30, for which there
>>> are no fixes in the mainline I know of.  If any of them have been fixed already,
>>> please let me know.
>>
>> Wireless-related ones...
>
> Some notes on some of these.
>
>>> Unresolved regressions
>>> ----------------------
>>
>>> Bug-Entry     : http://bugzilla.kernel.org/show_bug.cgi?id=13947
>>> Subject               : Libertas: Association request to the driver failed
>>> Submitter     : Daniel Mack <daniel@caiaq.de>
>>> Date          : 2009-08-07 19:11 (3 days old)
>>> First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=57921c312e8cef72ba35a4cfe870b376da0b1b87
>>> References    : http://marc.info/?l=linux-kernel&m=124967234311481&w=4
>>> Handled-By    : Roel Kluin <roel.kluin@gmail.com>
>>>
>>>
>>> Bug-Entry     : http://bugzilla.kernel.org/show_bug.cgi?id=13943
>>> Subject               : WARNING: at net/mac80211/mlme.c:2292 with ath5k
>>> Submitter     : Fabio Comolli <fabio.comolli@gmail.com>
>>> Date          : 2009-08-06 20:15 (4 days old)
>>> References    : http://marc.info/?l=linux-kernel&m=124958978600600&w=4
>
> As I noted earlier this comes from the fact that a driver or mac80211
> is queuing work onto the mac80211 workqueue when we already ran the
> mac80211 suspend callbacks and we haven't yet resumed. There have been
> several fixes for these, for both drivers and mac80211. We've already
> pushed them to wireless-testing but I do not recall which ones have
> been propagated to 2.6.31 as fixes.

This is on my todo and I haven't looked into this very hard yet,
but afaik ath5k doesn't (directly) use the mac80211 workqueue, so
my guess in Fabio's case would be further up the stack.

-- 
Bob Copeland %% www.bobcopeland.com

^ permalink raw reply

* Re: [RFC PATCH] b43: Implement LP-PHY baseband table initialization
From: Larry Finger @ 2009-08-10 16:02 UTC (permalink / raw)
  To: Gábor Stefanik
  Cc: John Linville, Michael Buesch, Johannes Berg, Broadcom Wireless,
	linux-wireless
In-Reply-To: <69e28c910908100842o6eecb131n50ff39fc48566880@mail.gmail.com>

Gábor Stefanik wrote:
> 2009/8/10 Larry Finger <Larry.Finger@lwfinger.net>:
>> Yes, that would work for the 2.4 GHz band, and I guess there could be
>> similar routines or macros to split the 5 GHz band into low, medium
>> and high channels.
> 
> AFAIK there is no need to do that - using current_band for 2GHz is
> specifically to ensure that channels in the 2500...3000MHz range don't
> get parsed as 5GHz. There is currently no band above 5GHz used for
> wlan, so this problem can't show up on 5GHz.

OK.

> I'm gonna re-submit this as a formal patch soon.

Good.

I just noticed that
http://bcm-v4.sipsolutions.net/802.11/PHY/LP/Calibration is
incomplete. I'll work on that next.

Larry


^ permalink raw reply

* Re: wireless regressions -- Re: 2.6.31-rc5-git5: Reported regressions from 2.6.30
From: Luis R. Rodriguez @ 2009-08-10 15:50 UTC (permalink / raw)
  To: John W. Linville, Fabio Comolli, Rafael J. Wysocki; +Cc: Linux Wireless List
In-Reply-To: <20090810150455.GB2733@tuxdriver.com>

On Mon, Aug 10, 2009 at 8:04 AM, John W. Linville<linville@tuxdriver.com> wrote:
> On Sun, Aug 09, 2009 at 10:36:49PM +0200, Rafael J. Wysocki wrote:
>> This message contains a list of some regressions from 2.6.30, for which there
>> are no fixes in the mainline I know of.  If any of them have been fixed already,
>> please let me know.
>
> Wireless-related ones...

Some notes on some of these.

>> Unresolved regressions
>> ----------------------
>
>> Bug-Entry     : http://bugzilla.kernel.org/show_bug.cgi?id=13947
>> Subject               : Libertas: Association request to the driver failed
>> Submitter     : Daniel Mack <daniel@caiaq.de>
>> Date          : 2009-08-07 19:11 (3 days old)
>> First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=57921c312e8cef72ba35a4cfe870b376da0b1b87
>> References    : http://marc.info/?l=linux-kernel&m=124967234311481&w=4
>> Handled-By    : Roel Kluin <roel.kluin@gmail.com>
>>
>>
>> Bug-Entry     : http://bugzilla.kernel.org/show_bug.cgi?id=13943
>> Subject               : WARNING: at net/mac80211/mlme.c:2292 with ath5k
>> Submitter     : Fabio Comolli <fabio.comolli@gmail.com>
>> Date          : 2009-08-06 20:15 (4 days old)
>> References    : http://marc.info/?l=linux-kernel&m=124958978600600&w=4

As I noted earlier this comes from the fact that a driver or mac80211
is queuing work onto the mac80211 workqueue when we already ran the
mac80211 suspend callbacks and we haven't yet resumed. There have been
several fixes for these, for both drivers and mac80211. We've already
pushed them to wireless-testing but I do not recall which ones have
been propagated to 2.6.31 as fixes.

So we have two options, we either treat all these as real issues for
2.6.31 and try to backport all related fixes, or we downgrade this
warning to just bail out. The problem with debugging these issues
as-is on 2.6.31 is that the caller which queued the work remains
invisible to the trace from the warning -- the warning comes from the
workqueue callback not the routine which ran queue_work(). This was
recently changed in wireless-testing and we now issue the warnings
from the callers of queue_work() for the mac80211 workqueue so we
*can* easily see the root cause to the issue and easily fix this.

We can surely fix this issue alone but we're sure bound to see this
warning later from other buggy drivers/mac80211 on 2.6.31 so we do
need to address how we want to address this issue as a whole for
2.6.31.

Fabio to help iron out this issue can you please use wireless-testing,
use IBSS as you were and go through the suspend-resume cycle to see if
you see a new warning with ath5k.

>> Regressions with patches
>> ------------------------
>>
>> Bug-Entry     : http://bugzilla.kernel.org/show_bug.cgi?id=13948
>> Subject               : ath5k broken after suspend-to-ram
>> Submitter     : Johannes Stezenbach <js@sig21.net>
>> Date          : 2009-08-07 21:51 (3 days old)
>> References    : http://marc.info/?l=linux-kernel&m=124968192727854&w=4
>> Handled-By    : Nick Kossifidis <mickflemm@gmail.com>
>> Patch         : http://patchwork.kernel.org/patch/38550/

This bug report status is now RESOLVED PATCH_ALREADY_AVAILABLE .

  Luis

^ permalink raw reply

* Re: [RFC PATCH] b43: Implement LP-PHY baseband table initialization
From: Gábor Stefanik @ 2009-08-10 15:42 UTC (permalink / raw)
  To: Larry Finger
  Cc: John Linville, Michael Buesch, Johannes Berg, Broadcom Wireless,
	linux-wireless
In-Reply-To: <4A8034D4.5030909@lwfinger.net>

2009/8/10 Larry Finger <Larry.Finger@lwfinger.net>:
> Gábor Stefanik wrote:
>> 2009/8/10 Larry Finger <Larry.Finger@lwfinger.net>:
>>> Gábor Stefanik wrote:
>>>> Implement LP-PHY baseband table init for all revisions.
>>>>
>>>> Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
>>>>
>>>> ---
>>>> Sorry for the size; it's difficult to cut short changes like this
>>>> (most of the patch is just table data). Please review, there may always be
>>>> bugs that I failed to catch while reading through the code. I have added
>>>> comments to places that were not quite clear to me.
>>>>
>>>> phy_lp.c       |   41 tables_lpphy.c | 3223
>>>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>> tables_lpphy.h |    3 3 files changed, 3263 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/net/wireless/b43/phy_lp.c
>>>> b/drivers/net/wireless/b43/phy_lp.c
>>>> index 27eadee..cf17489 100644
>>>> --- a/drivers/net/wireless/b43/phy_lp.c
>>>> +++ b/drivers/net/wireless/b43/phy_lp.c
>>>> @@ -59,9 +59,43 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
>>>>     dev->phy.lp = NULL;
>>>> }
>>>>
>>>> +static void lpphy_adjust_gain_table(struct b43_wldev *dev)
>>>> +{
>>>> +    struct b43_phy_lp *lpphy = dev->phy.lp;
>>>> +    u32 freq = dev->wl->hw->conf.channel->center_freq;
>>>> +    u16 temp[3];
>>>> +    u16 isolation;
>>>> +
>>>> +    B43_WARN_ON(dev->phy.rev >= 2);
>>>> +
>>>> +    if (freq < 2400) /* FIXME Can this ever happen? Should we WARN_ON? */
>>> This was a typo. It should be 2500, not 2400.
>>
>> Thanks! So it is actually better to implement this as "if
>> (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)"? That would make
>> it easier to implement non-standard channels similar to how it was
>> done for ath5k (Richard Farina's frequency patch - assuming the HW is
>> capable of something like that).
>
> Yes, that would work for the 2.4 GHz band, and I guess there could be
> similar routines or macros to split the 5 GHz band into low, medium
> and high channels.

AFAIK there is no need to do that - using current_band for 2GHz is
specifically to ensure that channels in the 2500...3000MHz range don't
get parsed as 5GHz. There is currently no band above 5GHz used for
wlan, so this problem can't show up on 5GHz.

>
>>>> +        isolation = lpphy->tx_isolation_med_band;
>>>> +    else if (freq <= 5320)
>>> --snip --
>>>
>>>> +void lpphy_rev2plus_table_init(struct b43_wldev *dev)
>>>> +{
>>>> +    struct ssb_bus *bus = dev->dev->bus;
>>>> +    int i;
>>>> +
>>>> +    B43_WARN_ON(dev->phy.rev < 2);
>>>> +
>>>> +    //XXX should this be done using b43_lptab_write_bulk?
>>>> +    for (i = 0; i < 704; i++)
>>>> +        b43_lptab_write(dev, B43_LPTAB32(7, i), 0);
>>> No. The bulk write is for writing tables with length greater than 1.
>>> In this case, you have 704 different tables each of length 1.
>>
>> By the way, looking at the implementation again, it looks a bit fishy
>> to me - we write zeros to 4 bytes of table ID 7, then increase the
>> offset by 1 byte, and again write 4 bytes - 3 of which are the same
>> bytes we already zeroed in the previous step.
>>
>> I suspect this would suffice:
>>
>> for (i = 0; i < 704; i += 4)
>>            b43_lptab_write(dev, B43_LPTAB32(7, i), 0);
>>
>> This version cuts the write count in half, and removes redundant byte writes.
>>
>> Maybe this should be tested once the code is functional.
>
> Without knowing what the firmware does with these values, I'm not sure
> that the two steps are equivalent, but that can be tested. I'm sure of
> the specs in this instance.
>
> Larry
>

Thanks, I have added a big comment to this code so that this won't be forgotten.

I'm gonna re-submit this as a formal patch soon.

-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply

* wireless regressions -- Re: 2.6.31-rc5-git5: Reported regressions from 2.6.30
From: John W. Linville @ 2009-08-10 15:04 UTC (permalink / raw)
  To: Linux Wireless List
In-Reply-To: <AuPdDySr74O.A.5LC.Pj1fKB@chimera>

On Sun, Aug 09, 2009 at 10:36:49PM +0200, Rafael J. Wysocki wrote:
> This message contains a list of some regressions from 2.6.30, for which there
> are no fixes in the mainline I know of.  If any of them have been fixed already,
> please let me know.

Wireless-related ones...

> Unresolved regressions
> ----------------------

> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13947
> Subject		: Libertas: Association request to the driver failed
> Submitter	: Daniel Mack <daniel@caiaq.de>
> Date		: 2009-08-07 19:11 (3 days old)
> First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=57921c312e8cef72ba35a4cfe870b376da0b1b87
> References	: http://marc.info/?l=linux-kernel&m=124967234311481&w=4
> Handled-By	: Roel Kluin <roel.kluin@gmail.com>
> 
> 
> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13943
> Subject		: WARNING: at net/mac80211/mlme.c:2292 with ath5k
> Submitter	: Fabio Comolli <fabio.comolli@gmail.com>
> Date		: 2009-08-06 20:15 (4 days old)
> References	: http://marc.info/?l=linux-kernel&m=124958978600600&w=4
 
> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13940
> Subject		: iwlagn and sky2 stopped working, ACPI-related
> Submitter	: Ricardo Jorge da Fonseca Marques Ferreira <storm@sys49152.net>
> Date		: 2009-08-07 22:33 (3 days old)
> References	: http://marc.info/?l=linux-kernel&m=124968457731107&w=4
 
> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13848
> Subject		: iwlwifi (4965) regression since 2.6.30
> Submitter	: Lukas Hejtmanek <xhejtman@ics.muni.cz>
> Date		: 2009-07-26 7:57 (15 days old)
> References	: http://marc.info/?l=linux-kernel&m=124859658502866&w=4
> 
> 
> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13846
> Subject		: LEDs switched off permanently by power saving with rt61pci driver
> Submitter	: Chris Clayton <chris2553@googlemail.com>
> Date		: 2009-07-13 8:27 (28 days old)
> References	: http://marc.info/?l=linux-kernel&m=124747418828398&w=4
 
> Regressions with patches
> ------------------------
> 
> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13948
> Subject		: ath5k broken after suspend-to-ram
> Submitter	: Johannes Stezenbach <js@sig21.net>
> Date		: 2009-08-07 21:51 (3 days old)
> References	: http://marc.info/?l=linux-kernel&m=124968192727854&w=4
> Handled-By	: Nick Kossifidis <mickflemm@gmail.com>
> Patch		: http://patchwork.kernel.org/patch/38550/
 
Hth...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH] cfg80211: fix alignment problem in scan request
From: John W. Linville @ 2009-08-10 15:11 UTC (permalink / raw)
  To: Ivan Kuten; +Cc: Johannes Berg, Yauhen Kharuzhy, linux-wireless
In-Reply-To: <4A800E17.3000002@promwad.com>

On Mon, Aug 10, 2009 at 03:09:59PM +0300, Ivan Kuten wrote:
> Johannes,
> 
> I can test only on compat-wireless.

Did you have to quote the whole patch (and top-post) for that?
Any reason you can't apply patches to compat-wireless?

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH] crap/rtl8187se: Fix comment-out-typo
From: John W. Linville @ 2009-08-10 14:59 UTC (permalink / raw)
  To: Michael Buesch; +Cc: gregkh, linux-wireless
In-Reply-To: <200908091802.31166.mb@bu3sch.de>

On Sun, Aug 09, 2009 at 06:02:30PM +0200, Michael Buesch wrote:
> This fixes a comment-out-typo that resulted in a dangling if-branch.
> 
> Signed-off-by: Michael Buesch <mb@bu3sch.de>
> 
> ---
> 
> Completely untested, but looks sane.
> 
> 
>  drivers/staging/rtl8187se/r8180_core.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> --- wireless-testing.orig/drivers/staging/rtl8187se/r8180_core.c
> +++ wireless-testing/drivers/staging/rtl8187se/r8180_core.c
> @@ -3394,21 +3394,21 @@ short rtl8180_tx(struct net_device *dev,
>  			if(remain == 4 && i+4 >= buflen) break;
>  			/* ensure the last desc has at least 4 bytes payload */
>  
>  		}
>  		txbuf = txbuf + i;
>  		*(tail+3)=*(tail+3) &~ 0xfff;
>  		*(tail+3)=*(tail+3) | i; // buffer lenght
>  		// Use short preamble or not
>  		if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
>  			if (priv->plcp_preamble_mode==1 && rate!=0)	//  short mode now, not long!
> -			//	*tail |= (1<<16);				// enable short preamble mode.
> +			;//	*tail |= (1<<16);				// enable short preamble mode.
>  
>  #ifdef CONFIG_RTL8185B
>  		if(bCTSEnable) {
>  			*tail |= (1<<18);
>  		}
>  
>  		if(bRTSEnable) //rts enable
>  		{
>  			*tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19);//RTS RATE
>  			*tail |= (1<<23);//rts enable

Thanks for the reminder of why rtl8187se remains abandoned...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [RFC PATCH] b43: Implement LP-PHY baseband table initialization
From: Larry Finger @ 2009-08-10 14:55 UTC (permalink / raw)
  To: Gábor Stefanik
  Cc: John Linville, Michael Buesch, Johannes Berg, Broadcom Wireless,
	linux-wireless
In-Reply-To: <69e28c910908100437n46a04f76tf91876d48ab19cb4@mail.gmail.com>

Gábor Stefanik wrote:
> 2009/8/10 Larry Finger <Larry.Finger@lwfinger.net>:
>> Gábor Stefanik wrote:
>>> Implement LP-PHY baseband table init for all revisions.
>>>
>>> Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
>>>
>>> ---
>>> Sorry for the size; it's difficult to cut short changes like this
>>> (most of the patch is just table data). Please review, there may always be
>>> bugs that I failed to catch while reading through the code. I have added
>>> comments to places that were not quite clear to me.
>>>
>>> phy_lp.c       |   41 tables_lpphy.c | 3223
>>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>> tables_lpphy.h |    3 3 files changed, 3263 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/net/wireless/b43/phy_lp.c
>>> b/drivers/net/wireless/b43/phy_lp.c
>>> index 27eadee..cf17489 100644
>>> --- a/drivers/net/wireless/b43/phy_lp.c
>>> +++ b/drivers/net/wireless/b43/phy_lp.c
>>> @@ -59,9 +59,43 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
>>>     dev->phy.lp = NULL;
>>> }
>>>
>>> +static void lpphy_adjust_gain_table(struct b43_wldev *dev)
>>> +{
>>> +    struct b43_phy_lp *lpphy = dev->phy.lp;
>>> +    u32 freq = dev->wl->hw->conf.channel->center_freq;
>>> +    u16 temp[3];
>>> +    u16 isolation;
>>> +
>>> +    B43_WARN_ON(dev->phy.rev >= 2);
>>> +
>>> +    if (freq < 2400) /* FIXME Can this ever happen? Should we WARN_ON? */
>> This was a typo. It should be 2500, not 2400.
> 
> Thanks! So it is actually better to implement this as "if
> (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)"? That would make
> it easier to implement non-standard channels similar to how it was
> done for ath5k (Richard Farina's frequency patch - assuming the HW is
> capable of something like that).

Yes, that would work for the 2.4 GHz band, and I guess there could be
similar routines or macros to split the 5 GHz band into low, medium
and high channels.

>>> +        isolation = lpphy->tx_isolation_med_band;
>>> +    else if (freq <= 5320)
>> --snip --
>>
>>> +void lpphy_rev2plus_table_init(struct b43_wldev *dev)
>>> +{
>>> +    struct ssb_bus *bus = dev->dev->bus;
>>> +    int i;
>>> +
>>> +    B43_WARN_ON(dev->phy.rev < 2);
>>> +
>>> +    //XXX should this be done using b43_lptab_write_bulk?
>>> +    for (i = 0; i < 704; i++)
>>> +        b43_lptab_write(dev, B43_LPTAB32(7, i), 0);
>> No. The bulk write is for writing tables with length greater than 1.
>> In this case, you have 704 different tables each of length 1.
> 
> By the way, looking at the implementation again, it looks a bit fishy
> to me - we write zeros to 4 bytes of table ID 7, then increase the
> offset by 1 byte, and again write 4 bytes - 3 of which are the same
> bytes we already zeroed in the previous step.
> 
> I suspect this would suffice:
> 
> for (i = 0; i < 704; i += 4)
>            b43_lptab_write(dev, B43_LPTAB32(7, i), 0);
> 
> This version cuts the write count in half, and removes redundant byte writes.
> 
> Maybe this should be tested once the code is functional.

Without knowing what the firmware does with these values, I'm not sure
that the two steps are equivalent, but that can be tested. I'm sure of
the specs in this instance.

Larry

^ permalink raw reply

* Re: 2.6.31-rc5-git5: Reported regressions from 2.6.30
From: James Bottomley @ 2009-08-10 14:30 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux Kernel Mailing List, Adrian Bunk, Andrew Morton,
	Linus Torvalds, Natalie Protasevich, Kernel Testers List,
	Network Development, Linux ACPI, Linux PM List, Linux SCSI List,
	Linux Wireless List, DRI
In-Reply-To: <AuPdDySr74O.A.5LC.Pj1fKB@chimera>

On Sun, 2009-08-09 at 22:36 +0200, Rafael J. Wysocki wrote:
> Bug-Entry       : http://bugzilla.kernel.org/show_bug.cgi?id=13716
> Subject         : The AIC-7892P controller does not work any more
> Submitter       : Andrej Podzimek <andrej@podzimek.org>
> Date            : 2009-07-05 19:23 (36 days old)

This one sounds like an IRQ routing error, so probably ACPI, but we've
been totally unsuccessful at getting any further information out of the
submitter.  Use your own time judgement on this, but if he hasn't been
responding to you either for 36 days, I'd suggest closing this as
unresponsive.

James



^ permalink raw reply

* Re: [PATCH 2/2] ieee802154: add virtual loopback driver
From: Johannes Berg @ 2009-08-10 14:29 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: netdev, linux-zigbee-devel, linux-wireless, Sergey Lapin
In-Reply-To: <1249913800-10176-3-git-send-email-dbaryshkov@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 522 bytes --]

On Mon, 2009-08-10 at 18:16 +0400, Dmitry Eremin-Solenikov wrote:

> +if IEEE802154_DRIVERS && MAC802154
> +config IEEE802154_FAKELB

depends on

> +	tristate "Fake LR-WPAN driver with several interconnected devices"
> +	---help---
> +	  Say Y here to enable the fake driver that can emulate a net
> +          of several interconnected radio devices.
> +
> +          This driver can also be built as a module. To do so say M here.
> +	  The module will be called 'fakelb'.

whitespace damage

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH 1/2] mac802154: add a software MAC 802.15.4 implementation
From: Johannes Berg @ 2009-08-10 14:27 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov; +Cc: netdev, linux-wireless, Sergey Lapin
In-Reply-To: <1249913800-10176-2-git-send-email-dbaryshkov@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2260 bytes --]

On Mon, 2009-08-10 at 18:16 +0400, Dmitry Eremin-Solenikov wrote:
> Some of available devices are just dump radios implementing IEEE 802.15.4

dump -> dumb

> Note this implementaion is neither certified, nor feature complete!

implementation

> + * @tx: Handler that 802.15.4 module calls for each transmitted frame.
> + *      skb cntains the buffer starting from the IEEE 802.15.4 header.
> + *      The low-level driver should send the frame based on available
> + *      configuration.
> + *      This function should return zero or negative errno.

That return value is strange.

> +++ b/net/Makefile
> @@ -61,6 +61,7 @@ ifneq ($(CONFIG_DCB),)
>  obj-y				+= dcb/
>  endif
>  obj-y				+= ieee802154/
> +obj-y				+= mac802154/

I think you should use obj-$(CONFIG_MAC802154) as there's no need to
recurse into the dir unless that's selected.

But does it make sense to actually have this little code as a separate
dir/module?

> +	  Note: this implementation is neither certified, nor feature
> +	  complete! We do not garantee that it is compatible w/ other
> +	  implementations, etc.

guarantee

But generally, you don't have to write that anyway due to the license.

> +	  If you plan to use HardMAC IEEE 802.15.4 devices, you can
> +          say N here. Alternatievly you can say M to compile it as
> +	  module.

white space gone wrong

> +	struct net_device *netdev; /* mwpanX device */
> +	int open_count;
> +	/* As in mac80211 slaves list is modified:
> +	 * 1) under the RTNL
> +	 * 2) protected by slaves_mtx;
> +	 * 3) in an RCU manner
> +	 *
> +	 * So atomic readers can use any of this protection methods
> +	 */
> +	struct list_head	slaves;

heh.

> +static int ieee802154_master_open(struct net_device *dev)
> +{

We've had no end to trouble with the master netdev, I suggest you look
into the current mac80211 code and see if you can get rid of it.

> +struct ieee802154_dev *ieee802154_alloc_device(size_t priv_size,
> +		struct ieee802154_ops *ops)
> +{

> +	if (!try_module_get(ops->owner)) {

That isn't necessary since the module is just calling your function. In
fact, doing this removes the ability to rmmod any module using this
which is bogus.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH] rtl818x: Add some documentation to the TX desc flags
From: Larry Finger @ 2009-08-10 14:27 UTC (permalink / raw)
  To: Michael Buesch
  Cc: linville, Herton Ronaldo Krzesinski, Hin-Tak Leung,
	linux-wireless
In-Reply-To: <200908091757.31010.mb@bu3sch.de>

Michael Buesch wrote:
> Add some TX desc flags docs.
> 
> Signed-off-by: Michael Buesch <mb@bu3sch.de>
> 
> ---
> 
> It's incomplete. Just the ones I could easily figure out by myself...

ack

Thanks for the start. In a quick check, the one you didn't fill in
(RTL818X_TX_DESC_FLAG_RX_UNDER) is not used and should be removed.
I'll do that and add the RX desc flags.

Larry



^ permalink raw reply

* [PATCH 2/2] ieee802154: add virtual loopback driver
From: Dmitry Eremin-Solenikov @ 2009-08-10 14:16 UTC (permalink / raw)
  To: netdev; +Cc: linux-zigbee-devel, linux-wireless, Sergey Lapin
In-Reply-To: <1249913800-10176-2-git-send-email-dbaryshkov@gmail.com>

fakelb is a virtual loopback driver implementing one or several
interconnected radios. Packets from the radio are either sent
back to the node (if no other fake radio are registered) or to
all other fake radio.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 drivers/ieee802154/Kconfig  |   13 ++
 drivers/ieee802154/Makefile |    1 +
 drivers/ieee802154/fakelb.c |  255 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ieee802154/fakelb.c

diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
index 9b9f43a..b68b5c5 100644
--- a/drivers/ieee802154/Kconfig
+++ b/drivers/ieee802154/Kconfig
@@ -20,3 +20,16 @@ config IEEE802154_FAKEHARD
           This driver can also be built as a module. To do so say M here.
 	  The module will be called 'fakehard'.
 
+
+if IEEE802154_DRIVERS && MAC802154
+config IEEE802154_FAKELB
+	tristate "Fake LR-WPAN driver with several interconnected devices"
+	---help---
+	  Say Y here to enable the fake driver that can emulate a net
+          of several interconnected radio devices.
+
+          This driver can also be built as a module. To do so say M here.
+	  The module will be called 'fakelb'.
+
+endif
+
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
index e0e8e1a..2bd7bdf 100644
--- a/drivers/ieee802154/Makefile
+++ b/drivers/ieee802154/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
+obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
 
 EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/fakelb.c b/drivers/ieee802154/fakelb.c
new file mode 100644
index 0000000..9a135a9
--- /dev/null
+++ b/drivers/ieee802154/fakelb.c
@@ -0,0 +1,255 @@
+/*
+ * Loopback IEEE 802.15.4 interface
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
+#include <net/mac802154.h>
+
+struct fake_dev_priv {
+	struct ieee802154_dev *dev;
+
+	struct list_head list;
+	struct fake_priv *fake;
+
+	unsigned int working:1;
+};
+
+static int radios = 3;
+module_param(radios, int, 0444);
+MODULE_PARM_DESC(radios, "Number of simulated radios");
+
+struct fake_priv {
+	struct list_head list;
+	rwlock_t lock;
+};
+
+static int
+hw_ed(struct ieee802154_dev *dev, u8 *level)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	BUG_ON(!level);
+	*level = 0xbe;
+	return 0;
+}
+
+static int
+hw_channel(struct ieee802154_dev *dev, int channel)
+{
+	pr_debug("%s %d\n", __func__, channel);
+	might_sleep();
+	dev->current_channel = channel;
+	return 0;
+}
+
+static void
+hw_deliver(struct fake_dev_priv *priv, struct sk_buff *skb)
+{
+	struct sk_buff *newskb;
+
+	if (!priv->working)
+		return;
+
+	newskb = pskb_copy(skb, GFP_ATOMIC);
+
+	ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
+}
+
+static int
+hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+	struct fake_dev_priv *priv = dev->priv;
+	struct fake_priv *fake = priv->fake;
+
+	might_sleep();
+
+	read_lock_bh(&fake->lock);
+	if (priv->list.next == priv->list.prev) {
+		/* we are the only one device */
+		hw_deliver(priv, skb);
+	} else {
+		struct fake_dev_priv *dp;
+		list_for_each_entry(dp, &priv->fake->list, list)
+			if (dp != priv &&
+			    dp->dev->current_channel ==
+					priv->dev->current_channel)
+				hw_deliver(dp, skb);
+	}
+	read_unlock_bh(&fake->lock);
+
+	return 0;
+}
+
+static int
+hw_start(struct ieee802154_dev *dev) {
+	struct fake_dev_priv *priv = dev->priv;
+
+	if (priv->working)
+		return -EBUSY;
+
+	priv->working = 1;
+
+	return 0;
+}
+
+static void
+hw_stop(struct ieee802154_dev *dev) {
+	struct fake_dev_priv *priv = dev->priv;
+
+	priv->working = 0;
+}
+
+static struct ieee802154_ops fake_ops = {
+	.owner = THIS_MODULE,
+	.xmit = hw_xmit,
+	.ed = hw_ed,
+	.set_channel = hw_channel,
+	.start = hw_start,
+	.stop = hw_stop,
+};
+
+static int ieee802154fake_add_priv(struct device *dev, struct fake_priv *fake)
+{
+	struct fake_dev_priv *priv;
+	int err = -ENOMEM;
+	struct ieee802154_dev *ieee;
+
+	ieee = ieee802154_alloc_device(sizeof(*priv), &fake_ops);
+	if (!dev)
+		goto err_alloc_dev;
+
+	priv = ieee->priv;
+	priv->dev = ieee;
+
+	INIT_LIST_HEAD(&priv->list);
+	priv->fake = fake;
+
+	ieee->parent = dev;
+
+	err = ieee802154_register_device(ieee);
+	if (err)
+		goto err_reg;
+
+	write_lock_bh(&fake->lock);
+	list_add_tail(&priv->list, &fake->list);
+	write_unlock_bh(&fake->lock);
+
+	return 0;
+
+err_reg:
+	ieee802154_free_device(priv->dev);
+err_alloc_dev:
+	return err;
+}
+
+static void ieee802154fake_del_priv(struct fake_dev_priv *priv)
+{
+	write_lock_bh(&priv->fake->lock);
+	list_del(&priv->list);
+	write_unlock_bh(&priv->fake->lock);
+
+	ieee802154_unregister_device(priv->dev);
+	ieee802154_free_device(priv->dev);
+}
+
+static int __devinit ieee802154fake_probe(struct platform_device *pdev)
+{
+	struct fake_priv *priv;
+	struct fake_dev_priv *dp;
+	int err = -ENOMEM;
+	int i;
+
+	if (radios < 1 || radios > 100)
+		return -EINVAL;
+
+	priv = kzalloc(sizeof(struct fake_priv), GFP_KERNEL);
+	if (!priv)
+		goto err_alloc;
+
+	INIT_LIST_HEAD(&priv->list);
+	rwlock_init(&priv->lock);
+
+	for (i = 0; i < radios; i++) {
+		err = ieee802154fake_add_priv(&pdev->dev, priv);
+		if (err < 0)
+			goto err_slave;
+	}
+
+	platform_set_drvdata(pdev, priv);
+	dev_info(&pdev->dev, "Added ieee802154 hardware\n");
+	return 0;
+
+err_slave:
+	list_for_each_entry(dp, &priv->list, list)
+		ieee802154fake_del_priv(dp);
+err_grp:
+	kfree(priv);
+err_alloc:
+	return err;
+}
+
+static int __devexit ieee802154fake_remove(struct platform_device *pdev)
+{
+	struct fake_priv *priv = platform_get_drvdata(pdev);
+	struct fake_dev_priv *dp, *temp;
+
+	list_for_each_entry_safe(dp, temp, &priv->list, list)
+		ieee802154fake_del_priv(dp);
+	kfree(priv);
+	return 0;
+}
+
+static struct platform_device *ieee802154fake_dev;
+
+static struct platform_driver ieee802154fake_driver = {
+	.probe = ieee802154fake_probe,
+	.remove = __devexit_p(ieee802154fake_remove),
+	.driver = {
+			.name = "ieee802154fakelb",
+			.owner = THIS_MODULE,
+	},
+};
+
+static __init int fake_init(void)
+{
+	ieee802154fake_dev = platform_device_register_simple(
+			"ieee802154fakelb", -1, NULL, 0);
+	return platform_driver_register(&ieee802154fake_driver);
+}
+
+static __exit void fake_exit(void)
+{
+	platform_driver_unregister(&ieee802154fake_driver);
+	platform_device_unregister(ieee802154fake_dev);
+}
+
+module_init(fake_init);
+module_exit(fake_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dmitry Eremin-Solenikov, Sergey Lapin");
+
+
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 1/2] mac802154: add a software MAC 802.15.4 implementation
From: Dmitry Eremin-Solenikov @ 2009-08-10 14:16 UTC (permalink / raw)
  To: netdev; +Cc: linux-zigbee-devel, linux-wireless, Sergey Lapin
In-Reply-To: <1249913800-10176-1-git-send-email-dbaryshkov@gmail.com>

Some of available devices are just dump radios implementing IEEE 802.15.4
PHY layer. This commit adds a common library that acts like an intermediate
layer between our socket family and drivers for those dumb devices.

Currently this is data-only part (no commands, no beacons). Control
interfaces will follow up shortly.

Note this implementaion is neither certified, nor feature complete!

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 MAINTAINERS               |    1 +
 include/linux/mac802154.h |   35 ++
 include/net/mac802154.h   |  106 ++++++
 net/Kconfig               |    1 +
 net/Makefile              |    1 +
 net/mac802154/Kconfig     |   17 +
 net/mac802154/Makefile    |    4 +
 net/mac802154/dev.c       |  924 +++++++++++++++++++++++++++++++++++++++++++++
 net/mac802154/mac802154.h |   85 +++++
 net/mac802154/mac_cmd.c   |   99 +++++
 net/mac802154/mdev.c      |  295 +++++++++++++++
 net/mac802154/mib.h       |   32 ++
 net/mac802154/rx.c        |   98 +++++
 13 files changed, 1698 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/mac802154.h
 create mode 100644 include/net/mac802154.h
 create mode 100644 net/mac802154/Kconfig
 create mode 100644 net/mac802154/Makefile
 create mode 100644 net/mac802154/dev.c
 create mode 100644 net/mac802154/mac802154.h
 create mode 100644 net/mac802154/mac_cmd.c
 create mode 100644 net/mac802154/mdev.c
 create mode 100644 net/mac802154/mib.h
 create mode 100644 net/mac802154/rx.c

diff --git a/MAINTAINERS b/MAINTAINERS
index d6befb2..5bdb64e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2529,6 +2529,7 @@ W:	http://apps.sourceforge.net/trac/linux-zigbee
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
 S:	Maintained
 F:	net/ieee802154/
+F:	net/mac802154/
 F:	drivers/ieee802154/
 
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
diff --git a/include/linux/mac802154.h b/include/linux/mac802154.h
new file mode 100644
index 0000000..e95e38d
--- /dev/null
+++ b/include/linux/mac802154.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef LINUX_MAC802154_H
+#define LINUX_MAC802154_H
+
+enum {
+	IFLA_WPAN_UNSPEC,
+	IFLA_WPAN_CHANNEL,
+	IFLA_WPAN_PAN_ID,
+	IFLA_WPAN_SHORT_ADDR,
+	IFLA_WPAN_COORD_SHORT_ADDR,
+	IFLA_WPAN_COORD_EXT_ADDR,
+	__IFLA_WPAN_MAX,
+};
+
+#define IFLA_WPAN_MAX	(__IFLA_WPAN_MAX - 1)
+
+#endif
+
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
new file mode 100644
index 0000000..db76799
--- /dev/null
+++ b/include/net/mac802154.h
@@ -0,0 +1,106 @@
+/*
+ * IEEE802.15.4-2003 specification
+ *
+ * Copyright (C) 2007, 2008 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ */
+#ifndef NET_MAC802154_H
+#define NET_MAC802154_H
+
+struct ieee802154_dev {
+	int	extra_tx_headroom; /* headroom to reserve for tx skb */
+	void	*priv;		/* driver-specific data */
+	u32	channel_mask;
+	u8	current_channel;
+	u32	flags; /* Flags for device to set */
+	struct device *parent;
+};
+
+/* Checksum is in hardware and is omitted from packet */
+/**
+ * enum ieee802154_hw_flags - hardware flags
+ *
+ * These flags are used to indicate hardware capabilities to
+ * the stack. Generally, flags here should have their meaning
+ * done in a way that the simplest hardware doesn't need setting
+ * any particular flags. There are some exceptions to this rule,
+ * however, so you are advised to review these flags carefully.
+ *
+ * @IEEE802154_HW_OMIT_CKSUM:
+ *	Indicates that receiver omits FCS and transmitter will add
+ *	FCS on it's own.
+ *
+ * @IEEE802154_HW_AACK:
+ * 	Indicates that receiver will autorespond with ACK frames.
+ */
+enum ieee802154_hw_flags {
+	IEEE802154_HW_OMIT_CKSUM			= 1 << 0,
+	IEEE802154_HW_AACK				= 1 << 1,
+};
+
+struct sk_buff;
+
+/**
+ * struct ieee802154_ops - callbacks from mac802154 to the driver
+ *
+ * This structure contains various callbacks that the driver may
+ * handle or, in some cases, must handle, for example to transmit
+ * a frame.
+ *
+ * @start: Handler that 802.15.4 module calls for device initialisation.
+ * 	This function is called before the first interface is attached.
+ *
+ * @stop: Handler that 802.15.4 module calls for device cleanup
+ * 	This function is called after the last interface is removed.
+ *
+ * @tx: Handler that 802.15.4 module calls for each transmitted frame.
+ *      skb cntains the buffer starting from the IEEE 802.15.4 header.
+ *      The low-level driver should send the frame based on available
+ *      configuration.
+ *      This function should return zero or negative errno.
+ *
+ * @ed: Handler that 802.15.4 module calls for Energy Detection.
+ *      This function should place the value for detected energy
+ *      (usually device-dependant) in the level pointer and return
+ *      either zero or negative errno.
+ *
+ * @set_channel: Set radio for listening on specific channel.
+ *      Set the device for listening on specified channel.
+ *      Returns either zero, or negative errno.
+ */
+struct ieee802154_ops {
+	struct module	*owner;
+	int		(*start)(struct ieee802154_dev *dev);
+	void		(*stop)(struct ieee802154_dev *dev);
+	int		(*xmit)(struct ieee802154_dev *dev,
+						struct sk_buff *skb);
+	int		(*ed)(struct ieee802154_dev *dev, u8 *level);
+	int		(*set_channel)(struct ieee802154_dev *dev,
+						int channel);
+};
+
+struct ieee802154_dev *ieee802154_alloc_device(size_t priv_size,
+						struct ieee802154_ops *ops);
+int ieee802154_register_device(struct ieee802154_dev *dev);
+void ieee802154_unregister_device(struct ieee802154_dev *dev);
+void ieee802154_free_device(struct ieee802154_dev *dev);
+
+void ieee802154_rx(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi);
+void ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb,
+		u8 lqi);
+#endif
+
diff --git a/net/Kconfig b/net/Kconfig
index 7051b97..b42d325 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -180,6 +180,7 @@ source "net/econet/Kconfig"
 source "net/wanrouter/Kconfig"
 source "net/phonet/Kconfig"
 source "net/ieee802154/Kconfig"
+source "net/mac802154/Kconfig"
 source "net/sched/Kconfig"
 source "net/dcb/Kconfig"
 
diff --git a/net/Makefile b/net/Makefile
index ba324ae..81115f6 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -61,6 +61,7 @@ ifneq ($(CONFIG_DCB),)
 obj-y				+= dcb/
 endif
 obj-y				+= ieee802154/
+obj-y				+= mac802154/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/mac802154/Kconfig b/net/mac802154/Kconfig
new file mode 100644
index 0000000..2dd7f99
--- /dev/null
+++ b/net/mac802154/Kconfig
@@ -0,0 +1,17 @@
+config MAC802154
+	tristate "Generic IEEE 802.15.4 Soft Networking Stack (mac802154)"
+	depends on IEEE802154 && EXPERIMENTAL
+	select CRC_CCITT
+	---help---
+	  This option enables the hardware independent IEEE 802.15.4
+	  networking stack for SoftMAC devices (the ones implementing
+	  only PHY level of IEEE 802.15.4 standard).
+
+	  Note: this implementation is neither certified, nor feature
+	  complete! We do not garantee that it is compatible w/ other
+	  implementations, etc.
+
+	  If you plan to use HardMAC IEEE 802.15.4 devices, you can
+          say N here. Alternatievly you can say M to compile it as
+	  module.
+
diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile
new file mode 100644
index 0000000..07b7821
--- /dev/null
+++ b/net/mac802154/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_MAC802154) +=	mac802154.o
+mac802154-objs		:= rx.o mdev.o dev.o mac_cmd.o
+
+EXTRA_CFLAGS += -Wall -DDEBUG
diff --git a/net/mac802154/dev.c b/net/mac802154/dev.c
new file mode 100644
index 0000000..b40f6fd
--- /dev/null
+++ b/net/mac802154/dev.c
@@ -0,0 +1,924 @@
+/*
+ * Copyright 2007, 2008, 2009 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ */
+
+#include <linux/net.h>
+#include <linux/capability.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/rculist.h>
+#include <linux/random.h>
+#include <linux/crc-ccitt.h>
+#include <linux/mac802154.h>
+#include <net/rtnetlink.h>
+
+#include <net/af_ieee802154.h>
+#include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/ieee802154.h>
+
+#include "mac802154.h"
+#include "mib.h"
+
+static int ieee802154_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv;
+	priv = netdev_priv(dev);
+
+	if (!(priv->hw->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
+		u16 crc = crc_ccitt(0, skb->data, skb->len);
+		u8 *data = skb_put(skb, 2);
+		data[0] = crc & 0xff;
+		data[1] = crc >> 8;
+	}
+
+	read_lock(&priv->mib_lock);
+	phy_cb(skb)->chan = priv->chan;
+	read_unlock(&priv->mib_lock);
+
+	skb->iif = dev->ifindex;
+	skb->dev = priv->hw->netdev;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	dev->trans_start = jiffies;
+	dev_queue_xmit(skb);
+
+	return 0;
+}
+
+static int ieee802154_slave_open(struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+	int res = 0;
+
+	if (priv->hw->open_count++ == 0) {
+		res = dev_open(priv->hw->netdev);
+		WARN_ON(res);
+		if (res)
+			goto err;
+	}
+
+	netif_start_queue(dev);
+	return 0;
+err:
+	priv->hw->open_count--;
+
+	return res;
+}
+
+static int ieee802154_slave_close(struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+
+	if ((--priv->hw->open_count) == 0) {
+		if (netif_running(priv->hw->netdev))
+			dev_close(priv->hw->netdev);
+	}
+
+	return 0;
+}
+
+
+static int ieee802154_slave_ioctl(struct net_device *dev, struct ifreq *ifr,
+		int cmd)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+	struct sockaddr_ieee802154 *sa =
+		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
+	int err = -ENOIOCTLCMD;
+
+	read_lock(&priv->mib_lock);
+
+	switch (cmd) {
+	case SIOCGIFADDR:
+		if (priv->pan_id == IEEE802154_PANID_BROADCAST ||
+		    priv->short_addr == IEEE802154_ADDR_BROADCAST) {
+			err = -EADDRNOTAVAIL;
+			break;
+		}
+
+		sa->family = AF_IEEE802154;
+		sa->addr.addr_type = IEEE802154_ADDR_SHORT;
+		sa->addr.pan_id = priv->pan_id;
+		sa->addr.short_addr = priv->short_addr;
+
+		err = 0;
+		break;
+	case SIOCSIFADDR:
+		dev_warn(&dev->dev,
+			"Using DEBUGing ioctl SIOCSIFADDR isn't recommened!\n");
+		if (sa->family != AF_IEEE802154 ||
+		    sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
+		    sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
+		    sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
+		    sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
+			err = -EINVAL;
+			break;
+		}
+
+		priv->pan_id = sa->addr.pan_id;
+		priv->short_addr = sa->addr.short_addr;
+		err = 0;
+		break;
+	}
+	read_unlock(&priv->mib_lock);
+	return err;
+}
+
+static int ieee802154_slave_mac_addr(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+	/* FIXME: validate addr */
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	return 0;
+}
+
+static void ieee802154_haddr_copy_swap(u8 *dest, const u8 *src)
+{
+	int i;
+	for (i = 0; i < IEEE802154_ADDR_LEN; i++)
+		dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
+}
+
+static int ieee802154_header_create(struct sk_buff *skb,
+			   struct net_device *dev,
+			   unsigned short type, const void *_daddr,
+			   const void *_saddr, unsigned len)
+{
+	u8 head[24] = {};
+	int pos = 0;
+
+	u16 fc;
+	const struct ieee802154_addr *saddr = _saddr;
+	const struct ieee802154_addr *daddr = _daddr;
+	struct ieee802154_addr dev_addr;
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+
+	fc = mac_cb_type(skb);
+	if (mac_cb_is_ackreq(skb))
+		fc |= IEEE802154_FC_ACK_REQ;
+
+	pos = 2;
+
+	head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
+
+	if (!daddr)
+		return -EINVAL;
+
+	if (!saddr) {
+		read_lock(&priv->mib_lock);
+		if (priv->short_addr == IEEE802154_ADDR_BROADCAST ||
+		    priv->short_addr == IEEE802154_ADDR_UNDEF ||
+		    priv->pan_id == IEEE802154_PANID_BROADCAST) {
+			dev_addr.addr_type = IEEE802154_ADDR_LONG;
+			memcpy(dev_addr.hwaddr, dev->dev_addr,
+					IEEE802154_ADDR_LEN);
+		} else {
+			dev_addr.addr_type = IEEE802154_ADDR_SHORT;
+			dev_addr.short_addr = priv->short_addr;
+		}
+
+		dev_addr.pan_id = priv->pan_id;
+		saddr = &dev_addr;
+
+		read_unlock(&priv->mib_lock);
+	}
+
+	if (daddr->addr_type != IEEE802154_ADDR_NONE) {
+		fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
+
+		head[pos++] = daddr->pan_id & 0xff;
+		head[pos++] = daddr->pan_id >> 8;
+
+		if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
+			head[pos++] = daddr->short_addr & 0xff;
+			head[pos++] = daddr->short_addr >> 8;
+		} else {
+			ieee802154_haddr_copy_swap(head + pos, daddr->hwaddr);
+			pos += IEEE802154_ADDR_LEN;
+		}
+	}
+
+	if (saddr->addr_type != IEEE802154_ADDR_NONE) {
+		fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
+
+		if ((saddr->pan_id == daddr->pan_id) &&
+		    (saddr->pan_id != IEEE802154_PANID_BROADCAST))
+			/* PANID compression/ intra PAN */
+			fc |= IEEE802154_FC_INTRA_PAN;
+		else {
+			head[pos++] = saddr->pan_id & 0xff;
+			head[pos++] = saddr->pan_id >> 8;
+		}
+
+		if (saddr->addr_type == IEEE802154_ADDR_SHORT) {
+			head[pos++] = saddr->short_addr & 0xff;
+			head[pos++] = saddr->short_addr >> 8;
+		} else {
+			ieee802154_haddr_copy_swap(head + pos, saddr->hwaddr);
+			pos += IEEE802154_ADDR_LEN;
+		}
+	}
+
+	head[0] = fc;
+	head[1] = fc >> 8;
+
+	memcpy(skb_push(skb, pos), head, pos);
+
+	return pos;
+}
+
+static int ieee802154_header_parse(const struct sk_buff *skb,
+		unsigned char *haddr)
+{
+	const u8 *hdr = skb_mac_header(skb), *tail = skb_tail_pointer(skb);
+	struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
+	u16 fc;
+	int da_type;
+
+	if (hdr + 3 > tail)
+		goto malformed;
+
+	fc = hdr[0] | (hdr[1] << 8);
+
+	hdr += 3;
+
+	da_type = IEEE802154_FC_DAMODE(fc);
+	addr->addr_type = IEEE802154_FC_SAMODE(fc);
+
+	switch (da_type) {
+	case IEEE802154_ADDR_NONE:
+		if (fc & IEEE802154_FC_INTRA_PAN)
+			goto malformed;
+		break;
+
+	case IEEE802154_ADDR_LONG:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (fc & IEEE802154_FC_INTRA_PAN) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + IEEE802154_ADDR_LEN > tail)
+			goto malformed;
+		hdr += IEEE802154_ADDR_LEN;
+		break;
+
+	case IEEE802154_ADDR_SHORT:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (fc & IEEE802154_FC_INTRA_PAN) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + 2 > tail)
+			goto malformed;
+		hdr += 2;
+		break;
+
+	default:
+		goto malformed;
+
+	}
+
+	switch (addr->addr_type) {
+	case IEEE802154_ADDR_NONE:
+		break;
+
+	case IEEE802154_ADDR_LONG:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (!(fc & IEEE802154_FC_INTRA_PAN)) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + IEEE802154_ADDR_LEN > tail)
+			goto malformed;
+		memcpy(addr->hwaddr, hdr, IEEE802154_ADDR_LEN);
+		hdr += IEEE802154_ADDR_LEN;
+		break;
+
+	case IEEE802154_ADDR_SHORT:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (!(fc & IEEE802154_FC_INTRA_PAN)) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + 2 > tail)
+			goto malformed;
+		addr->short_addr = hdr[0] | (hdr[1] << 8);
+		hdr += 2;
+		break;
+
+	default:
+		goto malformed;
+
+	}
+
+	return sizeof(struct ieee802154_addr);
+
+malformed:
+	pr_debug("malformed packet\n");
+	return 0;
+}
+
+static struct header_ops ieee802154_header_ops = {
+	.create		= ieee802154_header_create,
+	.parse		= ieee802154_header_parse,
+};
+
+static const struct net_device_ops ieee802154_slave_ops = {
+	.ndo_open		= ieee802154_slave_open,
+	.ndo_stop		= ieee802154_slave_close,
+	.ndo_start_xmit		= ieee802154_net_xmit,
+	.ndo_do_ioctl		= ieee802154_slave_ioctl,
+	.ndo_set_mac_address	= ieee802154_slave_mac_addr,
+};
+
+static void ieee802154_netdev_setup(struct net_device *dev)
+{
+	dev->addr_len		= IEEE802154_ADDR_LEN;
+	memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+	dev->features		= NETIF_F_NO_CSUM;
+	dev->hard_header_len	= 2 + 1 + 20 + 14;
+	dev->header_ops		= &ieee802154_header_ops;
+	dev->needed_tailroom	= 2; /* FCS */
+	dev->mtu		= 127;
+	dev->tx_queue_len	= 10;
+	dev->type		= ARPHRD_IEEE802154;
+	dev->flags		= IFF_NOARP | IFF_BROADCAST;
+	dev->watchdog_timeo	= 0;
+
+	dev->destructor		= free_netdev;
+	dev->netdev_ops		= &ieee802154_slave_ops;
+	dev->ml_priv		= &mac802154_mlme;
+}
+
+/*
+ * This is for hw unregistration only, as it doesn't do RCU locking
+ */
+void ieee802154_drop_slaves(struct ieee802154_dev *hw)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(hw);
+	struct ieee802154_sub_if_data *sdata, *next;
+
+	ASSERT_RTNL();
+
+	list_for_each_entry_safe(sdata, next, &priv->slaves, list) {
+		mutex_lock(&sdata->hw->slaves_mtx);
+		list_del(&sdata->list);
+		mutex_unlock(&sdata->hw->slaves_mtx);
+
+		dev_put(sdata->hw->netdev);
+
+		unregister_netdevice(sdata->dev);
+	}
+}
+
+static int ieee802154_netdev_validate(struct nlattr *tb[],
+		struct nlattr *data[])
+{
+	if (tb[IFLA_ADDRESS])
+		if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
+			return -EINVAL;
+
+	if (tb[IFLA_BROADCAST])
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ieee802154_netdev_newlink(struct net_device *dev,
+					   struct nlattr *tb[],
+					   struct nlattr *data[])
+{
+	struct net_device *mdev;
+	struct ieee802154_sub_if_data *priv;
+	struct ieee802154_priv *ipriv;
+	int err;
+
+	if (!tb[IFLA_LINK])
+		return -EOPNOTSUPP;
+
+	mdev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK]));
+	if (!mdev)
+		return -ENODEV;
+
+	if (mdev->type != ARPHRD_IEEE802154_PHY)
+		return -EINVAL;
+
+	ipriv = netdev_priv(mdev);
+
+	priv = netdev_priv(dev);
+	priv->dev = dev;
+	priv->hw = ipriv;
+
+	rwlock_init(&priv->mib_lock);
+
+	get_random_bytes(&priv->bsn, 1);
+	get_random_bytes(&priv->dsn, 1);
+
+	priv->pan_id = IEEE802154_PANID_BROADCAST;
+	priv->short_addr = IEEE802154_ADDR_BROADCAST;
+
+	dev_hold(ipriv->netdev);
+
+	dev->needed_headroom = ipriv->hw.extra_tx_headroom;
+
+	SET_NETDEV_DEV(dev, &ipriv->netdev->dev);
+
+	err = register_netdevice(dev);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&ipriv->slaves_mtx);
+	list_add_tail_rcu(&priv->list, &ipriv->slaves);
+	mutex_unlock(&ipriv->slaves_mtx);
+
+	return 0;
+}
+
+static void ieee802154_netdev_dellink(struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *sdata;
+	ASSERT_RTNL();
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	sdata = netdev_priv(dev);
+
+	mutex_lock(&sdata->hw->slaves_mtx);
+	list_del_rcu(&sdata->list);
+	mutex_unlock(&sdata->hw->slaves_mtx);
+
+	dev_put(sdata->hw->netdev);
+
+	synchronize_rcu();
+	unregister_netdevice(sdata->dev);
+}
+
+static size_t ieee802154_netdev_get_size(const struct net_device *dev)
+{
+	return	nla_total_size(2) +	/* IFLA_WPAN_CHANNEL */
+		nla_total_size(2) +	/* IFLA_WPAN_PAN_ID */
+		nla_total_size(2) +	/* IFLA_WPAN_SHORT_ADDR */
+		nla_total_size(2) +	/* IFLA_WPAN_COORD_SHORT_ADDR */
+		nla_total_size(8);	/* IFLA_WPAN_COORD_EXT_ADDR */
+}
+
+static int ieee802154_netdev_fill_info(struct sk_buff *skb,
+					const struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+
+	read_lock(&priv->mib_lock);
+
+	NLA_PUT_U16(skb, IFLA_WPAN_CHANNEL, priv->chan);
+	NLA_PUT_U16(skb, IFLA_WPAN_PAN_ID, priv->pan_id);
+	NLA_PUT_U16(skb, IFLA_WPAN_SHORT_ADDR, priv->short_addr);
+	/* TODO: IFLA_WPAN_COORD_SHORT_ADDR */
+	/* TODO: IFLA_WPAN_COORD_EXT_ADDR */
+
+	read_unlock(&priv->mib_lock);
+
+	return 0;
+
+nla_put_failure:
+	read_unlock(&priv->mib_lock);
+	return -EMSGSIZE;
+}
+
+static struct rtnl_link_ops wpan_link_ops __read_mostly = {
+	.kind		= "wpan",
+	.priv_size	= sizeof(struct ieee802154_sub_if_data),
+	.setup		= ieee802154_netdev_setup,
+	.validate	= ieee802154_netdev_validate,
+	.newlink	= ieee802154_netdev_newlink,
+	.dellink	= ieee802154_netdev_dellink,
+	.get_size	= ieee802154_netdev_get_size,
+	.fill_info	= ieee802154_netdev_fill_info,
+};
+
+static int ieee802154_process_beacon(struct net_device *dev,
+		struct sk_buff *skb)
+{
+	pr_warning("ieee802154: beacon frames are not yet supported\n");
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int ieee802154_process_ack(struct net_device *dev, struct sk_buff *skb)
+{
+	pr_debug("got ACK for SEQ=%d\n", mac_cb(skb)->seq);
+
+	kfree_skb(skb);
+	return NET_RX_SUCCESS;
+}
+
+static int ieee802154_process_data(struct net_device *dev, struct sk_buff *skb)
+{
+	return netif_rx(skb);
+}
+
+static int ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
+		struct sk_buff *skb)
+{
+	pr_debug("%s Getting packet via slave interface %s\n",
+				__func__, sdata->dev->name);
+
+	read_lock(&sdata->mib_lock);
+
+	switch (mac_cb(skb)->da.addr_type) {
+	case IEEE802154_ADDR_NONE:
+		if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE)
+			/* FIXME: check if we are PAN coordinator :) */
+			skb->pkt_type = PACKET_OTHERHOST;
+		else
+			/* ACK comes with both addresses empty */
+			skb->pkt_type = PACKET_HOST;
+		break;
+	case IEEE802154_ADDR_LONG:
+		if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
+		    mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+			skb->pkt_type = PACKET_OTHERHOST;
+		else if (!memcmp(mac_cb(skb)->da.hwaddr, sdata->dev->dev_addr,
+					IEEE802154_ADDR_LEN))
+			skb->pkt_type = PACKET_HOST;
+		else
+			skb->pkt_type = PACKET_OTHERHOST;
+		break;
+	case IEEE802154_ADDR_SHORT:
+		if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
+		    mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+			skb->pkt_type = PACKET_OTHERHOST;
+		else if (mac_cb(skb)->da.short_addr == sdata->short_addr)
+			skb->pkt_type = PACKET_HOST;
+		else if (mac_cb(skb)->da.short_addr ==
+					IEEE802154_ADDR_BROADCAST)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_OTHERHOST;
+		break;
+	}
+
+	read_unlock(&sdata->mib_lock);
+
+	skb->dev = sdata->dev;
+
+	if (skb->pkt_type == PACKET_HOST && mac_cb_is_ackreq(skb) &&
+			!(sdata->hw->hw.flags & IEEE802154_HW_AACK))
+		dev_warn(&sdata->dev->dev,
+			"ACK requested, however AACK not supported.\n");
+
+	switch (mac_cb_type(skb)) {
+	case IEEE802154_FC_TYPE_BEACON:
+		return ieee802154_process_beacon(sdata->dev, skb);
+	case IEEE802154_FC_TYPE_ACK:
+		return ieee802154_process_ack(sdata->dev, skb);
+	case IEEE802154_FC_TYPE_MAC_CMD:
+		return ieee802154_process_cmd(sdata->dev, skb);
+	case IEEE802154_FC_TYPE_DATA:
+		return ieee802154_process_data(sdata->dev, skb);
+	default:
+		pr_warning("ieee802154: Bad frame received (type = %d)\n",
+				mac_cb_type(skb));
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+}
+
+static u8 fetch_skb_u8(struct sk_buff *skb)
+{
+	u8 ret;
+
+	BUG_ON(skb->len < 1);
+
+	ret = skb->data[0];
+	skb_pull(skb, 1);
+
+	return ret;
+}
+
+static u16 fetch_skb_u16(struct sk_buff *skb)
+{
+	u16 ret;
+
+	BUG_ON(skb->len < 2);
+
+	ret = skb->data[0] + (skb->data[1] * 256);
+	skb_pull(skb, 2);
+	return ret;
+}
+
+static void fetch_skb_u64(struct sk_buff *skb, void *data)
+{
+	BUG_ON(skb->len < IEEE802154_ADDR_LEN);
+
+	memcpy(data, skb->data, IEEE802154_ADDR_LEN);
+	skb_pull(skb, IEEE802154_ADDR_LEN);
+}
+
+#define IEEE802154_FETCH_U8(skb, var)		\
+	do {					\
+		if (skb->len < 1)		\
+			goto exit_error;	\
+		var = fetch_skb_u8(skb);	\
+	} while (0)
+
+#define IEEE802154_FETCH_U16(skb, var)		\
+	do {					\
+		if (skb->len < 2)		\
+			goto exit_error;	\
+		var = fetch_skb_u16(skb);	\
+	} while (0)
+
+#define IEEE802154_FETCH_U64(skb, var)			\
+	do {						\
+		if (skb->len < IEEE802154_ADDR_LEN)	\
+			goto exit_error;		\
+		fetch_skb_u64(skb, &var);		\
+	} while (0)
+
+static int parse_frame_start(struct sk_buff *skb)
+{
+	u8 *head = skb->data;
+	u16 fc;
+
+	if (skb->len < 3) {
+		pr_debug("frame size %d bytes is too short\n", skb->len);
+		return -EINVAL;
+	}
+
+	IEEE802154_FETCH_U16(skb, fc);
+	IEEE802154_FETCH_U8(skb, mac_cb(skb)->seq);
+
+	pr_debug("%s: %04x dsn%02x\n", __func__, fc, head[2]);
+
+	mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc);
+
+	if (fc & IEEE802154_FC_ACK_REQ) {
+		pr_debug("%s(): ACKNOWLEDGE required\n", __func__);
+		mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+	}
+
+	if (fc & IEEE802154_FC_SECEN)
+		mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
+
+	if (fc & IEEE802154_FC_INTRA_PAN)
+		mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN;
+
+	/* TODO */
+	if (mac_cb_is_secen(skb)) {
+		pr_info("security support is not implemented\n");
+		return -EINVAL;
+	}
+
+	mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc);
+	if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_NONE)
+		pr_debug("%s(): src addr_type is NONE\n", __func__);
+
+	mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc);
+	if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_NONE)
+		pr_debug("%s(): dst addr_type is NONE\n", __func__);
+
+	if (IEEE802154_FC_TYPE(fc) == IEEE802154_FC_TYPE_ACK) {
+		/* ACK can only have NONE-type addresses */
+		if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE ||
+		    mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE)
+			return -EINVAL;
+	}
+
+	if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) {
+		IEEE802154_FETCH_U16(skb, mac_cb(skb)->da.pan_id);
+
+		if (mac_cb_is_intrapan(skb)) { /* ! panid compress */
+			pr_debug("%s(): src IEEE802154_FC_INTRA_PAN\n",
+					__func__);
+			mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id;
+			pr_debug("%s(): src PAN address %04x\n",
+					__func__, mac_cb(skb)->sa.pan_id);
+		}
+
+		pr_debug("%s(): dst PAN address %04x\n",
+				__func__, mac_cb(skb)->da.pan_id);
+
+		if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) {
+			IEEE802154_FETCH_U16(skb, mac_cb(skb)->da.short_addr);
+			pr_debug("%s(): dst SHORT address %04x\n",
+					__func__, mac_cb(skb)->da.short_addr);
+
+		} else {
+			IEEE802154_FETCH_U64(skb, mac_cb(skb)->da.hwaddr);
+			pr_debug("%s(): dst hardware addr\n", __func__);
+		}
+	}
+
+	if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) {
+		pr_debug("%s(): got src non-NONE address\n", __func__);
+		if (!(mac_cb_is_intrapan(skb))) { /* ! panid compress */
+			IEEE802154_FETCH_U16(skb, mac_cb(skb)->sa.pan_id);
+			pr_debug("%s(): src IEEE802154_FC_INTRA_PAN\n",
+					__func__);
+		}
+
+		if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
+			IEEE802154_FETCH_U16(skb, mac_cb(skb)->sa.short_addr);
+			pr_debug("%s(): src IEEE802154_ADDR_SHORT\n",
+					__func__);
+		} else {
+			IEEE802154_FETCH_U64(skb, mac_cb(skb)->sa.hwaddr);
+			pr_debug("%s(): src hardware addr\n", __func__);
+		}
+	}
+
+	return 0;
+
+exit_error:
+	return -EINVAL;
+}
+
+void ieee802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(hw);
+	struct ieee802154_sub_if_data *sdata, *prev = NULL;
+	int ret;
+
+	BUILD_BUG_ON(sizeof(struct ieee802154_mac_cb) > sizeof(skb->cb));
+	pr_debug("%s()\n", __func__);
+
+	if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
+		u16 crc;
+
+		if (skb->len < 2) {
+			pr_debug("%s(): Got invalid frame\n", __func__);
+			goto out;
+		}
+		crc = crc_ccitt(0, skb->data, skb->len);
+		if (crc) {
+			pr_debug("%s(): CRC mismatch\n", __func__);
+			goto out;
+		}
+		skb_trim(skb, skb->len - 2); /* CRC */
+	}
+
+	ret = parse_frame_start(skb); /* 3 bytes pulled after this */
+	if (ret) {
+		pr_debug("%s(): Got invalid frame\n", __func__);
+		goto out;
+	}
+
+	pr_debug("%s() frame %d\n", __func__, mac_cb_type(skb));
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &priv->slaves, list)
+	{
+		if (prev) {
+			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+			if (skb2)
+				ieee802154_subif_frame(prev, skb2);
+		}
+
+		prev = sdata;
+	}
+
+	if (prev) {
+		ieee802154_subif_frame(prev, skb);
+		skb = NULL;
+	}
+
+	rcu_read_unlock();
+
+out:
+	dev_kfree_skb(skb);
+	return;
+}
+
+u16 ieee802154_dev_get_pan_id(struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+	u16 ret;
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	read_lock(&priv->mib_lock);
+	ret = priv->pan_id;
+	read_unlock(&priv->mib_lock);
+
+	return ret;
+}
+
+u16 ieee802154_dev_get_short_addr(struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+	u16 ret;
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	read_lock(&priv->mib_lock);
+	ret = priv->short_addr;
+	read_unlock(&priv->mib_lock);
+
+	return ret;
+}
+
+void ieee802154_dev_set_pan_id(struct net_device *dev, u16 val)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	write_lock(&priv->mib_lock);
+	priv->pan_id = val;
+	write_unlock(&priv->mib_lock);
+}
+void ieee802154_dev_set_short_addr(struct net_device *dev, u16 val)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	write_lock(&priv->mib_lock);
+	priv->short_addr = val;
+	write_unlock(&priv->mib_lock);
+}
+void ieee802154_dev_set_channel(struct net_device *dev, u8 val)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	write_lock(&priv->mib_lock);
+	priv->chan = val;
+	write_unlock(&priv->mib_lock);
+}
+
+u8 ieee802154_dev_get_dsn(struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+	u16 ret;
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	write_lock(&priv->mib_lock);
+	ret = priv->dsn++;
+	write_unlock(&priv->mib_lock);
+
+	return ret;
+}
+
+u8 ieee802154_dev_get_bsn(struct net_device *dev)
+{
+	struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+	u16 ret;
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	write_lock(&priv->mib_lock);
+	ret = priv->bsn++;
+	write_unlock(&priv->mib_lock);
+
+	return ret;
+}
+
+static int __init ieee802154_dev_init(void)
+{
+	return rtnl_link_register(&wpan_link_ops);
+}
+module_init(ieee802154_dev_init);
+
+static void __exit ieee802154_dev_exit(void)
+{
+	rtnl_link_unregister(&wpan_link_ops);
+}
+module_exit(ieee802154_dev_exit);
+
+MODULE_ALIAS_RTNL_LINK("wpan");
+
diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h
new file mode 100644
index 0000000..f4e8d29
--- /dev/null
+++ b/net/mac802154/mac802154.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007, 2008 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+#ifndef MAC802154_H
+#define MAC802154_H
+
+#include <linux/spinlock.h>
+struct ieee802154_priv {
+	struct ieee802154_dev	hw;
+	struct ieee802154_ops	*ops;
+
+	struct net_device *netdev; /* mwpanX device */
+	int open_count;
+	/* As in mac80211 slaves list is modified:
+	 * 1) under the RTNL
+	 * 2) protected by slaves_mtx;
+	 * 3) in an RCU manner
+	 *
+	 * So atomic readers can use any of this protection methods
+	 */
+	struct list_head	slaves;
+	struct mutex		slaves_mtx;
+	/* This one is used for scanning and other
+	 * jobs not to be interfered with serial driver */
+	struct workqueue_struct	*dev_workqueue;
+};
+
+#define ieee802154_to_priv(_hw)	container_of(_hw, struct ieee802154_priv, hw)
+
+struct ieee802154_sub_if_data {
+	struct list_head list; /* the ieee802154_priv->slaves list */
+
+	struct ieee802154_priv *hw;
+	struct net_device *dev;
+
+	rwlock_t mib_lock;
+
+	u16 pan_id;
+	u16 short_addr;
+
+	u8 chan;
+
+	/* MAC BSN field */
+	u8 bsn;
+	/* MAC BSN field */
+	u8 dsn;
+};
+
+void ieee802154_drop_slaves(struct ieee802154_dev *hw);
+
+void ieee802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb);
+
+struct ieee802154_phy_cb {
+	u8 lqi;
+	u8 chan;
+};
+
+static inline struct ieee802154_phy_cb *phy_cb(struct sk_buff *skb)
+{
+	return (struct ieee802154_phy_cb *)skb->cb;
+}
+
+extern struct ieee802154_mlme_ops mac802154_mlme;
+
+int ieee802154_process_cmd(struct net_device *dev, struct sk_buff *skb);
+
+#endif
diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c
new file mode 100644
index 0000000..8941628
--- /dev/null
+++ b/net/mac802154/mac_cmd.c
@@ -0,0 +1,99 @@
+/*
+ * MAC commands interface
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <net/af_ieee802154.h>
+#include <net/mac802154.h>
+#include <net/ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/nl802154.h>
+
+#include "mac802154.h"
+#include "mib.h"
+
+int ieee802154_process_cmd(struct net_device *dev, struct sk_buff *skb)
+{
+	pr_warning("ieee802154: command frames are not yet supported\n");
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+
+static int ieee802154_mlme_assoc_req(struct net_device *dev,
+		struct ieee802154_addr *addr, u8 channel, u8 cap)
+{
+	/* We simply emulate it here */
+	return ieee802154_nl_assoc_confirm(dev,
+			ieee802154_dev_get_short_addr(dev),
+			IEEE802154_SUCCESS);
+}
+
+static int ieee802154_mlme_assoc_resp(struct net_device *dev,
+		struct ieee802154_addr *addr, u16 short_addr, u8 status)
+{
+	return 0;
+}
+
+static int ieee802154_mlme_disassoc_req(struct net_device *dev,
+		struct ieee802154_addr *addr, u8 reason)
+{
+	return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
+}
+
+static int ieee802154_mlme_start_req(struct net_device *dev,
+				struct ieee802154_addr *addr,
+				u8 channel,
+				u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+				u8 coord_realign)
+{
+	/* We don't emulate beacons here at all, so START should fail */
+	ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER);
+	return 0;
+}
+
+static int ieee802154_mlme_scan_req(struct net_device *dev, u8 type,
+		u32 channels,
+		u8 duration)
+{
+	u8 edl[27] = {};
+	return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
+			channels,
+			type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
+}
+
+
+struct ieee802154_mlme_ops mac802154_mlme = {
+	.assoc_req = ieee802154_mlme_assoc_req,
+	.assoc_resp = ieee802154_mlme_assoc_resp,
+	.disassoc_req = ieee802154_mlme_disassoc_req,
+	.start_req = ieee802154_mlme_start_req,
+	.scan_req = ieee802154_mlme_scan_req,
+
+	.get_pan_id = ieee802154_dev_get_pan_id,
+	.get_short_addr = ieee802154_dev_get_short_addr,
+	.get_dsn = ieee802154_dev_get_dsn,
+	.get_bsn = ieee802154_dev_get_bsn,
+};
+
diff --git a/net/mac802154/mdev.c b/net/mac802154/mdev.c
new file mode 100644
index 0000000..191e942
--- /dev/null
+++ b/net/mac802154/mdev.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2007, 2008 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <net/route.h>
+
+#include <net/af_ieee802154.h>
+#include <net/mac802154.h>
+
+#include "mac802154.h"
+
+struct xmit_work {
+	struct sk_buff *skb;
+	struct work_struct work;
+	struct ieee802154_priv *priv;
+};
+
+static void ieee802154_xmit_worker(struct work_struct *work)
+{
+	struct xmit_work *xw = container_of(work, struct xmit_work, work);
+	int res;
+
+	if (xw->priv->hw.current_channel != phy_cb(xw->skb)->chan) {
+		res = xw->priv->ops->set_channel(&xw->priv->hw,
+				phy_cb(xw->skb)->chan);
+		if (res) {
+			pr_debug("set_channel failed\n");
+			goto out;
+		}
+	}
+
+	res = xw->priv->ops->xmit(&xw->priv->hw, xw->skb);
+
+out:
+	/* FIXME: result processing and/or requeue!!! */
+	dev_kfree_skb(xw->skb);
+
+	kfree(xw);
+}
+
+static int ieee802154_master_hard_start_xmit(struct sk_buff *skb,
+		struct net_device *dev)
+{
+	struct ieee802154_priv *priv = netdev_priv(dev);
+	struct xmit_work *work;
+
+	if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC);
+	if (!work)
+		return NETDEV_TX_BUSY;
+
+	INIT_WORK(&work->work, ieee802154_xmit_worker);
+	work->skb = skb;
+	work->priv = priv;
+
+	queue_work(priv->dev_workqueue, &work->work);
+
+	return NETDEV_TX_OK;
+}
+
+static int ieee802154_master_open(struct net_device *dev)
+{
+	int rc;
+	struct ieee802154_priv *priv = netdev_priv(dev);
+
+	if (!priv) {
+		pr_debug("%s:%s: unable to get master private data\n",
+				__FILE__, __func__);
+		return -ENODEV;
+	}
+
+	if (!priv->open_count)
+		return -EOPNOTSUPP;
+
+	rc = priv->ops->start(&priv->hw);
+
+	if (!rc)
+		netif_tx_start_all_queues(dev);
+
+	return rc;
+}
+
+static int ieee802154_master_close(struct net_device *dev)
+{
+	struct ieee802154_priv *priv = netdev_priv(dev);
+	struct ieee802154_sub_if_data *sdata;
+
+	ASSERT_RTNL();
+
+	/* We are under RTNL, so it's fine to do this */
+	list_for_each_entry(sdata, &priv->slaves, list)
+		if (netif_running(sdata->dev))
+			dev_close(sdata->dev);
+
+	priv->ops->stop(&priv->hw);
+
+	return 0;
+}
+
+static ssize_t ieee802154_netdev_show(const struct device *dev,
+		   struct device_attribute *attr, char *buf,
+		   ssize_t (*format)(const struct net_device *, char *))
+{
+	struct net_device *netdev = to_net_dev(dev);
+	ssize_t ret = -EINVAL;
+
+	if (netdev->reg_state <= NETREG_REGISTERED)
+		ret = (*format)(netdev, buf);
+
+	return ret;
+}
+#define MASTER_SHOW(field, format_string)				\
+static ssize_t format_##field(const struct net_device *dev, char *buf)	\
+{									\
+	struct ieee802154_priv *priv = netdev_priv(dev);		\
+	return sprintf(buf, format_string, priv->hw.field);		\
+}									\
+static ssize_t show_##field(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
+{									\
+	return ieee802154_netdev_show(dev, attr, buf, format_##field);	\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
+
+static const char fmt_long_hex[] = "%#lx\n";
+static const char fmt_hex[] = "%#x\n";
+static const char fmt_dec[] = "%d\n";
+
+MASTER_SHOW(current_channel, fmt_dec);
+MASTER_SHOW(channel_mask, fmt_hex);
+
+static struct attribute *pmib_attrs[] = {
+	&dev_attr_current_channel.attr,
+	&dev_attr_channel_mask.attr,
+	NULL
+};
+
+static struct attribute_group pmib_group = {
+	.name  = "pib",
+	.attrs  = pmib_attrs,
+};
+
+static const struct net_device_ops ieee802154_master_ops = {
+	.ndo_open		= ieee802154_master_open,
+	.ndo_stop		= ieee802154_master_close,
+	.ndo_start_xmit		= ieee802154_master_hard_start_xmit,
+};
+
+static void ieee802154_netdev_setup_master(struct net_device *dev)
+{
+	dev->addr_len		= 0;
+	dev->features		= NETIF_F_NO_CSUM;
+	dev->hard_header_len	= 0;
+	dev->mtu		= 127;
+	dev->tx_queue_len	= 0;
+	dev->type		= ARPHRD_IEEE802154_PHY;
+	dev->flags		= IFF_NOARP | IFF_BROADCAST;
+	dev->watchdog_timeo	= 0;
+
+	dev->netdev_ops = &ieee802154_master_ops;
+}
+
+struct ieee802154_dev *ieee802154_alloc_device(size_t priv_size,
+		struct ieee802154_ops *ops)
+{
+	struct net_device *dev;
+	struct ieee802154_priv *priv;
+
+	dev = alloc_netdev(ALIGN(sizeof(*priv), NETDEV_ALIGN) + priv_size,
+			"mwpan%d", ieee802154_netdev_setup_master);
+	if (!dev) {
+		printk(KERN_ERR
+			"Failure to initialize master IEEE802154 device\n");
+		return NULL;
+	}
+	priv = netdev_priv(dev);
+	priv->netdev = dev;
+	priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN);
+
+	BUG_ON(!dev);
+	BUG_ON(!ops);
+	BUG_ON(!ops->xmit);
+	BUG_ON(!ops->ed);
+	BUG_ON(!ops->start);
+	BUG_ON(!ops->stop);
+
+	if (!try_module_get(ops->owner)) {
+		free_netdev(dev);
+		return NULL;
+	}
+
+	priv->ops = ops;
+
+	INIT_LIST_HEAD(&priv->slaves);
+	mutex_init(&priv->slaves_mtx);
+
+	return &priv->hw;
+}
+EXPORT_SYMBOL(ieee802154_alloc_device);
+
+void ieee802154_free_device(struct ieee802154_dev *hw)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(hw);
+
+	BUG_ON(!list_empty(&priv->slaves));
+	BUG_ON(!priv->netdev);
+
+	module_put(priv->ops->owner);
+
+	free_netdev(priv->netdev);
+}
+EXPORT_SYMBOL(ieee802154_free_device);
+
+int ieee802154_register_device(struct ieee802154_dev *dev)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+	struct net_device *ndev = priv->netdev;
+
+	int rc;
+
+	rtnl_lock();
+	if (strchr(ndev->name, '%')) {
+		rc = dev_alloc_name(ndev, ndev->name);
+		if (rc < 0)
+			goto out_unlock;
+	}
+
+	priv->dev_workqueue =
+		create_singlethread_workqueue(ndev->name);
+	if (!priv->dev_workqueue) {
+		rc = -ENOMEM;
+		goto out_unlock;
+	}
+
+	ndev->needed_headroom = priv->hw.extra_tx_headroom;
+	SET_NETDEV_DEV(ndev, priv->hw.parent);
+
+	ndev->sysfs_groups[1] = &pmib_group;
+
+	rc = register_netdevice(ndev);
+	if (rc < 0)
+		goto out_wq;
+
+	rtnl_unlock();
+
+	return 0;
+
+out_wq:
+	destroy_workqueue(priv->dev_workqueue);
+out_unlock:
+	rtnl_unlock();
+	return rc;
+}
+EXPORT_SYMBOL(ieee802154_register_device);
+
+void ieee802154_unregister_device(struct ieee802154_dev *dev)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+
+	flush_workqueue(priv->dev_workqueue);
+	destroy_workqueue(priv->dev_workqueue);
+
+	rtnl_lock();
+
+	ieee802154_drop_slaves(dev);
+	unregister_netdevice(priv->netdev);
+
+	rtnl_unlock();
+}
+EXPORT_SYMBOL(ieee802154_unregister_device);
+
+MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
+MODULE_LICENSE("GPL v2");
+
diff --git a/net/mac802154/mib.h b/net/mac802154/mib.h
new file mode 100644
index 0000000..57bf03f
--- /dev/null
+++ b/net/mac802154/mib.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef MIB802154_H
+#define MIB802154_H
+
+/* FIXME: should be dropped in favour of generic MIB API */
+u8 ieee802154_dev_get_dsn(struct net_device *dev);
+u8 ieee802154_dev_get_bsn(struct net_device *dev);
+u16 ieee802154_dev_get_pan_id(struct net_device *dev);
+u16 ieee802154_dev_get_short_addr(struct net_device *dev);
+void ieee802154_dev_set_pan_id(struct net_device *dev, u16 val);
+void ieee802154_dev_set_short_addr(struct net_device *dev, u16 val);
+void ieee802154_dev_set_channel(struct net_device *dev, u8 chan);
+
+
+#endif
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
new file mode 100644
index 0000000..81a269e
--- /dev/null
+++ b/net/mac802154/rx.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/netdevice.h>
+
+#include <net/mac802154.h>
+
+#include "mac802154.h"
+
+static void __ieee802154_rx_prepare(struct ieee802154_dev *dev,
+		struct sk_buff *skb, u8 lqi)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+
+	BUG_ON(!skb);
+
+	phy_cb(skb)->lqi = lqi;
+
+	skb->dev = priv->netdev;
+
+	skb->iif = skb->dev->ifindex;
+
+	skb->protocol = htons(ETH_P_IEEE802154);
+
+	skb_reset_mac_header(skb);
+}
+
+void ieee802154_rx(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
+{
+	struct sk_buff *skb2;
+
+	__ieee802154_rx_prepare(dev, skb, lqi);
+
+	skb2 = skb_clone(skb, GFP_KERNEL);
+	netif_rx(skb2);
+
+	ieee802154_subif_rx(dev, skb);
+}
+EXPORT_SYMBOL(ieee802154_rx);
+
+struct rx_work {
+	struct sk_buff *skb;
+	struct work_struct work;
+	struct ieee802154_dev *dev;
+};
+
+static void ieee802154_rx_worker(struct work_struct *work)
+{
+	struct rx_work *rw = container_of(work, struct rx_work, work);
+	struct sk_buff *skb = rw->skb;
+
+	struct sk_buff *skb2 = skb_clone(skb, GFP_KERNEL);
+	netif_rx(skb2);
+
+	ieee802154_subif_rx(rw->dev, skb);
+	kfree(rw);
+}
+
+void ieee802154_rx_irqsafe(struct ieee802154_dev *dev,
+		struct sk_buff *skb, u8 lqi)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+	struct rx_work *work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC);
+
+	if (!work)
+		return;
+
+	__ieee802154_rx_prepare(dev, skb, lqi);
+
+	INIT_WORK(&work->work, ieee802154_rx_worker);
+	work->skb = skb;
+	work->dev = dev;
+
+	queue_work(priv->dev_workqueue, &work->work);
+}
+EXPORT_SYMBOL(ieee802154_rx_irqsafe);
-- 
1.6.3.3


^ permalink raw reply related

* [RFC 0/2] Software implementation of IEEE 802.15.4
From: Dmitry Eremin-Solenikov @ 2009-08-10 14:16 UTC (permalink / raw)
  To: netdev; +Cc: linux-zigbee-devel, linux-wireless, Sergey Lapin


Hi,

In this (small) patchset we'd like to present the grounds of our software
IEEE 802.15.4 MAC implementation. Especially this patchset contains only
packet dissection and data path (in generic parts) and virtual loopback
driver (as an example user).

Please review.

Dmitry Eremin-Solenikov (2):
      mac802154: add a software MAC 802.15.4 implementation
      ieee802154: add virtual loopback driver

 MAINTAINERS                 |    1 +
 drivers/ieee802154/Kconfig  |   13 +
 drivers/ieee802154/Makefile |    1 +
 drivers/ieee802154/fakelb.c |  255 ++++++++++++
 include/linux/mac802154.h   |   35 ++
 include/net/mac802154.h     |  106 +++++
 net/Kconfig                 |    1 +
 net/Makefile                |    1 +
 net/mac802154/Kconfig       |   17 +
 net/mac802154/Makefile      |    4 +
 net/mac802154/dev.c         |  924 +++++++++++++++++++++++++++++++++++++++++++
 net/mac802154/mac802154.h   |   85 ++++
 net/mac802154/mac_cmd.c     |   99 +++++
 net/mac802154/mdev.c        |  295 ++++++++++++++
 net/mac802154/mib.h         |   32 ++
 net/mac802154/rx.c          |   98 +++++
 16 files changed, 1967 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ieee802154/fakelb.c
 create mode 100644 include/linux/mac802154.h
 create mode 100644 include/net/mac802154.h
 create mode 100644 net/mac802154/Kconfig
 create mode 100644 net/mac802154/Makefile
 create mode 100644 net/mac802154/dev.c
 create mode 100644 net/mac802154/mac802154.h
 create mode 100644 net/mac802154/mac_cmd.c
 create mode 100644 net/mac802154/mdev.c
 create mode 100644 net/mac802154/mib.h
 create mode 100644 net/mac802154/rx.c



^ permalink raw reply

* Re: [Bug #13846] LEDs switched off permanently by power saving with rt61pci driver
From: Rafael J. Wysocki @ 2009-08-10 14:06 UTC (permalink / raw)
  To: chris2553; +Cc: Linux Kernel Mailing List, Kernel Testers List, linux-wireless
In-Reply-To: <200908101111.16762.chris2553@googlemail.com>

On Monday 10 August 2009, Chris Clayton wrote:
> Hi Rafael,
> 
> On Sunday 09 August 2009, Rafael J. Wysocki wrote:
> > This message has been generated automatically as a part of a report
> > of recent regressions.
> >
> > The following bug entry is on the current list of known regressions
> > from 2.6.30.  Please verify if it still should be listed and let me know
> > (either way).
> >
> 
> Ivo sent a test patch for this and I tested it., but without success. I reported my findings but 
> didn't get a reply. See http://marc.info/?l=linux-wireless&m=124940189007154&w=4.
> 
> I suspect the failure is due to the same PS hardware probelms that were at the route of my original 
> report.. Unless one of the wireless folks say otherwise, I think we should close this on the basis 
> of busted hardware. I'm happy to simply eject the card and re-insert it now that I have some udev 
> scripts to tear down the wireless configuration on the ejection and set it uop again when the card 
> is re-inserted.

Thanks, closed.

Rafael

^ permalink raw reply

* [PATCH] mac80211: small tx code cleanup
From: Johannes Berg @ 2009-08-10 14:04 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

It's really easier to read if it's not indented
as much, so invert the condition and rearrange
the code so the smaller chunk is indented instead.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 net/mac80211/tx.c |   38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

--- wireless-testing.orig/net/mac80211/tx.c	2009-08-10 13:38:28.000000000 +0200
+++ wireless-testing/net/mac80211/tx.c	2009-08-10 13:39:32.000000000 +0200
@@ -317,30 +317,30 @@ ieee80211_tx_h_multicast_ps_buf(struct i
 	if (!atomic_read(&tx->sdata->bss->num_sta_ps))
 		return TX_CONTINUE;
 
+	/* buffered in hardware */
+	if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) {
+		info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
+
+		return TX_CONTINUE;
+	}
+
 	/* buffered in mac80211 */
-	if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) {
-		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
-			purge_old_ps_buffers(tx->local);
-		if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=
-		    AP_MAX_BC_BUFFER) {
+	if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+		purge_old_ps_buffers(tx->local);
+
+	if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "%s: BC TX buffer full - "
-				       "dropping the oldest frame\n",
-				       tx->dev->name);
-			}
+		if (net_ratelimit())
+			printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n",
+			       tx->dev->name);
 #endif
-			dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
-		} else
-			tx->local->total_ps_buffered++;
-		skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
-		return TX_QUEUED;
-	}
+		dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
+	} else
+		tx->local->total_ps_buffered++;
 
-	/* buffered in hardware */
-	info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
+	skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
 
-	return TX_CONTINUE;
+	return TX_QUEUED;
 }
 
 static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,



^ permalink raw reply

* Re: Libertas: Association request to the driver failed
From: Cyrill Gorcunov @ 2009-08-10 14:04 UTC (permalink / raw)
  To: Roel Kluin
  Cc: Michael Buesch, Daniel Mack, John W. Linville, libertas-dev,
	linux-wireless, linux-kernel
In-Reply-To: <4A7FF84C.7070708@gmail.com>

[Roel Kluin - Mon, Aug 10, 2009 at 12:37:00PM +0200]
...
| > I saw one pattern in trace code (not sure if it's
| > still there) but personally don't like dynamic
| > stack arrays (though at moment the max value
| > being passed into routine is known maybe just
| > use MAX_RATES instead of (*rates_size)?). Hmm?
| 
| Good point.
| 
| > 	-- Cyrill
| 
| Thanks,
| 
| I think there was another problem in lbs_associate(),
| the memcpy already affected rates->rates.
| 

Yeah, something like that. Note that I was only cared about
stack so I didn't dive into details of this code :)

I suppose wireless mainteiners will review it more
precisely. Thanks Roel!

	-- Cyrill

^ permalink raw reply

* [PATCH] mac80211: sequence number micro-optimisation
From: Johannes Berg @ 2009-08-10 14:02 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

There's no need to mask the variable with 0xFFF0
since we ever only use it as a u16 and the lowest
four bits can't ever be non-zero. The compiler
cannot infer the latter, and therefore has to emit
code to do the masking.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 net/mac80211/tx.c |    1 -
 1 file changed, 1 deletion(-)

--- wireless-testing.orig/net/mac80211/tx.c	2009-08-10 13:34:45.000000000 +0200
+++ wireless-testing/net/mac80211/tx.c	2009-08-10 13:34:58.000000000 +0200
@@ -700,7 +700,6 @@ ieee80211_tx_h_sequence(struct ieee80211
 		/* for pure STA mode without beacons, we can do it */
 		hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
 		tx->sdata->sequence_number += 0x10;
-		tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ;
 		return TX_CONTINUE;
 	}
 



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox