Netdev List
 help / color / mirror / Atom feed
* e1000: Detected Tx Unit Hang
From: Bernd Schubert @ 2008-02-15 22:52 UTC (permalink / raw)
  To: netdev

Hello,

I can't login to one of our servers and just got this in an ipmi sol
session:

[18169.209181] e1000: eth0: e1000_clean_tx_irq: Detected Tx Unit Hang
[18169.209183]   Tx Queue             <0>
[18169.209184]   TDH                  <e3>
[18169.209185]   TDT                  <e3>
[18169.209186]   next_to_use          <e3>
[18169.209187]   next_to_clean        <bd>
[18169.209188] buffer_info[next_to_clean]
[18169.209189]   time_stamp           <10043e4d2>
[18169.209190]   next_to_watch        <be>
[18169.209191]   jiffies              <10043e6f6>
[18169.209192]   next_to_watch.status <1>
[18169.256978] e1000: eth2: e1000_clean_tx_irq: Detected Tx Unit Hang
[18169.256979]   Tx Queue             <0>
[18169.256980]   TDH                  <de>
[18169.256982]   TDT                  <de>
[18169.256983]   next_to_use          <de>
[18169.256984]   next_to_clean        <bc>
[18169.256985] buffer_info[next_to_clean]
[18169.256986]   time_stamp           <10043e511>
[18169.256987]   next_to_watch        <bd>
[18169.256988]   jiffies              <10043e701>
[18169.256989]   next_to_watch.status <1>

This is with 2.6.22.18. Is there any chance to recover the system? For some
reasons I would prefer not to reboot now.

Thanks,
Bernd


^ permalink raw reply

* Re: BUG/ spinlock lockup, 2.6.24
From: Jarek Poplawski @ 2008-02-15 22:49 UTC (permalink / raw)
  To: Denys Fedoryshchenko; +Cc: Bart Van Assche, netdev, linux-kernel
In-Reply-To: <47B5FE1E.5080804@gmail.com>

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

Jarek Poplawski wrote, On 02/15/2008 10:03 PM:
...

> ...On the other hand this:
> 
>> Feb 15 15:50:17 217.151.X.X [1521315.068984] BUG: spinlock lockup on CPU#1, 
>> ksoftirqd/1/7, f0551180
> 
> seems to point just at spinlock lockup, so it's more about the full report.
> I wonder if this patch to prink could help here:
> 
> author	Ingo Molnar <mingo at elte.hu>
> 	Fri, 25 Jan 2008 20:07:58 +0000 (21:07 +0100)
> printk: make printk more robust by not allowing recursion
> 
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=32a76006683f7b28ae3cc491da37716e002f198e


...or maybe a patch like this attached here?

Jarek P.

[-- Attachment #2: spinlock_debug.diff --]
[-- Type: text/x-diff, Size: 733 bytes --]

diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 9c4b025..21c8aaa 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -111,8 +111,7 @@ static void __spin_lock_debug(spinlock_t *lock)
 			__delay(1);
 		}
 		/* lockup suspected: */
-		if (print_once) {
-			print_once = 0;
+		if (print_once == 1) {
 			printk(KERN_EMERG "BUG: spinlock lockup on CPU#%d, "
 					"%s/%d, %p\n",
 				raw_smp_processor_id(), current->comm,
@@ -122,7 +121,14 @@ static void __spin_lock_debug(spinlock_t *lock)
 			trigger_all_cpu_backtrace();
 #endif
 		}
+		if (print_once++ > 1000)
+			goto out;
 	}
+	return;
+out:
+	panic("spinlock lockup panic #%llu\n", i);
+	// or:
+	// BUG();
 }
 
 void _raw_spin_lock(spinlock_t *lock)

^ permalink raw reply related

* Re: [PATCH] (02/14/08 Linus git) Smack unlabeled outgoing ambient packets - v3
From: Casey Schaufler @ 2008-02-15 22:39 UTC (permalink / raw)
  To: Paul Moore, casey; +Cc: akpm, torvalds, linux-kernel, netdev
In-Reply-To: <200802151637.14835.paul.moore@hp.com>


--- Paul Moore <paul.moore@hp.com> wrote:


> > Yerk. I can put that fix into my tree, but my patch without
> > the "correction" makes sockets behave very badly. I can't have
> > people using it without Pavel's fix. Any notion on the plans to
> > get that in?
> 
> FYI, it looks like Linus just tagged -rc2 and it does have the fix you 
> need.

Thank you. Verification in progress.


Casey Schaufler
casey@schaufler-ca.com

^ permalink raw reply

* [PATCH] igb: fix legacy mode irq issue
From: Auke Kok @ 2008-02-15 22:05 UTC (permalink / raw)
  To: jeff; +Cc: netdev, e1000-devel, andy

From: Andy Gospodarek <andy@greyhouse.net>

I booted an igb kernel with the option pci=nomsi and instantly noticed
that interrupts no longer worked on my igb device.  I took a look at the
interrupt initialization and quickly discovered a comment stating:

"DO NOT USE EIAME or IAME in legacy mode"

It seemed a bit odd that bits to enable IAM were being set in legacy
interrupt mode, so I dropped out the following parts and interrupts
began working fine again.

[Updated code flow and a nitpick spelling error --Auke]

Signed-off-by: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/igb/igb_main.c |    9 ++-------
 1 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index bff280e..3480cc7 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -439,7 +439,7 @@ static int igb_request_irq(struct igb_adapter *adapter)
 		err = igb_request_msix(adapter);
 		if (!err) {
 			/* enable IAM, auto-mask,
-			 * DO NOT USE EIAME or IAME in legacy mode */
+			 * DO NOT USE EIAM or IAM in legacy mode */
 			wr32(E1000_IAM, IMS_ENABLE_MASK);
 			goto request_done;
 		}
@@ -465,14 +465,9 @@ static int igb_request_irq(struct igb_adapter *adapter)
 	err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED,
 			  netdev->name, netdev);
 
-	if (err) {
+	if (err)
 		dev_err(&adapter->pdev->dev, "Error %d getting interrupt\n",
 			err);
-		goto request_done;
-	}
-
-	/* enable IAM, auto-mask */
-	wr32(E1000_IAM, IMS_ENABLE_MASK);
 
 request_done:
 	return err;


^ permalink raw reply related

* RE: [PATCH] fs_enet: Don't call phy_mii_ioctl() in atomic context.
From: Rune Torgersen @ 2008-02-15 21:47 UTC (permalink / raw)
  To: Scott Wood, jgarzik; +Cc: netdev, linuxppc-dev
In-Reply-To: <20080215210804.GA14468@loki.buserror.net>

Scott Wood wrote:
> The lock acquisition in fs_ioctl() does not appear to actually be
> necessary, and thus is simply removed.
> 
> Signed-off-by: Scott Wood <scottwood@freescale.com> ---
> This fixes the following bug:
> http://ozlabs.org/pipermail/linuxppc-dev/2008-February/051564.html
> 
>  drivers/net/fs_enet/fs_enet-main.c |    7 +------
>  1 files changed, 1 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/fs_enet/fs_enet-main.c
> b/drivers/net/fs_enet/fs_enet-main.c
> index 42d94ed..af869cf 100644
> --- a/drivers/net/fs_enet/fs_enet-main.c
> +++ b/drivers/net/fs_enet/fs_enet-main.c
> @@ -946,16 +946,11 @@ static int fs_ioctl(struct net_device
> *dev, struct ifreq *rq, int cmd)
>  {
>  	struct fs_enet_private *fep = netdev_priv(dev);
>  	struct mii_ioctl_data *mii = (struct mii_ioctl_data
*)&rq->ifr_data;
> -	unsigned long flags;
> -	int rc;
> 
>  	if (!netif_running(dev))
>  		return -EINVAL;
> 
> -	spin_lock_irqsave(&fep->lock, flags);
> -	rc = phy_mii_ioctl(fep->phydev, mii, cmd);
> -	spin_unlock_irqrestore(&fep->lock, flags);
> -	return rc;
> +	return phy_mii_ioctl(fep->phydev, mii, cmd);
>  }
> 
>  extern int fs_mii_connect(struct net_device *dev);

Acked-by: Rune Torgersen <runet@innovsys.com>

Tested it and it does indeed take care of the bug.

^ permalink raw reply

* Re: [PATCH] (02/14/08 Linus git) Smack unlabeled outgoing ambient packets - v3
From: Paul Moore @ 2008-02-15 21:37 UTC (permalink / raw)
  To: casey; +Cc: akpm, torvalds, linux-kernel, netdev
In-Reply-To: <291070.74513.qm@web36606.mail.mud.yahoo.com>

On Friday 15 February 2008 4:00:26 pm Casey Schaufler wrote:
> --- Paul Moore <paul.moore@hp.com> wrote:
> > On Friday 15 February 2008 12:38:49 am Casey Schaufler wrote:
> > > From: Casey Schaufler <casey@schaufler-ca.com>
> > >
> > > Smack uses CIPSO labeling, but allows for unlabeled packets
> > > by specifying an "ambient" label that is applied to incoming
> > > unlabeled packets. Because the other end of the connection
> > > may dislike IP options, and ssh is one know application that
> > > behaves thus, it is prudent to respond in kind. This patch
> > > changes the network labeling behavior such that an outgoing
> > > packet that would be given a CIPSO label that matches the
> > > ambient label is left unlabeled. An "unlbl" domain is added
> > > and the netlabel defaulting mechanism invoked rather than
> > > assuming that everything is CIPSO. Locking has been added
> > > around changes to the ambient label as the mechanisms used
> > > to do so are more involved.
> > >
> > > Cleaned up some issues noted in review.
> > > Make smk_cipso_doi() static.
> > > Create a hook for the new security_secctx_to_secid()
> > > using existing underlying code.
> > > Fill in audit data for netlbl domain calls.
> > > Collapse unnecessary multiple assignments.
> > >
> > > Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> >
> > Hi Casey,
> >
> > Thanks for the update, it's much improved.  I'd ack it except for
> > one last thing which popped up in this revision ... (and don't
> > worry, it's kinda my fault - not yours) ...
> >
> > > @@ -1282,15 +1281,21 @@ static int smack_netlabel(struct sock *s
> > >  {
> > >  	struct socket_smack *ssp;
> > >  	struct netlbl_lsm_secattr secattr;
> > > -	int rc = 0;
> > > +	int rc;
> > >
> > >  	ssp = sk->sk_security;
> > >  	netlbl_secattr_init(&secattr);
> > >  	smack_to_secattr(ssp->smk_out, &secattr);
> > > -	if (secattr.flags != NETLBL_SECATTR_NONE)
> > > -		rc = netlbl_sock_setattr(sk, &secattr);
> > > -
> > > +	rc = netlbl_sock_setattr(sk, &secattr);
> > >  	netlbl_secattr_destroy(&secattr);
> > > +
> > > +	/*
> > > +	 * A return of -ENOENT from netlbl_sock_setattr
> > > +	 * indicates that the "domain" was not found, but that's
> > > +	 * not an issue because of the defaulting behavior.
> > > +	 */
> > > +	if (rc == -ENOENT)
> > > +		rc = 0;
> > >  	return rc;
> > >  }
> >
> > ... you shouldn't fix-up the return value from
> > netlbl_sock_setattr(). It only returns an error when there really
> > is an error, if there are no matching domain mappings and the
> > default catches the "domain" then the function will return 0
> > (assuming no other failures).
> >
> > The fact that you ran into this problem isn't your fault, it's
> > mine, but thankfully for both of us Pavel Emelyanov found this bug
> > and fixed it[1].  It hasn't hit Linus' tree yet but it's in the
> > net-2.6 tree.  If you can't wait for it to hit Linus' tree you can
> > always apply the fix by hand, it's pretty minor.
> >
> > Sorry about that.
>
> [1]http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=comm
>it;h=4c3a0a254e5d706d3fe01bf42261534858d05586
>
> Yerk. I can put that fix into my tree, but my patch without
> the "correction" makes sockets behave very badly. I can't have
> people using it without Pavel's fix. Any notion on the plans to
> get that in?

FYI, it looks like Linus just tagged -rc2 and it does have the fix you 
need.

-- 
paul moore
linux security @ hp

^ permalink raw reply

* [PATCH] fs_enet: Don't call phy_mii_ioctl() in atomic context.
From: Scott Wood @ 2008-02-15 21:08 UTC (permalink / raw)
  To: jgarzik; +Cc: netdev, linuxppc-dev, Rune Torgersen

The lock acquisition in fs_ioctl() does not appear to actually be necessary,
and thus is simply removed.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
This fixes the following bug:
http://ozlabs.org/pipermail/linuxppc-dev/2008-February/051564.html

 drivers/net/fs_enet/fs_enet-main.c |    7 +------
 1 files changed, 1 insertions(+), 6 deletions(-)

diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 42d94ed..af869cf 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -946,16 +946,11 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 	struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
-	unsigned long flags;
-	int rc;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	spin_lock_irqsave(&fep->lock, flags);
-	rc = phy_mii_ioctl(fep->phydev, mii, cmd);
-	spin_unlock_irqrestore(&fep->lock, flags);
-	return rc;
+	return phy_mii_ioctl(fep->phydev, mii, cmd);
 }
 
 extern int fs_mii_connect(struct net_device *dev);
-- 
1.5.3.8

^ permalink raw reply related

* Re: [PATCH] (02/14/08 Linus git) Smack unlabeled outgoing ambient packets - v3
From: Paul Moore @ 2008-02-15 21:08 UTC (permalink / raw)
  To: casey; +Cc: akpm, torvalds, linux-kernel, netdev
In-Reply-To: <291070.74513.qm@web36606.mail.mud.yahoo.com>

On Friday 15 February 2008 4:00:26 pm Casey Schaufler wrote:
> --- Paul Moore <paul.moore@hp.com> wrote:
> > On Friday 15 February 2008 12:38:49 am Casey Schaufler wrote:
> > ... you shouldn't fix-up the return value from
> > netlbl_sock_setattr(). It only returns an error when there really
> > is an error, if there are no matching domain mappings and the
> > default catches the "domain" then the function will return 0
> > (assuming no other failures).
> >
> > The fact that you ran into this problem isn't your fault, it's
> > mine, but thankfully for both of us Pavel Emelyanov found this bug
> > and fixed it[1].  It hasn't hit Linus' tree yet but it's in the
> > net-2.6 tree.  If you can't wait for it to hit Linus' tree you can
> > always apply the fix by hand, it's pretty minor.
> >
> > Sorry about that.
>
> [1]http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=comm
>it;h=4c3a0a254e5d706d3fe01bf42261534858d05586
>
> Yerk. I can put that fix into my tree, but my patch without
> the "correction" makes sockets behave very badly. I can't have
> people using it without Pavel's fix. Any notion on the plans to
> get that in?

It is already "in", it just hasn't percolated up to Linus' tree yet.  In 
the past I've always dealt with similar issues by just waiting until 
the patch I need has hit Linus' tree then submitted my patch.  If you 
can't wait, you can always rebase your patch against the net-2.6 tree 
(should be no work at all) and if DaveM doesn't have a problem pulling 
your patch into the net-2.6 tree you can always send it up that way.

-- 
paul moore
linux security @ hp

^ permalink raw reply

* Re: [PATCH] (02/14/08 Linus git) Smack unlabeled outgoing ambient packets - v3
From: Casey Schaufler @ 2008-02-15 21:00 UTC (permalink / raw)
  To: Paul Moore, casey; +Cc: akpm, torvalds, linux-kernel, netdev
In-Reply-To: <200802151359.35049.paul.moore@hp.com>


--- Paul Moore <paul.moore@hp.com> wrote:

> On Friday 15 February 2008 12:38:49 am Casey Schaufler wrote:
> > From: Casey Schaufler <casey@schaufler-ca.com>
> >
> > Smack uses CIPSO labeling, but allows for unlabeled packets
> > by specifying an "ambient" label that is applied to incoming
> > unlabeled packets. Because the other end of the connection
> > may dislike IP options, and ssh is one know application that
> > behaves thus, it is prudent to respond in kind. This patch
> > changes the network labeling behavior such that an outgoing
> > packet that would be given a CIPSO label that matches the
> > ambient label is left unlabeled. An "unlbl" domain is added
> > and the netlabel defaulting mechanism invoked rather than
> > assuming that everything is CIPSO. Locking has been added
> > around changes to the ambient label as the mechanisms used
> > to do so are more involved.
> >
> > Cleaned up some issues noted in review.
> > Make smk_cipso_doi() static.
> > Create a hook for the new security_secctx_to_secid()
> > using existing underlying code.
> > Fill in audit data for netlbl domain calls.
> > Collapse unnecessary multiple assignments.
> >
> > Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> 
> Hi Casey,
> 
> Thanks for the update, it's much improved.  I'd ack it except for one 
> last thing which popped up in this revision ... (and don't worry, it's 
> kinda my fault - not yours) ...
> 
> > @@ -1282,15 +1281,21 @@ static int smack_netlabel(struct sock *s
> >  {
> >  	struct socket_smack *ssp;
> >  	struct netlbl_lsm_secattr secattr;
> > -	int rc = 0;
> > +	int rc;
> >
> >  	ssp = sk->sk_security;
> >  	netlbl_secattr_init(&secattr);
> >  	smack_to_secattr(ssp->smk_out, &secattr);
> > -	if (secattr.flags != NETLBL_SECATTR_NONE)
> > -		rc = netlbl_sock_setattr(sk, &secattr);
> > -
> > +	rc = netlbl_sock_setattr(sk, &secattr);
> >  	netlbl_secattr_destroy(&secattr);
> > +
> > +	/*
> > +	 * A return of -ENOENT from netlbl_sock_setattr
> > +	 * indicates that the "domain" was not found, but that's
> > +	 * not an issue because of the defaulting behavior.
> > +	 */
> > +	if (rc == -ENOENT)
> > +		rc = 0;
> >  	return rc;
> >  }
> 
> ... you shouldn't fix-up the return value from netlbl_sock_setattr().  
> It only returns an error when there really is an error, if there are no 
> matching domain mappings and the default catches the "domain" then the 
> function will return 0 (assuming no other failures).
> 
> The fact that you ran into this problem isn't your fault, it's mine, but 
> thankfully for both of us Pavel Emelyanov found this bug and fixed 
> it[1].  It hasn't hit Linus' tree yet but it's in the net-2.6 tree.  If 
> you can't wait for it to hit Linus' tree you can always apply the fix 
> by hand, it's pretty minor.
> 
> Sorry about that.
> 
>
[1]http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=commit;h=4c3a0a254e5d706d3fe01bf42261534858d05586

Yerk. I can put that fix into my tree, but my patch without
the "correction" makes sockets behave very badly. I can't have
people using it without Pavel's fix. Any notion on the plans to
get that in?

Thank you.


Casey Schaufler
casey@schaufler-ca.com

^ permalink raw reply

* Re: BUG/ spinlock lockup, 2.6.24
From: Jarek Poplawski @ 2008-02-15 21:03 UTC (permalink / raw)
  Cc: Denys Fedoryshchenko, Bart Van Assche, netdev, linux-kernel
In-Reply-To: <47B5F462.40603@gmail.com>

Jarek Poplawski wrote, On 02/15/2008 09:21 PM:

> Denys Fedoryshchenko wrote, On 02/15/2008 08:42 PM:
> ...
> 
>> I have similar crashes on completely different hardware with same job (QOS), 
>> so i think it is actually some nasty bug in networking.
> 
> Maybe you could try with some other debugging options? E.g. since lockdep
> doesn't help - turn this off. Instead try some others, like these:

...On the other hand this:

> Feb 15 15:50:17 217.151.X.X [1521315.068984] BUG: spinlock lockup on CPU#1, 
> ksoftirqd/1/7, f0551180

seems to point just at spinlock lockup, so it's more about the full report.
I wonder if this patch to prink could help here:

author	Ingo Molnar <mingo at elte.hu>
	Fri, 25 Jan 2008 20:07:58 +0000 (21:07 +0100)
printk: make printk more robust by not allowing recursion

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=32a76006683f7b28ae3cc491da37716e002f198e

Jarek P.

^ permalink raw reply

* Re: BUG/ spinlock lockup, 2.6.24
From: Jarek Poplawski @ 2008-02-15 20:21 UTC (permalink / raw)
  To: Denys Fedoryshchenko; +Cc: Bart Van Assche, netdev, linux-kernel
In-Reply-To: <20080215193854.M55147@visp.net.lb>

Denys Fedoryshchenko wrote, On 02/15/2008 08:42 PM:
...

> I have similar crashes on completely different hardware with same job (QOS), 
> so i think it is actually some nasty bug in networking.

Maybe you could try with some other debugging options? E.g. since lockdep
doesn't help - turn this off. Instead try some others, like these:

> # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
> # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
> # CONFIG_DEBUG_KOBJECT is not set
> # CONFIG_DEBUG_HIGHMEM is not set
> # CONFIG_DEBUG_VM is not set
> # CONFIG_DEBUG_LIST is not set
> # CONFIG_DEBUG_SG is not set
> # CONFIG_BOOT_PRINTK_DELAY is not set
> # CONFIG_DEBUG_STACKOVERFLOW is not set
> # CONFIG_DEBUG_STACK_USAGE is not set
> # CONFIG_DEBUG_RODATA is not set

Regards,
Jarek P.

^ permalink raw reply

* Re: BUG/ spinlock lockup, 2.6.24
From: Denys Fedoryshchenko @ 2008-02-15 19:42 UTC (permalink / raw)
  To: Bart Van Assche; +Cc: netdev, linux-kernel
In-Reply-To: <e2e108260802150724k4e5e6089mcb603b524157a9bc@mail.gmail.com>

This server was working fine under load under FreeBSD, and worked fine before 
with other tasks under Linux. I dont think it is RAM.
Additionally it is server hardware (Dell PowerEdge) with ECC, MCE and other 
layers, who will report about any hardware issue most probably, and i think 
even better than memtest. 
Additionally it is very difficult to run test on it, cause it is in another 
country, and i have limited access to it (i dont have network KVM).

I have similar crashes on completely different hardware with same job (QOS), 
so i think it is actually some nasty bug in networking.


On Fri, 15 Feb 2008 16:24:56 +0100, Bart Van Assche wrote
> 2008/2/15 Denys Fedoryshchenko <denys@visp.net.lb>:
> >  I have random crashes, at least once per week. It is very difficult to 
catch
> >  error message, and only recently i setup netconsole. Now i got crash, but
> >  there is no traceback and only single line came over netconsole, 
mentioned
> >  before.
> 
> Did you already run memtest ? You can run memtest by booting from the
> Knoppix CD-ROM or DVD. Most Linux distributions also have included
> memtest on their bootable distribution CD's/DVD's.
> 
> Bart Van Assche.
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
Denys Fedoryshchenko
Technical Manager
Virtual ISP S.A.L.


^ permalink raw reply

* pull request: wireless-2.6 'fixes' 2008-02-15
From: John W. Linville @ 2008-02-15 19:17 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-wireless

Dave,

A handful of (mostly) fixes for 2.6.25.  Also included are b43 patches
and their b43legacy counterparts that only add some debugging output
that should aid in diagnosing problems with those drivers.

Let me know if there are problems!

Thanks,

John

---

Individual patches are available here:

	http://www.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6/fixes

---

The following changes since commit 19af35546de68c872dcb687613e0902a602cb20e:
  Linus Torvalds (1):
        Linux 2.6.25-rc1

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git fixes

Bruno Randolf (1):
      ath5k: correct padding in tx descriptors

Dan Williams (1):
      ipw2200: fix ucode assertion for RX queue overrun

Gregory Greenman (1):
      iwlwifi: Don't send host commands on rfkill

Ivo van Doorn (1):
      rt2x00: Add new USB ID to rt2500usb

John W. Linville (1):
      wavelan: mark hardware interfacing structures as packed

Jussi Kivilinna (1):
      rndis_wlan: enable stall workaround by link quality instead of link speed

Michael Buesch (4):
      b43: Add driver load messages
      b43: Add firmware information to modinfo
      b43: Fix firmware load message level
      mac80211: Fix initial hardware configuration

Mohamed Abbas (1):
      iwlwifi: earlier rx allocation

Reinette Chatre (2):
      iwlwifi: do not clear GEO_CONFIGURED bit when calling _down
      iwlwifi: only check for association id when associating with AP

Stefano Brivio (4):
      b43legacy: fix DMA for 30/32-bit DMA engines
      b43legacy: add firmware information to modinfo
      b43legacy: fix firmware load message level
      b43legacy: Add driver load messages

Tomas Winkler (1):
      iwlwifi: reverting 'misc wireless annotations' patch for iwlwifi

 drivers/net/wireless/ath5k/base.c           |    4 +-
 drivers/net/wireless/ath5k/hw.c             |   34 +++---
 drivers/net/wireless/b43/b43.h              |    6 +
 drivers/net/wireless/b43/main.c             |   40 ++++++-
 drivers/net/wireless/b43legacy/b43legacy.h  |    4 +
 drivers/net/wireless/b43legacy/dma.c        |  167 +++++++++++++++++----------
 drivers/net/wireless/b43legacy/dma.h        |   33 ++----
 drivers/net/wireless/b43legacy/main.c       |   41 ++++++-
 drivers/net/wireless/ipw2200.c              |   45 ++++++--
 drivers/net/wireless/iwlwifi/iwl3945-base.c |   19 +++-
 drivers/net/wireless/iwlwifi/iwl4965-base.c |   17 ++-
 drivers/net/wireless/rndis_wlan.c           |   14 +--
 drivers/net/wireless/rt2x00/rt2500usb.c     |    2 +-
 drivers/net/wireless/wavelan.h              |    6 +-
 net/mac80211/ieee80211.c                    |    5 +-
 15 files changed, 291 insertions(+), 146 deletions(-)

diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index ddc8714..dfdaec0 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1256,7 +1256,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
 	if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
 		flags |= AR5K_TXDESC_NOACK;
 
-	pktlen = skb->len + FCS_LEN;
+	pktlen = skb->len;
 
 	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
 		keyidx = ctl->key_idx;
@@ -1952,7 +1952,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
 	}
 
 	ds->ds_data = bf->skbaddr;
-	ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN,
+	ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
 			ieee80211_get_hdrlen_from_skb(skb),
 			AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1,
 			AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0);
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
index 3a4bf40..1ab57aa 100644
--- a/drivers/net/wireless/ath5k/hw.c
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -3506,7 +3506,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
 {
 	u32 frame_type;
 	struct ath5k_hw_2w_tx_desc *tx_desc;
-	unsigned int buff_len;
+	unsigned int frame_len;
 
 	tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
 
@@ -3537,22 +3537,25 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
 	/* Setup control descriptor */
 
 	/* Verify and set frame length */
-	if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+
+	/* remove padding we might have added before */
+	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+
+	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
 		return -EINVAL;
 
-	tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+	tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
 
 	/* Verify and set buffer length */
-	buff_len = pkt_len - FCS_LEN;
 
 	/* NB: beacon's BufLen must be a multiple of 4 bytes */
 	if(type == AR5K_PKT_TYPE_BEACON)
-		buff_len = roundup(buff_len, 4);
+		pkt_len = roundup(pkt_len, 4);
 
-	if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
 		return -EINVAL;
 
-	tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+	tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
 
 	/*
 	 * Verify and set header length
@@ -3634,7 +3637,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
 {
 	struct ath5k_hw_4w_tx_desc *tx_desc;
 	struct ath5k_hw_tx_status *tx_status;
-	unsigned int buff_len;
+	unsigned int frame_len;
 
 	ATH5K_TRACE(ah->ah_sc);
 	tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
@@ -3669,22 +3672,25 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
 	/* Setup control descriptor */
 
 	/* Verify and set frame length */
-	if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+
+	/* remove padding we might have added before */
+	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+
+	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
 		return -EINVAL;
 
-	tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+	tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
 
 	/* Verify and set buffer length */
-	buff_len = pkt_len - FCS_LEN;
 
 	/* NB: beacon's BufLen must be a multiple of 4 bytes */
 	if(type == AR5K_PKT_TYPE_BEACON)
-		buff_len = roundup(buff_len, 4);
+		pkt_len = roundup(pkt_len, 4);
 
-	if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
 		return -EINVAL;
 
-	tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+	tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
 
 	tx_desc->tx_control_0 |=
 		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 08a011f..f13346b 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -14,6 +14,12 @@
 #include "lo.h"
 #include "phy.h"
 
+
+/* The unique identifier of the firmware that's officially supported by
+ * this driver version. */
+#define B43_SUPPORTED_FIRMWARE_ID	"FW13"
+
+
 #ifdef CONFIG_B43_DEBUG
 # define B43_DEBUG	1
 #else
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index ef65c41..51dfce1 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -58,6 +58,8 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
+MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
+
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
@@ -1859,11 +1861,11 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 		err = -EOPNOTSUPP;
 		goto error;
 	}
-	b43dbg(dev->wl, "Loading firmware version %u.%u "
-	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
-	       fwrev, fwpatch,
-	       (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
-	       (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+	b43info(dev->wl, "Loading firmware version %u.%u "
+		"(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
+		fwrev, fwpatch,
+		(fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+		(fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
 
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
@@ -4200,6 +4202,33 @@ static struct ssb_driver b43_ssb_driver = {
 	.resume		= b43_resume,
 };
 
+static void b43_print_driverinfo(void)
+{
+	const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
+		   *feat_leds = "", *feat_rfkill = "";
+
+#ifdef CONFIG_B43_PCI_AUTOSELECT
+	feat_pci = "P";
+#endif
+#ifdef CONFIG_B43_PCMCIA
+	feat_pcmcia = "M";
+#endif
+#ifdef CONFIG_B43_NPHY
+	feat_nphy = "N";
+#endif
+#ifdef CONFIG_B43_LEDS
+	feat_leds = "L";
+#endif
+#ifdef CONFIG_B43_RFKILL
+	feat_rfkill = "R";
+#endif
+	printk(KERN_INFO "Broadcom 43xx driver loaded "
+	       "[ Features: %s%s%s%s%s, Firmware-ID: "
+	       B43_SUPPORTED_FIRMWARE_ID " ]\n",
+	       feat_pci, feat_pcmcia, feat_nphy,
+	       feat_leds, feat_rfkill);
+}
+
 static int __init b43_init(void)
 {
 	int err;
@@ -4211,6 +4240,7 @@ static int __init b43_init(void)
 	err = ssb_driver_register(&b43_ssb_driver);
 	if (err)
 		goto err_pcmcia_exit;
+	b43_print_driverinfo();
 
 	return err;
 
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index c80edd2..93d45b7 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -23,6 +23,10 @@
 #include "phy.h"
 
 
+/* The unique identifier of the firmware that's officially supported by this
+ * driver version. */
+#define B43legacy_SUPPORTED_FIRMWARE_ID	"FW10"
+
 #define B43legacy_IRQWAIT_MAX_RETRIES	20
 
 #define B43legacy_RX_MAX_SSI		60 /* best guess at max ssi */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 6e08405..e87b427 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -354,7 +354,8 @@ return 0;
 }
 
 
-u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
+static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type,
+					int controller_idx)
 {
 	static const u16 map64[] = {
 		B43legacy_MMIO_DMA64_BASE0,
@@ -373,7 +374,7 @@ u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
 		B43legacy_MMIO_DMA32_BASE5,
 	};
 
-	if (dma64bit) {
+	if (type == B43legacy_DMA_64BIT) {
 		B43legacy_WARN_ON(!(controller_idx >= 0 &&
 				  controller_idx < ARRAY_SIZE(map64)));
 		return map64[controller_idx];
@@ -480,8 +481,9 @@ static void free_ringmemory(struct b43legacy_dmaring *ring)
 }
 
 /* Reset the RX DMA channel */
-int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
-				     u16 mmio_base, int dma64)
+static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+					    u16 mmio_base,
+					    enum b43legacy_dmatype type)
 {
 	int i;
 	u32 value;
@@ -489,13 +491,14 @@ int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
 
 	might_sleep();
 
-	offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
+	offset = (type == B43legacy_DMA_64BIT) ?
+		 B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
 	b43legacy_write32(dev, mmio_base + offset, 0);
 	for (i = 0; i < 10; i++) {
-		offset = dma64 ? B43legacy_DMA64_RXSTATUS :
-			 B43legacy_DMA32_RXSTATUS;
+		offset = (type == B43legacy_DMA_64BIT) ?
+			 B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS;
 		value = b43legacy_read32(dev, mmio_base + offset);
-		if (dma64) {
+		if (type == B43legacy_DMA_64BIT) {
 			value &= B43legacy_DMA64_RXSTAT;
 			if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
 				i = -1;
@@ -519,8 +522,9 @@ int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
 }
 
 /* Reset the RX DMA channel */
-int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
-				     u16 mmio_base, int dma64)
+static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+					    u16 mmio_base,
+					    enum b43legacy_dmatype type)
 {
 	int i;
 	u32 value;
@@ -529,10 +533,10 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
 	might_sleep();
 
 	for (i = 0; i < 10; i++) {
-		offset = dma64 ? B43legacy_DMA64_TXSTATUS :
-			 B43legacy_DMA32_TXSTATUS;
+		offset = (type == B43legacy_DMA_64BIT) ?
+			 B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
 		value = b43legacy_read32(dev, mmio_base + offset);
-		if (dma64) {
+		if (type == B43legacy_DMA_64BIT) {
 			value &= B43legacy_DMA64_TXSTAT;
 			if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
 			    value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
@@ -547,13 +551,14 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
 		}
 		msleep(1);
 	}
-	offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL;
+	offset = (type == B43legacy_DMA_64BIT) ? B43legacy_DMA64_TXCTL :
+						 B43legacy_DMA32_TXCTL;
 	b43legacy_write32(dev, mmio_base + offset, 0);
 	for (i = 0; i < 10; i++) {
-		offset = dma64 ? B43legacy_DMA64_TXSTATUS :
-			 B43legacy_DMA32_TXSTATUS;
+		offset = (type == B43legacy_DMA_64BIT) ?
+			 B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
 		value = b43legacy_read32(dev, mmio_base + offset);
-		if (dma64) {
+		if (type == B43legacy_DMA_64BIT) {
 			value &= B43legacy_DMA64_TXSTAT;
 			if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
 				i = -1;
@@ -578,6 +583,32 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
 	return 0;
 }
 
+/* Check if a DMA mapping address is invalid. */
+static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
+					dma_addr_t addr,
+					size_t buffersize)
+{
+	if (unlikely(dma_mapping_error(addr)))
+		return 1;
+
+	switch (ring->type) {
+	case B43legacy_DMA_30BIT:
+		if ((u64)addr + buffersize > (1ULL << 30))
+			return 1;
+		break;
+	case B43legacy_DMA_32BIT:
+		if ((u64)addr + buffersize > (1ULL << 32))
+			return 1;
+		break;
+	case B43legacy_DMA_64BIT:
+		/* Currently we can't have addresses beyond 64 bits in the kernel. */
+		break;
+	}
+
+	/* The address is OK. */
+	return 0;
+}
+
 static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
 			       struct b43legacy_dmadesc_generic *desc,
 			       struct b43legacy_dmadesc_meta *meta,
@@ -595,7 +626,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data,
 				 ring->rx_buffersize, 0);
-	if (dma_mapping_error(dmaaddr)) {
+	if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
 		/* ugh. try to realloc in zone_dma */
 		gfp_flags |= GFP_DMA;
 
@@ -608,7 +639,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
 					 ring->rx_buffersize, 0);
 	}
 
-	if (dma_mapping_error(dmaaddr)) {
+	if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
 		dev_kfree_skb_any(skb);
 		return -EIO;
 	}
@@ -674,7 +705,7 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring)
 	u32 trans = ssb_dma_translation(ring->dev->dev);
 
 	if (ring->tx) {
-		if (ring->dma64) {
+		if (ring->type == B43legacy_DMA_64BIT) {
 			u64 ringbase = (u64)(ring->dmabase);
 
 			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -709,7 +740,7 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring)
 		err = alloc_initial_descbuffers(ring);
 		if (err)
 			goto out;
-		if (ring->dma64) {
+		if (ring->type == B43legacy_DMA_64BIT) {
 			u64 ringbase = (u64)(ring->dmabase);
 
 			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -760,16 +791,16 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
 {
 	if (ring->tx) {
 		b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
-						 ring->dma64);
-		if (ring->dma64) {
+						 ring->type);
+		if (ring->type == B43legacy_DMA_64BIT) {
 			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
 			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
 		} else
 			b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
 	} else {
 		b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
-						 ring->dma64);
-		if (ring->dma64) {
+						 ring->type);
+		if (ring->type == B43legacy_DMA_64BIT) {
 			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
 			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
 		} else
@@ -824,11 +855,10 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev)
 
 /* Main initialization function. */
 static
-struct b43legacy_dmaring *b43legacy_setup_dmaring(
-					struct b43legacy_wldev *dev,
-					int controller_index,
-					int for_tx,
-					int dma64)
+struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
+						  int controller_index,
+						  int for_tx,
+						  enum b43legacy_dmatype type)
 {
 	struct b43legacy_dmaring *ring;
 	int err;
@@ -838,6 +868,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 	if (!ring)
 		goto out;
+	ring->type = type;
 
 	nr_slots = B43legacy_RXRING_SLOTS;
 	if (for_tx)
@@ -855,12 +886,12 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
 			goto err_kfree_meta;
 
 		/* test for ability to dma to txhdr_cache */
-		dma_test = dma_map_single(dev->dev->dev,
-				ring->txhdr_cache,
-				sizeof(struct b43legacy_txhdr_fw3),
-				DMA_TO_DEVICE);
+		dma_test = dma_map_single(dev->dev->dev, ring->txhdr_cache,
+					  sizeof(struct b43legacy_txhdr_fw3),
+					  DMA_TO_DEVICE);
 
-		if (dma_mapping_error(dma_test)) {
+		if (b43legacy_dma_mapping_error(ring, dma_test,
+					sizeof(struct b43legacy_txhdr_fw3))) {
 			/* ugh realloc */
 			kfree(ring->txhdr_cache);
 			ring->txhdr_cache = kcalloc(nr_slots,
@@ -874,7 +905,8 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
 					sizeof(struct b43legacy_txhdr_fw3),
 					DMA_TO_DEVICE);
 
-			if (dma_mapping_error(dma_test))
+			if (b43legacy_dma_mapping_error(ring, dma_test,
+					sizeof(struct b43legacy_txhdr_fw3)))
 				goto err_kfree_txhdr_cache;
 		}
 
@@ -885,11 +917,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
 
 	ring->dev = dev;
 	ring->nr_slots = nr_slots;
-	ring->mmio_base = b43legacy_dmacontroller_base(dma64,
-						       controller_index);
+	ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
 	ring->index = controller_index;
-	ring->dma64 = !!dma64;
-	if (dma64)
+	if (type == B43legacy_DMA_64BIT)
 		ring->ops = &dma64_ops;
 	else
 		ring->ops = &dma32_ops;
@@ -939,10 +969,10 @@ static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring)
 	if (!ring)
 		return;
 
-	b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:"
-		     " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base,
-		     (ring->tx) ? "TX" : "RX",
-		     ring->max_used_slots, ring->nr_slots);
+	b43legacydbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots:"
+		     " %d/%d\n", (unsigned int)(ring->type), ring->mmio_base,
+		     (ring->tx) ? "TX" : "RX", ring->max_used_slots,
+		     ring->nr_slots);
 	/* Device IRQs are disabled prior entering this function,
 	 * so no need to take care of concurrency with rx handler stuff.
 	 */
@@ -988,11 +1018,22 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev)
 	struct b43legacy_dmaring *ring;
 	int err;
 	u64 dmamask;
-	int dma64 = 0;
+	enum b43legacy_dmatype type;
 
 	dmamask = supported_dma_mask(dev);
-	if (dmamask == DMA_64BIT_MASK)
-		dma64 = 1;
+	switch (dmamask) {
+	default:
+		B43legacy_WARN_ON(1);
+	case DMA_30BIT_MASK:
+		type = B43legacy_DMA_30BIT;
+		break;
+	case DMA_32BIT_MASK:
+		type = B43legacy_DMA_32BIT;
+		break;
+	case DMA_64BIT_MASK:
+		type = B43legacy_DMA_64BIT;
+		break;
+	}
 
 	err = ssb_dma_set_mask(dev->dev, dmamask);
 	if (err) {
@@ -1010,52 +1051,50 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev)
 
 	err = -ENOMEM;
 	/* setup TX DMA channels. */
-	ring = b43legacy_setup_dmaring(dev, 0, 1, dma64);
+	ring = b43legacy_setup_dmaring(dev, 0, 1, type);
 	if (!ring)
 		goto out;
 	dma->tx_ring0 = ring;
 
-	ring = b43legacy_setup_dmaring(dev, 1, 1, dma64);
+	ring = b43legacy_setup_dmaring(dev, 1, 1, type);
 	if (!ring)
 		goto err_destroy_tx0;
 	dma->tx_ring1 = ring;
 
-	ring = b43legacy_setup_dmaring(dev, 2, 1, dma64);
+	ring = b43legacy_setup_dmaring(dev, 2, 1, type);
 	if (!ring)
 		goto err_destroy_tx1;
 	dma->tx_ring2 = ring;
 
-	ring = b43legacy_setup_dmaring(dev, 3, 1, dma64);
+	ring = b43legacy_setup_dmaring(dev, 3, 1, type);
 	if (!ring)
 		goto err_destroy_tx2;
 	dma->tx_ring3 = ring;
 
-	ring = b43legacy_setup_dmaring(dev, 4, 1, dma64);
+	ring = b43legacy_setup_dmaring(dev, 4, 1, type);
 	if (!ring)
 		goto err_destroy_tx3;
 	dma->tx_ring4 = ring;
 
-	ring = b43legacy_setup_dmaring(dev, 5, 1, dma64);
+	ring = b43legacy_setup_dmaring(dev, 5, 1, type);
 	if (!ring)
 		goto err_destroy_tx4;
 	dma->tx_ring5 = ring;
 
 	/* setup RX DMA channels. */
-	ring = b43legacy_setup_dmaring(dev, 0, 0, dma64);
+	ring = b43legacy_setup_dmaring(dev, 0, 0, type);
 	if (!ring)
 		goto err_destroy_tx5;
 	dma->rx_ring0 = ring;
 
 	if (dev->dev->id.revision < 5) {
-		ring = b43legacy_setup_dmaring(dev, 3, 0, dma64);
+		ring = b43legacy_setup_dmaring(dev, 3, 0, type);
 		if (!ring)
 			goto err_destroy_rx0;
 		dma->rx_ring3 = ring;
 	}
 
-	b43legacydbg(dev->wl, "%d-bit DMA initialized\n",
-	       (dmamask == DMA_64BIT_MASK) ? 64 :
-	       (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+	b43legacydbg(dev->wl, "%u-bit DMA initialized\n", (unsigned int)type);
 	err = 0;
 out:
 	return err;
@@ -1194,9 +1233,13 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 	}
 
 	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
-				       sizeof(struct b43legacy_txhdr_fw3), 1);
-	if (dma_mapping_error(meta_hdr->dmaaddr))
+					   sizeof(struct b43legacy_txhdr_fw3), 1);
+	if (b43legacy_dma_mapping_error(ring, meta_hdr->dmaaddr,
+					sizeof(struct b43legacy_txhdr_fw3))) {
+		ring->current_slot = old_top_slot;
+		ring->used_slots = old_used_slots;
 		return -EIO;
+	}
 	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
 			     sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
 
@@ -1211,7 +1254,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 
 	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	/* create a bounce buffer in zone_dma on mapping failure. */
-	if (dma_mapping_error(meta->dmaaddr)) {
+	if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
 		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
 		if (!bounce_skb) {
 			ring->current_slot = old_top_slot;
@@ -1225,7 +1268,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 		skb = bounce_skb;
 		meta->skb = skb;
 		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
-		if (dma_mapping_error(meta->dmaaddr)) {
+		if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
 			ring->current_slot = old_top_slot;
 			ring->used_slots = old_used_slots;
 			err = -EIO;
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index 26f6ab0..2dd488c 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -218,6 +218,12 @@ struct b43legacy_dma_ops {
 	void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
 };
 
+enum b43legacy_dmatype {
+	B43legacy_DMA_30BIT = 30,
+	B43legacy_DMA_32BIT = 32,
+	B43legacy_DMA_64BIT = 64,
+};
+
 struct b43legacy_dmaring {
 	/* Lowlevel DMA ops. */
 	const struct b43legacy_dma_ops *ops;
@@ -250,8 +256,8 @@ struct b43legacy_dmaring {
 	int index;
 	/* Boolean. Is this a TX ring? */
 	bool tx;
-	/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
-	bool dma64;
+	/* The type of DMA engine used. */
+	enum b43legacy_dmatype type;
 	/* Boolean. Is this ring stopped at ieee80211 level? */
 	bool stopped;
 	/* Lock, only used for TX. */
@@ -284,15 +290,6 @@ void b43legacy_dma_write(struct b43legacy_dmaring *ring,
 int b43legacy_dma_init(struct b43legacy_wldev *dev);
 void b43legacy_dma_free(struct b43legacy_wldev *dev);
 
-int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
-				     u16 dmacontroller_mmio_base,
-				     int dma64);
-int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
-				     u16 dmacontroller_mmio_base,
-				     int dma64);
-
-u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
 void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev);
 void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev);
 
@@ -320,20 +317,6 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev)
 {
 }
 static inline
-int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
-				     u16 dmacontroller_mmio_base,
-				     int dma64)
-{
-	return 0;
-}
-static inline
-int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
-				     u16 dmacontroller_mmio_base,
-				     int dma64)
-{
-	return 0;
-}
-static inline
 void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
 				struct ieee80211_tx_queue_stats *stats)
 {
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 53f7f2e..c39de42 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3,7 +3,7 @@
  *  Broadcom B43legacy wireless driver
  *
  *  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
- *  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+ *  Copyright (c) 2005-2008 Stefano Brivio <stefano.brivio@polimi.it>
  *  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
  *  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
  *  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -60,6 +60,8 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
+MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID);
+
 #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
 static int modparam_pio;
 module_param_named(pio, modparam_pio, int, 0444);
@@ -1640,10 +1642,11 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
 		err = -EOPNOTSUPP;
 		goto error;
 	}
-	b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
-	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
-	       (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
-	       (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+	b43legacyinfo(dev->wl, "Loading firmware version 0x%X, patch level %u "
+		      "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
+		      (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+		      (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F,
+		      fwtime & 0x1F);
 
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
@@ -3806,6 +3809,32 @@ static struct ssb_driver b43legacy_ssb_driver = {
 	.resume		= b43legacy_resume,
 };
 
+static void b43legacy_print_driverinfo(void)
+{
+	const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "",
+		   *feat_pio = "", *feat_dma = "";
+
+#ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT
+	feat_pci = "P";
+#endif
+#ifdef CONFIG_B43LEGACY_LEDS
+	feat_leds = "L";
+#endif
+#ifdef CONFIG_B43LEGACY_RFKILL
+	feat_rfkill = "R";
+#endif
+#ifdef CONFIG_B43LEGACY_PIO
+	feat_pio = "I";
+#endif
+#ifdef CONFIG_B43LEGACY_DMA
+	feat_dma = "D";
+#endif
+	printk(KERN_INFO "Broadcom 43xx driver loaded "
+	       "[ Features: %s%s%s%s%s, Firmware-ID: "
+	       B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
+	       feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma);
+}
+
 static int __init b43legacy_init(void)
 {
 	int err;
@@ -3816,6 +3845,8 @@ static int __init b43legacy_init(void)
 	if (err)
 		goto err_dfs_exit;
 
+	b43legacy_print_driverinfo();
+
 	return err;
 
 err_dfs_exit:
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 3e6ad7b..a56d9fc 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -3365,7 +3365,6 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv,
 	/* Set us so that we have processed and used all buffers, but have
 	 * not restocked the Rx queue with fresh buffers */
 	rxq->read = rxq->write = 0;
-	rxq->processed = RX_QUEUE_SIZE - 1;
 	rxq->free_count = 0;
 	spin_unlock_irqrestore(&rxq->lock, flags);
 }
@@ -3607,7 +3606,22 @@ static int ipw_load(struct ipw_priv *priv)
  * Driver allocates buffers of this size for Rx
  */
 
-static inline int ipw_queue_space(const struct clx2_queue *q)
+/**
+ * ipw_rx_queue_space - Return number of free slots available in queue.
+ */
+static int ipw_rx_queue_space(const struct ipw_rx_queue *q)
+{
+	int s = q->read - q->write;
+	if (s <= 0)
+		s += RX_QUEUE_SIZE;
+	/* keep some buffer to not confuse full and empty queue */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+static inline int ipw_tx_queue_space(const struct clx2_queue *q)
 {
 	int s = q->last_used - q->first_empty;
 	if (s <= 0)
@@ -4947,7 +4961,7 @@ static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
 		priv->tx_packets++;
 	}
       done:
-	if ((ipw_queue_space(q) > q->low_mark) &&
+	if ((ipw_tx_queue_space(q) > q->low_mark) &&
 	    (qindex >= 0) &&
 	    (priv->status & STATUS_ASSOCIATED) && netif_running(priv->net_dev))
 		netif_wake_queue(priv->net_dev);
@@ -4965,7 +4979,7 @@ static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf,
 	struct clx2_queue *q = &txq->q;
 	struct tfd_frame *tfd;
 
-	if (ipw_queue_space(q) < (sync ? 1 : 2)) {
+	if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) {
 		IPW_ERROR("No space for Tx\n");
 		return -EBUSY;
 	}
@@ -5070,7 +5084,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv)
 
 	spin_lock_irqsave(&rxq->lock, flags);
 	write = rxq->write;
-	while ((rxq->write != rxq->processed) && (rxq->free_count)) {
+	while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
 		element = rxq->rx_free.next;
 		rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
 		list_del(element);
@@ -5187,7 +5201,6 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
 	/* Set us so that we have processed and used all buffers, but have
 	 * not restocked the Rx queue with fresh buffers */
 	rxq->read = rxq->write = 0;
-	rxq->processed = RX_QUEUE_SIZE - 1;
 	rxq->free_count = 0;
 
 	return rxq;
@@ -8223,13 +8236,17 @@ static void ipw_rx(struct ipw_priv *priv)
 	struct ieee80211_hdr_4addr *header;
 	u32 r, w, i;
 	u8 network_packet;
+	u8 fill_rx = 0;
 	DECLARE_MAC_BUF(mac);
 	DECLARE_MAC_BUF(mac2);
 	DECLARE_MAC_BUF(mac3);
 
 	r = ipw_read32(priv, IPW_RX_READ_INDEX);
 	w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
-	i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;
+	i = priv->rxq->read;
+
+	if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2))
+		fill_rx = 1;
 
 	while (i != r) {
 		rxb = priv->rxq->queue[i];
@@ -8404,11 +8421,17 @@ static void ipw_rx(struct ipw_priv *priv)
 		list_add_tail(&rxb->list, &priv->rxq->rx_used);
 
 		i = (i + 1) % RX_QUEUE_SIZE;
+
+		/* If there are a lot of unsued frames, restock the Rx queue
+		 * so the ucode won't assert */
+		if (fill_rx) {
+			priv->rxq->read = i;
+			ipw_rx_queue_replenish(priv);
+		}
 	}
 
 	/* Backtrack one entry */
-	priv->rxq->processed = (i ? i : RX_QUEUE_SIZE) - 1;
-
+	priv->rxq->read = i;
 	ipw_rx_queue_restock(priv);
 }
 
@@ -10336,7 +10359,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
 	q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
 	ipw_write32(priv, q->reg_w, q->first_empty);
 
-	if (ipw_queue_space(q) < q->high_mark)
+	if (ipw_tx_queue_space(q) < q->high_mark)
 		netif_stop_queue(priv->net_dev);
 
 	return NETDEV_TX_OK;
@@ -10357,7 +10380,7 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri)
 	struct clx2_tx_queue *txq = &priv->txq[0];
 #endif				/* CONFIG_IPW2200_QOS */
 
-	if (ipw_queue_space(&txq->q) < txq->q.high_mark)
+	if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark)
 		return 1;
 
 	return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 5ee1ad6..40b71bc 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -687,6 +687,12 @@ static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_c
 	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
 	       !(cmd->meta.flags & CMD_SIZE_HUGE));
 
+
+	if (iwl3945_is_rfkill(priv)) {
+		IWL_DEBUG_INFO("Not sending command - RF KILL");
+		return -EIO;
+	}
+
 	if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
 		IWL_ERROR("No space for Tx\n");
 		return -ENOSPC;
@@ -1580,7 +1586,7 @@ static inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
  */
 int iwl3945_eeprom_init(struct iwl3945_priv *priv)
 {
-	__le16 *e = (__le16 *)&priv->eeprom;
+	u16 *e = (u16 *)&priv->eeprom;
 	u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP);
 	u32 r;
 	int sz = sizeof(priv->eeprom);
@@ -1623,7 +1629,7 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv)
 			IWL_ERROR("Time out reading EEPROM[%d]", addr);
 			return -ETIMEDOUT;
 		}
-		e[addr / 2] = cpu_to_le16(r >> 16);
+		e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
 	}
 
 	return 0;
@@ -2806,7 +2812,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
 #endif
 
 	/* drop all data frame if we are not associated */
-	if ((!iwl3945_is_associated(priv) || !priv->assoc_id) &&
+	if ((!iwl3945_is_associated(priv) ||
+	     ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) &&
 	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
 		IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
 		goto drop_unlock;
@@ -4281,7 +4288,7 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv)
 	int reclaim;
 	unsigned long flags;
 	u8 fill_rx = 0;
-	u32 count = 0;
+	u32 count = 8;
 
 	/* uCode's read index (stored in shared DRAM) indicates the last Rx
 	 * buffer that the driver may process (last buffer filled by ucode). */
@@ -6256,6 +6263,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
 					STATUS_RF_KILL_HW |
 			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
 					STATUS_RF_KILL_SW |
+			       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+					STATUS_GEO_CONFIGURED |
 			       test_bit(STATUS_IN_SUSPEND, &priv->status) <<
 					STATUS_IN_SUSPEND;
 		goto exit;
@@ -6267,6 +6276,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
 				STATUS_RF_KILL_HW |
 			test_bit(STATUS_RF_KILL_SW, &priv->status) <<
 				STATUS_RF_KILL_SW |
+			test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+				STATUS_GEO_CONFIGURED |
 			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
 				STATUS_IN_SUSPEND |
 			test_bit(STATUS_FW_ERROR, &priv->status) <<
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index f423241..a23d479 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -692,6 +692,11 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c
 	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
 	       !(cmd->meta.flags & CMD_SIZE_HUGE));
 
+	if (iwl4965_is_rfkill(priv)) {
+		IWL_DEBUG_INFO("Not sending command - RF KILL");
+		return -EIO;
+	}
+
 	if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
 		IWL_ERROR("No space for Tx\n");
 		return -ENOSPC;
@@ -1654,7 +1659,7 @@ static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
  */
 int iwl4965_eeprom_init(struct iwl4965_priv *priv)
 {
-	__le16 *e = (__le16 *)&priv->eeprom;
+	u16 *e = (u16 *)&priv->eeprom;
 	u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
 	u32 r;
 	int sz = sizeof(priv->eeprom);
@@ -1698,7 +1703,7 @@ int iwl4965_eeprom_init(struct iwl4965_priv *priv)
 			rc = -ETIMEDOUT;
 			goto done;
 		}
-		e[addr / 2] = cpu_to_le16(r >> 16);
+		e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
 	}
 	rc = 0;
 
@@ -2935,7 +2940,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
 	/* drop all data frame if we are not associated */
 	if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
 	   (!iwl4965_is_associated(priv) ||
-	    !priv->assoc_id ||
+	    ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
 	    !priv->assoc_station_added)) {
 		IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
 		goto drop_unlock;
@@ -4664,7 +4669,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
 	int reclaim;
 	unsigned long flags;
 	u8 fill_rx = 0;
-	u32 count = 0;
+	u32 count = 8;
 
 	/* uCode's read index (stored in shared DRAM) indicates the last Rx
 	 * buffer that the driver may process (last buffer filled by ucode). */
@@ -6680,6 +6685,8 @@ static void __iwl4965_down(struct iwl4965_priv *priv)
 					STATUS_RF_KILL_HW |
 			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
 					STATUS_RF_KILL_SW |
+			       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+					STATUS_GEO_CONFIGURED |
 			       test_bit(STATUS_IN_SUSPEND, &priv->status) <<
 					STATUS_IN_SUSPEND;
 		goto exit;
@@ -6691,6 +6698,8 @@ static void __iwl4965_down(struct iwl4965_priv *priv)
 				STATUS_RF_KILL_HW |
 			test_bit(STATUS_RF_KILL_SW, &priv->status) <<
 				STATUS_RF_KILL_SW |
+			test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+				STATUS_GEO_CONFIGURED |
 			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
 				STATUS_IN_SUSPEND |
 			test_bit(STATUS_FW_ERROR, &priv->status) <<
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d3ecf89..8ce2ddf 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2300,7 +2300,7 @@ static void rndis_update_wireless_stats(struct work_struct *work)
 	struct usbnet *usbdev = priv->usbdev;
 	struct iw_statistics iwstats;
 	__le32 rssi, tmp;
-	int len, ret, bitrate, j;
+	int len, ret, j;
 	unsigned long flags;
 	int update_jiffies = STATS_UPDATE_JIFFIES;
 	void *buf;
@@ -2352,14 +2352,10 @@ static void rndis_update_wireless_stats(struct work_struct *work)
 	if (ret == 0)
 		iwstats.discard.misc += le32_to_cpu(tmp);
 
-	/* Workaround transfer stalls on poor quality links. */
-	len = sizeof(tmp);
-	ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len);
-	if (ret == 0) {
-		bitrate = le32_to_cpu(tmp) * 100;
-		if (bitrate > 11000000)
-			goto end;
-
+	/* Workaround transfer stalls on poor quality links.
+	 * TODO: find right way to fix these stalls (as stalls do not happen
+	 * with ndiswrapper/windows driver). */
+	if (iwstats.qual.qual <= 25) {
 		/* Decrease stats worker interval to catch stalls.
 		 * faster. Faster than 400-500ms causes packet loss,
 		 * Slower doesn't catch stalls fast enough.
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 86ded40..4ca9730 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1839,11 +1839,11 @@ static struct usb_device_id rt2500usb_device_table[] = {
 	/* Hercules */
 	{ USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) },
 	/* Melco */
+	{ USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) },
-
 	/* MSI */
 	{ USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) },
diff --git a/drivers/net/wireless/wavelan.h b/drivers/net/wireless/wavelan.h
index 27172cd..9ab3605 100644
--- a/drivers/net/wireless/wavelan.h
+++ b/drivers/net/wireless/wavelan.h
@@ -85,7 +85,7 @@ union hacs_u
 #define		HASR_MMC_INTR		0x0002	/* Interrupt request from MMC */
 #define		HASR_MMC_BUSY		0x0004	/* MMC busy indication */
 #define		HASR_PSA_BUSY		0x0008	/* LAN parameter storage area busy */
-};
+} __attribute__ ((packed));
 
 typedef struct ha_t	ha_t;
 struct ha_t
@@ -292,7 +292,7 @@ struct mmw_t
 #define	MMW_EXT_ANT_INTERNAL	0x00	/* Internal antenna */
 #define	MMW_EXT_ANT_EXTERNAL	0x03	/* External antenna */
 #define	MMW_EXT_ANT_IQ_TEST	0x1C	/* IQ test pattern (set to 0) */
-};
+} __attribute__ ((packed));
 
 #define	MMW_SIZE	37
 
@@ -347,7 +347,7 @@ struct mmr_t
   unsigned char	mmr_unused4[1];		/* unused */
   unsigned char	mmr_fee_data_l;		/* Read data from EEPROM (low) */
   unsigned char	mmr_fee_data_h;		/* Read data from EEPROM (high) */
-};
+} __attribute__ ((packed));
 
 #define	MMR_SIZE	36
 
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 67b7c75..28bcdf9 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -165,6 +165,7 @@ static int ieee80211_open(struct net_device *dev)
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_if_init_conf conf;
 	int res;
+	bool need_hw_reconfig = 0;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -218,7 +219,7 @@ static int ieee80211_open(struct net_device *dev)
 			res = local->ops->start(local_to_hw(local));
 		if (res)
 			return res;
-		ieee80211_hw_config(local);
+		need_hw_reconfig = 1;
 		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 	}
 
@@ -282,6 +283,8 @@ static int ieee80211_open(struct net_device *dev)
 		atomic_inc(&local->iff_promiscs);
 
 	local->open_count++;
+	if (need_hw_reconfig)
+		ieee80211_hw_config(local);
 
 	netif_start_queue(dev);
 
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related

* Re: [PATCH] (02/14/08 Linus git) Smack unlabeled outgoing ambient packets - v3
From: Paul Moore @ 2008-02-15 18:59 UTC (permalink / raw)
  To: casey; +Cc: akpm, torvalds, linux-kernel, netdev
In-Reply-To: <47B52569.9040502@schaufler-ca.com>

On Friday 15 February 2008 12:38:49 am Casey Schaufler wrote:
> From: Casey Schaufler <casey@schaufler-ca.com>
>
> Smack uses CIPSO labeling, but allows for unlabeled packets
> by specifying an "ambient" label that is applied to incoming
> unlabeled packets. Because the other end of the connection
> may dislike IP options, and ssh is one know application that
> behaves thus, it is prudent to respond in kind. This patch
> changes the network labeling behavior such that an outgoing
> packet that would be given a CIPSO label that matches the
> ambient label is left unlabeled. An "unlbl" domain is added
> and the netlabel defaulting mechanism invoked rather than
> assuming that everything is CIPSO. Locking has been added
> around changes to the ambient label as the mechanisms used
> to do so are more involved.
>
> Cleaned up some issues noted in review.
> Make smk_cipso_doi() static.
> Create a hook for the new security_secctx_to_secid()
> using existing underlying code.
> Fill in audit data for netlbl domain calls.
> Collapse unnecessary multiple assignments.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

Hi Casey,

Thanks for the update, it's much improved.  I'd ack it except for one 
last thing which popped up in this revision ... (and don't worry, it's 
kinda my fault - not yours) ...

> @@ -1282,15 +1281,21 @@ static int smack_netlabel(struct sock *s
>  {
>  	struct socket_smack *ssp;
>  	struct netlbl_lsm_secattr secattr;
> -	int rc = 0;
> +	int rc;
>
>  	ssp = sk->sk_security;
>  	netlbl_secattr_init(&secattr);
>  	smack_to_secattr(ssp->smk_out, &secattr);
> -	if (secattr.flags != NETLBL_SECATTR_NONE)
> -		rc = netlbl_sock_setattr(sk, &secattr);
> -
> +	rc = netlbl_sock_setattr(sk, &secattr);
>  	netlbl_secattr_destroy(&secattr);
> +
> +	/*
> +	 * A return of -ENOENT from netlbl_sock_setattr
> +	 * indicates that the "domain" was not found, but that's
> +	 * not an issue because of the defaulting behavior.
> +	 */
> +	if (rc == -ENOENT)
> +		rc = 0;
>  	return rc;
>  }

... you shouldn't fix-up the return value from netlbl_sock_setattr().  
It only returns an error when there really is an error, if there are no 
matching domain mappings and the default catches the "domain" then the 
function will return 0 (assuming no other failures).

The fact that you ran into this problem isn't your fault, it's mine, but 
thankfully for both of us Pavel Emelyanov found this bug and fixed 
it[1].  It hasn't hit Linus' tree yet but it's in the net-2.6 tree.  If 
you can't wait for it to hit Linus' tree you can always apply the fix 
by hand, it's pretty minor.

Sorry about that.

[1]http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=commit;h=4c3a0a254e5d706d3fe01bf42261534858d05586

-- 
paul moore
linux security @ hp

^ permalink raw reply

* [PATCHv2] [XFRM]: Speed up xfrm_policy and xfrm_state walking
From: Timo Teräs @ 2008-02-15 18:22 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20080212.225908.92858029.davem@davemloft.net>

Change xfrm_policy and xfrm_state walking algorithm from O(n^2) to O(n).
This is achieved adding the entries to one more list which is used
solely for walking the entries.

This also fixes some races where the dump can have duplicate or missing
entries when the SPD/SADB is modified during an ongoing dump.

Dumping SADB with 20000 entries using "time ip xfrm state" the sys
time dropped from 1.012s to 0.080s.

Signed-off-by: Timo Teras <timo.teras@iki.fi>
---
David Miller wrote:
> This will potentially leak walk->policy in the != -EEXIST case.
> 
> I think what needs to happen is we invoke xfrm_policy_walk_done()
> unconditionally, then we'll potentially return reqid.

Good catch. Fixed as suggested.

Also the walk context structure layout was changed to align
better on 64-bit machines as suggested by Margit Schubert-While.

 include/linux/xfrm.h   |    3 +-
 include/net/xfrm.h     |   52 ++++++++++++++++++++++++++++++-
 net/key/af_key.c       |   24 ++++++++++++--
 net/xfrm/xfrm_policy.c |   79 ++++++++++++++++++++++++++++--------------------
 net/xfrm/xfrm_state.c  |   53 ++++++++++++++++++++++----------
 net/xfrm/xfrm_user.c   |   71 ++++++++++++++++++++++++++-----------------
 6 files changed, 197 insertions(+), 85 deletions(-)

diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index e31b8c8..0c82c80 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -113,7 +113,8 @@ enum
 {
 	XFRM_POLICY_TYPE_MAIN	= 0,
 	XFRM_POLICY_TYPE_SUB	= 1,
-	XFRM_POLICY_TYPE_MAX	= 2
+	XFRM_POLICY_TYPE_MAX	= 2,
+	XFRM_POLICY_TYPE_ANY	= 255
 };
 
 enum
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index eea7785..9b62056 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -121,6 +121,7 @@ extern struct mutex xfrm_cfg_mutex;
 struct xfrm_state
 {
 	/* Note: bydst is re-used during gc */
+	struct list_head	all;
 	struct hlist_node	bydst;
 	struct hlist_node	bysrc;
 	struct hlist_node	byspi;
@@ -424,6 +425,7 @@ struct xfrm_tmpl
 struct xfrm_policy
 {
 	struct xfrm_policy	*next;
+	struct list_head	bytype;
 	struct hlist_node	bydst;
 	struct hlist_node	byidx;
 
@@ -1160,6 +1162,18 @@ struct xfrm6_tunnel {
 	int priority;
 };
 
+struct xfrm_state_walk {
+	struct xfrm_state *state;
+	int count;
+	u8 proto;
+};
+
+struct xfrm_policy_walk {
+	struct xfrm_policy *policy;
+	int count;
+	u8 type, cur_type;
+};
+
 extern void xfrm_init(void);
 extern void xfrm4_init(void);
 extern void xfrm_state_init(void);
@@ -1184,7 +1198,23 @@ static inline void xfrm6_fini(void)
 extern int xfrm_proc_init(void);
 #endif
 
-extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *);
+static inline void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
+{
+	walk->proto = proto;
+	walk->state = NULL;
+	walk->count = 0;
+}
+
+static inline void xfrm_state_walk_done(struct xfrm_state_walk *walk)
+{
+	if (walk->state != NULL) {
+		xfrm_state_put(walk->state);
+		walk->state = NULL;
+	}
+}
+
+extern int xfrm_state_walk(struct xfrm_state_walk *walk,
+			   int (*func)(struct xfrm_state *, int, void*), void *);
 extern struct xfrm_state *xfrm_state_alloc(void);
 extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 
 					  struct flowi *fl, struct xfrm_tmpl *tmpl,
@@ -1306,7 +1336,25 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
 #endif
 
 struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
-extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
+
+static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
+{
+	walk->cur_type = XFRM_POLICY_TYPE_MAIN;
+	walk->type = type;
+	walk->policy = NULL;
+	walk->count = 0;
+}
+
+static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
+{
+	if (walk->policy != NULL) {
+		xfrm_pol_put(walk->policy);
+		walk->policy = NULL;
+	}
+}
+
+extern int xfrm_policy_walk(struct xfrm_policy_walk *walk,
+	int (*func)(struct xfrm_policy *, int, int, void*), void *);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
 struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 					  struct xfrm_selector *sel,
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 1c85392..0d7c195 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1742,12 +1742,18 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr
 {
 	u8 proto;
 	struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+	struct xfrm_state_walk walk;
+	int rc;
 
 	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
 	if (proto == 0)
 		return -EINVAL;
 
-	return xfrm_state_walk(proto, dump_sa, &data);
+	xfrm_state_walk_init(&walk, proto);
+	rc = xfrm_state_walk(&walk, dump_sa, &data);
+	xfrm_state_walk_done(&walk);
+
+	return rc;
 }
 
 static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1780,7 +1786,9 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr)
 
 static u32 gen_reqid(void)
 {
+	struct xfrm_policy_walk walk;
 	u32 start;
+	int rc;
 	static u32 reqid = IPSEC_MANUAL_REQID_MAX;
 
 	start = reqid;
@@ -1788,8 +1796,10 @@ static u32 gen_reqid(void)
 		++reqid;
 		if (reqid == 0)
 			reqid = IPSEC_MANUAL_REQID_MAX+1;
-		if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid,
-				     (void*)&reqid) != -EEXIST)
+		xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
+		rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid);
+		xfrm_policy_walk_done(&walk);
+		if (rc != -EEXIST)
 			return reqid;
 	} while (reqid != start);
 	return 0;
@@ -2665,8 +2675,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
 static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
 	struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+	struct xfrm_policy_walk walk;
+	int rc;
+
+	xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
+	rc = xfrm_policy_walk(&walk, dump_sp, &data);
+	xfrm_policy_walk_done(&walk);
 
-	return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data);
+	return rc;
 }
 
 static int key_notify_policy_flush(struct km_event *c)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 47219f9..0966bd9 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex);
 
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
+static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX];
 unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
 EXPORT_SYMBOL(xfrm_policy_count);
 
@@ -208,6 +209,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
 	policy = kzalloc(sizeof(struct xfrm_policy), gfp);
 
 	if (policy) {
+		INIT_LIST_HEAD(&policy->bytype);
 		INIT_HLIST_NODE(&policy->bydst);
 		INIT_HLIST_NODE(&policy->byidx);
 		rwlock_init(&policy->lock);
@@ -230,6 +232,10 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
 	if (del_timer(&policy->timer))
 		BUG();
 
+	write_lock_bh(&xfrm_policy_lock);
+	list_del(&policy->bytype);
+	write_unlock_bh(&xfrm_policy_lock);
+
 	security_xfrm_policy_free(policy);
 	kfree(policy);
 }
@@ -568,6 +574,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
 	policy->curlft.use_time = 0;
 	if (!mod_timer(&policy->timer, jiffies + HZ))
 		xfrm_pol_hold(policy);
+	list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]);
 	write_unlock_bh(&xfrm_policy_lock);
 
 	if (delpol)
@@ -806,57 +813,60 @@ out:
 }
 EXPORT_SYMBOL(xfrm_policy_flush);
 
-int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),
+int xfrm_policy_walk(struct xfrm_policy_walk *walk,
+		     int (*func)(struct xfrm_policy *, int, int, void*),
 		     void *data)
 {
-	struct xfrm_policy *pol, *last = NULL;
-	struct hlist_node *entry;
-	int dir, last_dir = 0, count, error;
+	struct xfrm_policy *old, *pol, *last = NULL;
+	int error = 0;
+
+	if (walk->type >= XFRM_POLICY_TYPE_MAX &&
+	    walk->type != XFRM_POLICY_TYPE_ANY)
+		return -EINVAL;
 
+	if (walk->policy == NULL && walk->count != 0)
+		return 0;
+
+	old = pol = walk->policy;
+	walk->policy = NULL;
 	read_lock_bh(&xfrm_policy_lock);
-	count = 0;
 
-	for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
-		struct hlist_head *table = xfrm_policy_bydst[dir].table;
-		int i;
+	for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
+		if (walk->type != walk->cur_type &&
+		    walk->type != XFRM_POLICY_TYPE_ANY)
+			continue;
 
-		hlist_for_each_entry(pol, entry,
-				     &xfrm_policy_inexact[dir], bydst) {
-			if (pol->type != type)
+		if (pol == NULL) {
+			pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
+					       struct xfrm_policy, bytype);
+		}
+		list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
+			if (pol->dead)
 				continue;
 			if (last) {
-				error = func(last, last_dir % XFRM_POLICY_MAX,
-					     count, data);
-				if (error)
+				error = func(last, xfrm_policy_id2dir(last->index),
+					     walk->count, data);
+				if (error) {
+					xfrm_pol_hold(last);
+					walk->policy = last;
 					goto out;
-			}
-			last = pol;
-			last_dir = dir;
-			count++;
-		}
-		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
-			hlist_for_each_entry(pol, entry, table + i, bydst) {
-				if (pol->type != type)
-					continue;
-				if (last) {
-					error = func(last, last_dir % XFRM_POLICY_MAX,
-						     count, data);
-					if (error)
-						goto out;
 				}
-				last = pol;
-				last_dir = dir;
-				count++;
 			}
+			last = pol;
+			walk->count++;
 		}
+		pol = NULL;
 	}
-	if (count == 0) {
+	if (walk->count == 0) {
 		error = -ENOENT;
 		goto out;
 	}
-	error = func(last, last_dir % XFRM_POLICY_MAX, 0, data);
+	if (last)
+		error = func(last, xfrm_policy_id2dir(last->index), 0, data);
 out:
 	read_unlock_bh(&xfrm_policy_lock);
+	if (old != NULL)
+		xfrm_pol_put(old);
 	return error;
 }
 EXPORT_SYMBOL(xfrm_policy_walk);
@@ -2349,6 +2359,9 @@ static void __init xfrm_policy_init(void)
 			panic("XFRM: failed to allocate bydst hash\n");
 	}
 
+	for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
+		INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
+
 	INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
 	register_netdevice_notifier(&xfrm_dev_notifier);
 }
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 7ba65e8..9880b79 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -50,6 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock);
  * Main use is finding SA after policy selected tunnel or transport mode.
  * Also, it can be used by ah/esp icmp error handler to find offending SA.
  */
+static LIST_HEAD(xfrm_state_all);
 static struct hlist_head *xfrm_state_bydst __read_mostly;
 static struct hlist_head *xfrm_state_bysrc __read_mostly;
 static struct hlist_head *xfrm_state_byspi __read_mostly;
@@ -510,6 +511,7 @@ struct xfrm_state *xfrm_state_alloc(void)
 	if (x) {
 		atomic_set(&x->refcnt, 1);
 		atomic_set(&x->tunnel_users, 0);
+		INIT_LIST_HEAD(&x->all);
 		INIT_HLIST_NODE(&x->bydst);
 		INIT_HLIST_NODE(&x->bysrc);
 		INIT_HLIST_NODE(&x->byspi);
@@ -533,6 +535,10 @@ void __xfrm_state_destroy(struct xfrm_state *x)
 {
 	BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
 
+	spin_lock_bh(&xfrm_state_lock);
+	list_del(&x->all);
+	spin_unlock_bh(&xfrm_state_lock);
+
 	spin_lock_bh(&xfrm_state_gc_lock);
 	hlist_add_head(&x->bydst, &xfrm_state_gc_list);
 	spin_unlock_bh(&xfrm_state_gc_lock);
@@ -909,6 +915,8 @@ static void __xfrm_state_insert(struct xfrm_state *x)
 
 	x->genid = ++xfrm_state_genid;
 
+	list_add_tail(&x->all, &xfrm_state_all);
+
 	h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
 			  x->props.reqid, x->props.family);
 	hlist_add_head(&x->bydst, xfrm_state_bydst+h);
@@ -1518,36 +1526,47 @@ unlock:
 }
 EXPORT_SYMBOL(xfrm_alloc_spi);
 
-int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
+int xfrm_state_walk(struct xfrm_state_walk *walk,
+		    int (*func)(struct xfrm_state *, int, void*),
 		    void *data)
 {
-	int i;
-	struct xfrm_state *x, *last = NULL;
-	struct hlist_node *entry;
-	int count = 0;
+	struct xfrm_state *old, *x, *last = NULL;
 	int err = 0;
 
+	if (walk->state == NULL && walk->count != 0)
+		return 0;
+
+	old = x = walk->state;
+	walk->state = NULL;
 	spin_lock_bh(&xfrm_state_lock);
-	for (i = 0; i <= xfrm_state_hmask; i++) {
-		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
-			if (!xfrm_id_proto_match(x->id.proto, proto))
-				continue;
-			if (last) {
-				err = func(last, count, data);
-				if (err)
-					goto out;
+	if (x == NULL)
+		x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
+	list_for_each_entry_from(x, &xfrm_state_all, all) {
+		if (x->km.state == XFRM_STATE_DEAD)
+			continue;
+		if (!xfrm_id_proto_match(x->id.proto, walk->proto))
+			continue;
+		if (last) {
+			err = func(last, walk->count, data);
+			if (err) {
+				xfrm_state_hold(last);
+				walk->state = last;
+				goto out;
 			}
-			last = x;
-			count++;
 		}
+		last = x;
+		walk->count++;
 	}
-	if (count == 0) {
+	if (walk->count == 0) {
 		err = -ENOENT;
 		goto out;
 	}
-	err = func(last, 0, data);
+	if (last)
+		err = func(last, 0, data);
 out:
 	spin_unlock_bh(&xfrm_state_lock);
+	if (old != NULL)
+		xfrm_state_put(old);
 	return err;
 }
 EXPORT_SYMBOL(xfrm_state_walk);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index f971ca5..f5fd5b3 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -532,8 +532,6 @@ struct xfrm_dump_info {
 	struct sk_buff *out_skb;
 	u32 nlmsg_seq;
 	u16 nlmsg_flags;
-	int start_idx;
-	int this_idx;
 };
 
 static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
@@ -600,9 +598,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
 	struct nlmsghdr *nlh;
 	int err;
 
-	if (sp->this_idx < sp->start_idx)
-		goto out;
-
 	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
 			XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
 	if (nlh == NULL)
@@ -615,8 +610,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
 		goto nla_put_failure;
 
 	nlmsg_end(skb, nlh);
-out:
-	sp->this_idx++;
 	return 0;
 
 nla_put_failure:
@@ -624,18 +617,32 @@ nla_put_failure:
 	return err;
 }
 
+static int xfrm_dump_sa_done(struct netlink_callback *cb)
+{
+	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
+	xfrm_state_walk_done(walk);
+	return 0;
+}
+
 static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
 	struct xfrm_dump_info info;
 
+	BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
+		     sizeof(cb->args) - sizeof(cb->args[0]));
+
 	info.in_skb = cb->skb;
 	info.out_skb = skb;
 	info.nlmsg_seq = cb->nlh->nlmsg_seq;
 	info.nlmsg_flags = NLM_F_MULTI;
-	info.this_idx = 0;
-	info.start_idx = cb->args[0];
-	(void) xfrm_state_walk(0, dump_one_state, &info);
-	cb->args[0] = info.this_idx;
+
+	if (!cb->args[0]) {
+		cb->args[0] = 1;
+		xfrm_state_walk_init(walk, 0);
+	}
+
+	(void) xfrm_state_walk(walk, dump_one_state, &info);
 
 	return skb->len;
 }
@@ -654,7 +661,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
 	info.out_skb = skb;
 	info.nlmsg_seq = seq;
 	info.nlmsg_flags = 0;
-	info.this_idx = info.start_idx = 0;
 
 	if (dump_one_state(x, 0, &info)) {
 		kfree_skb(skb);
@@ -1232,9 +1238,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
 	struct sk_buff *skb = sp->out_skb;
 	struct nlmsghdr *nlh;
 
-	if (sp->this_idx < sp->start_idx)
-		goto out;
-
 	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
 			XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
 	if (nlh == NULL)
@@ -1250,8 +1253,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
 		goto nlmsg_failure;
 
 	nlmsg_end(skb, nlh);
-out:
-	sp->this_idx++;
 	return 0;
 
 nlmsg_failure:
@@ -1259,21 +1260,33 @@ nlmsg_failure:
 	return -EMSGSIZE;
 }
 
+static int xfrm_dump_policy_done(struct netlink_callback *cb)
+{
+	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
+
+	xfrm_policy_walk_done(walk);
+	return 0;
+}
+
 static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
 	struct xfrm_dump_info info;
 
+	BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
+		     sizeof(cb->args) - sizeof(cb->args[0]));
+
 	info.in_skb = cb->skb;
 	info.out_skb = skb;
 	info.nlmsg_seq = cb->nlh->nlmsg_seq;
 	info.nlmsg_flags = NLM_F_MULTI;
-	info.this_idx = 0;
-	info.start_idx = cb->args[0];
-	(void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info);
-#ifdef CONFIG_XFRM_SUB_POLICY
-	(void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info);
-#endif
-	cb->args[0] = info.this_idx;
+
+	if (!cb->args[0]) {
+		cb->args[0] = 1;
+		xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
+	}
+
+	(void) xfrm_policy_walk(walk, dump_one_policy, &info);
 
 	return skb->len;
 }
@@ -1293,7 +1306,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
 	info.out_skb = skb;
 	info.nlmsg_seq = seq;
 	info.nlmsg_flags = 0;
-	info.this_idx = info.start_idx = 0;
 
 	if (dump_one_policy(xp, dir, 0, &info) < 0) {
 		kfree_skb(skb);
@@ -1891,15 +1903,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
 static struct xfrm_link {
 	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
 	int (*dump)(struct sk_buff *, struct netlink_callback *);
+	int (*done)(struct netlink_callback *);
 } xfrm_dispatch[XFRM_NR_MSGTYPES] = {
 	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
 	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = { .doit = xfrm_del_sa        },
 	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
-						   .dump = xfrm_dump_sa       },
+						   .dump = xfrm_dump_sa,
+						   .done = xfrm_dump_sa_done  },
 	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
 	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy    },
 	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
-						   .dump = xfrm_dump_policy   },
+						   .dump = xfrm_dump_policy,
+						   .done = xfrm_dump_policy_done },
 	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
 	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
 	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
@@ -1938,7 +1953,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		if (link->dump == NULL)
 			return -EINVAL;
 
-		return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL);
+		return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done);
 	}
 
 	err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,
-- 
1.5.2.5


^ permalink raw reply related

* [PATCH] (02/14/08 Linus git) Smack unlabeled outgoing ambient packets - v3
From: Casey Schaufler @ 2008-02-15  5:38 UTC (permalink / raw)
  To: akpm, torvalds, paul.moore; +Cc: linux-kernel, netdev, casey

From: Casey Schaufler <casey@schaufler-ca.com>

Smack uses CIPSO labeling, but allows for unlabeled packets
by specifying an "ambient" label that is applied to incoming
unlabeled packets. Because the other end of the connection
may dislike IP options, and ssh is one know application that
behaves thus, it is prudent to respond in kind. This patch
changes the network labeling behavior such that an outgoing
packet that would be given a CIPSO label that matches the
ambient label is left unlabeled. An "unlbl" domain is added
and the netlabel defaulting mechanism invoked rather than
assuming that everything is CIPSO. Locking has been added
around changes to the ambient label as the mechanisms used
to do so are more involved.

Cleaned up some issues noted in review.
Make smk_cipso_doi() static.
Create a hook for the new security_secctx_to_secid()
using existing underlying code.
Fill in audit data for netlbl domain calls.
Collapse unnecessary multiple assignments.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

---

 security/smack/smack_lsm.c |   43 ++++++++++++++++++++----
 security/smack/smackfs.c   |   61 ++++++++++++++++++++++++++---------
 2 files changed, 81 insertions(+), 23 deletions(-)

diff -uprN -X linux-2.6.25-g0214-base/Documentation/dontdiff linux-2.6.25-g0214-base/security/smack/smackfs.c linux-2.6.25-g0214/security/smack/smackfs.c
--- linux-2.6.25-g0214-base/security/smack/smackfs.c	2008-02-14 15:37:13.000000000 -0800
+++ linux-2.6.25-g0214/security/smack/smackfs.c	2008-02-14 15:42:26.000000000 -0800
@@ -24,6 +24,7 @@
 #include <net/cipso_ipv4.h>
 #include <linux/seq_file.h>
 #include <linux/ctype.h>
+#include <linux/audit.h>
 #include "smack.h"
 
 /*
@@ -45,6 +46,7 @@ enum smk_inos {
  */
 static DEFINE_MUTEX(smack_list_lock);
 static DEFINE_MUTEX(smack_cipso_lock);
+static DEFINE_MUTEX(smack_ambient_lock);
 
 /*
  * This is the "ambient" label for network traffic.
@@ -342,6 +344,9 @@ void smk_cipso_doi(void)
 	struct cipso_v4_doi *doip;
 	struct netlbl_audit audit_info;
 
+	audit_info.loginuid = audit_get_loginuid(current);
+	audit_info.secid = smack_to_secid(current->security);
+
 	rc = netlbl_cfg_map_del(NULL, &audit_info);
 	if (rc != 0)
 		printk(KERN_WARNING "%s:%d remove rc = %d\n",
@@ -363,6 +368,30 @@ void smk_cipso_doi(void)
 		       __func__, __LINE__, rc);
 }
 
+/**
+ * smk_unlbl_ambient - initialize the unlabeled domain
+ */
+void smk_unlbl_ambient(char *oldambient)
+{
+	int rc;
+	struct netlbl_audit audit_info;
+
+	audit_info.loginuid = audit_get_loginuid(current);
+	audit_info.secid = smack_to_secid(current->security);
+
+	if (oldambient != NULL) {
+		rc = netlbl_cfg_map_del(oldambient, &audit_info);
+		if (rc != 0)
+			printk(KERN_WARNING "%s:%d remove rc = %d\n",
+			       __func__, __LINE__, rc);
+	}
+
+	rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info);
+	if (rc != 0)
+		printk(KERN_WARNING "%s:%d add rc = %d\n",
+		       __func__, __LINE__, rc);
+}
+
 /*
  * Seq_file read operations for /smack/cipso
  */
@@ -709,7 +738,6 @@ static ssize_t smk_read_ambient(struct f
 				size_t cn, loff_t *ppos)
 {
 	ssize_t rc;
-	char out[SMK_LABELLEN];
 	int asize;
 
 	if (*ppos != 0)
@@ -717,23 +745,18 @@ static ssize_t smk_read_ambient(struct f
 	/*
 	 * Being careful to avoid a problem in the case where
 	 * smack_net_ambient gets changed in midstream.
-	 * Since smack_net_ambient is always set with a value
-	 * from the label list, including initially, and those
-	 * never get freed, the worst case is that the pointer
-	 * gets changed just after this strncpy, in which case
-	 * the value passed up is incorrect. Locking around
-	 * smack_net_ambient wouldn't be any better than this
-	 * copy scheme as by the time the caller got to look
-	 * at the ambient value it would have cleared the lock
-	 * and been changed.
 	 */
-	strncpy(out, smack_net_ambient, SMK_LABELLEN);
-	asize = strlen(out) + 1;
+	mutex_lock(&smack_ambient_lock);
 
-	if (cn < asize)
-		return -EINVAL;
+	asize = strlen(smack_net_ambient) + 1;
+
+	if (cn >= asize)
+		rc = simple_read_from_buffer(buf, cn, ppos,
+					     smack_net_ambient, asize);
+	else
+		rc = -EINVAL;
 
-	rc = simple_read_from_buffer(buf, cn, ppos, out, asize);
+	mutex_unlock(&smack_ambient_lock);
 
 	return rc;
 }
@@ -751,6 +774,7 @@ static ssize_t smk_write_ambient(struct 
 				 size_t count, loff_t *ppos)
 {
 	char in[SMK_LABELLEN];
+	char *oldambient;
 	char *smack;
 
 	if (!capable(CAP_MAC_ADMIN))
@@ -766,7 +790,13 @@ static ssize_t smk_write_ambient(struct 
 	if (smack == NULL)
 		return -EINVAL;
 
+	mutex_lock(&smack_ambient_lock);
+
+	oldambient = smack_net_ambient;
 	smack_net_ambient = smack;
+	smk_unlbl_ambient(oldambient);
+
+	mutex_unlock(&smack_ambient_lock);
 
 	return count;
 }
@@ -974,6 +1004,7 @@ static int __init init_smk_fs(void)
 
 	sema_init(&smack_write_sem, 1);
 	smk_cipso_doi();
+	smk_unlbl_ambient(NULL);
 
 	return err;
 }
diff -uprN -X linux-2.6.25-g0214-base/Documentation/dontdiff linux-2.6.25-g0214-base/security/smack/smack_lsm.c linux-2.6.25-g0214/security/smack/smack_lsm.c
--- linux-2.6.25-g0214-base/security/smack/smack_lsm.c	2008-02-14 15:37:13.000000000 -0800
+++ linux-2.6.25-g0214/security/smack/smack_lsm.c	2008-02-14 15:49:29.000000000 -0800
@@ -1251,9 +1251,8 @@ static void smack_to_secattr(char *smack
 
 	switch (smack_net_nltype) {
 	case NETLBL_NLTYPE_CIPSOV4:
-		nlsp->domain = NULL;
-		nlsp->flags = NETLBL_SECATTR_DOMAIN;
-		nlsp->flags |= NETLBL_SECATTR_MLS_LVL;
+		nlsp->domain = kstrdup(smack, GFP_ATOMIC);
+		nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
 
 		rc = smack_to_cipso(smack, &cipso);
 		if (rc == 0) {
@@ -1282,15 +1281,21 @@ static int smack_netlabel(struct sock *s
 {
 	struct socket_smack *ssp;
 	struct netlbl_lsm_secattr secattr;
-	int rc = 0;
+	int rc;
 
 	ssp = sk->sk_security;
 	netlbl_secattr_init(&secattr);
 	smack_to_secattr(ssp->smk_out, &secattr);
-	if (secattr.flags != NETLBL_SECATTR_NONE)
-		rc = netlbl_sock_setattr(sk, &secattr);
-
+	rc = netlbl_sock_setattr(sk, &secattr);
 	netlbl_secattr_destroy(&secattr);
+
+	/*
+	 * A return of -ENOENT from netlbl_sock_setattr
+	 * indicates that the "domain" was not found, but that's
+	 * not an issue because of the defaulting behavior.
+	 */
+	if (rc == -ENOENT)
+		rc = 0;
 	return rc;
 }
 
@@ -1313,6 +1318,7 @@ static int smack_inode_setsecurity(struc
 	struct inode_smack *nsp = inode->i_security;
 	struct socket_smack *ssp;
 	struct socket *sock;
+	int rc = 0;
 
 	if (value == NULL || size > SMK_LABELLEN)
 		return -EACCES;
@@ -1341,7 +1347,10 @@ static int smack_inode_setsecurity(struc
 		ssp->smk_in = sp;
 	else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
 		ssp->smk_out = sp;
-		return smack_netlabel(sock->sk);
+		rc = smack_netlabel(sock->sk);
+		if (rc != 0)
+			printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
+			       __func__, -rc);
 	} else
 		return -EOPNOTSUPP;
 
@@ -2214,6 +2223,9 @@ static void smack_sock_graft(struct sock
 	ssp->smk_packet[0] = '\0';
 
 	rc = smack_netlabel(sk);
+	if (rc != 0)
+		printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
+		       __func__, -rc);
 }
 
 /**
@@ -2346,6 +2358,20 @@ static int smack_secid_to_secctx(u32 sec
 }
 
 /*
+ * smack_secctx_to_secid - return the secid for a smack label
+ * @secdata: smack label
+ * @seclen: how long result is
+ * @secid: outgoing integer
+ *
+ * Exists for audit and networking code.
+ */
+static int smack_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+{
+	*secid = smack_to_secid(secdata);
+	return 0;
+}
+
+/*
  * smack_release_secctx - don't do anything.
  * @key_ref: unused
  * @context: unused
@@ -2475,6 +2501,7 @@ static struct security_operations smack_
 	.key_permission = 		smack_key_permission,
 #endif /* CONFIG_KEYS */
 	.secid_to_secctx = 		smack_secid_to_secctx,
+	.secctx_to_secid = 		smack_secctx_to_secid,
 	.release_secctx = 		smack_release_secctx,
 };





^ permalink raw reply

* [PATCH 2/2] Remove MAC_FMT
From: Joe Perches @ 2008-02-15 17:42 UTC (permalink / raw)
  To: David Miller
  Cc: bruno-L9ZBdB2wSWtl57MIdRCFDg, netdev-u79uwXL29TY76Z2rM5mHXA,
	jgarzik-e+AXbWqSrlAAvxtiuMwx3w,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linville-2XuSBdqkA4R54TAoqtyWWQ
In-Reply-To: <20080215.025855.202184003.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>

MAC_FMT is no longer used

Signed-off-by: Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>

diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index e157c13..7a1e011 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -130,7 +130,6 @@ extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
  *	Display a 6 byte device address (MAC) in a readable format.
  */
 extern char *print_mac(char *buf, const unsigned char *addr);
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAC_BUF_SIZE	18
 #define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE] __maybe_unused
 

^ permalink raw reply related

* [PATCH] net/8021q/vlan_dev.c - Use print_mac
From: Joe Perches @ 2008-02-15 17:42 UTC (permalink / raw)
  To: David Miller, Patrick McHardy
  Cc: bruno-L9ZBdB2wSWtl57MIdRCFDg, netdev-u79uwXL29TY76Z2rM5mHXA,
	jgarzik-e+AXbWqSrlAAvxtiuMwx3w,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linville-2XuSBdqkA4R54TAoqtyWWQ
In-Reply-To: <20080215.025855.202184003.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>

On Fri, 2008-02-15 at 02:58 -0800, David Miller wrote:
> From: Bruno Randolf <bruno-L9ZBdB2wSWtl57MIdRCFDg@public.gmane.org>
> Date: Fri, 15 Feb 2008 19:48:05 +0900
> > is there any chance to include a macro like this for printing mac
> addresses?
> > its advantage is that it can be used without the need to declare
> buffers for
> > print_mac(), for example:
> We specifically removed this sort of thing, please don't
> add it back.

Remove direct use of MAC_FMT

Signed-off-by: Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>

diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 77f04e4..839c70e 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -366,7 +366,8 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct net_device_stats *stats = &dev->stats;
 	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
-
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 	/* Handle non-VLAN frames if they are sent to us, for example by DHCP.
 	 *
 	 * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
@@ -404,11 +405,8 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	pr_debug("%s: about to send skb: %p to dev: %s\n",
 		__FUNCTION__, skb, skb->dev->name);
-	pr_debug("  " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n",
-		 veth->h_dest[0], veth->h_dest[1], veth->h_dest[2],
-		 veth->h_dest[3], veth->h_dest[4], veth->h_dest[5],
-		 veth->h_source[0], veth->h_source[1], veth->h_source[2],
-		 veth->h_source[3], veth->h_source[4], veth->h_source[5],
+	pr_debug("  %s %s %4hx %4hx %4hx\n",
+		 print_mac(mac, veth->h_dest), print_mac(mac2, veth->h_source),
 		 veth->h_vlan_proto, veth->h_vlan_TCI,
 		 veth->h_vlan_encapsulated_proto);
 

^ permalink raw reply related

* [PATCH 3/3] Add IPv6 Support to TCP SYN cookies
From: Glenn Griffin @ 2008-02-15 17:47 UTC (permalink / raw)
  To: netdev, linux-kernel; +Cc: Glenn Griffin
In-Reply-To: <1203097630-13237-2-git-send-email-ggriffin.kernel@gmail.com>

Support IPv6 syncookies

Signed-off-by: Glenn Griffin <ggriffin.kernel@gmail.com>
---
 include/net/tcp.h        |   10 ++
 net/ipv4/syncookies.c    |    9 +-
 net/ipv4/tcp_input.c     |    1 +
 net/ipv4/tcp_minisocks.c |    2 +
 net/ipv4/tcp_output.c    |    1 +
 net/ipv6/Makefile        |    1 +
 net/ipv6/syncookies.c    |  284 ++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv6/tcp_ipv6.c      |   78 +++++++++----
 8 files changed, 359 insertions(+), 27 deletions(-)
 create mode 100644 net/ipv6/syncookies.c

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 42b36f5..18bc5f2 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -29,6 +29,7 @@
 #include <linux/skbuff.h>
 #include <linux/dmaengine.h>
 #include <linux/crypto.h>
+#include <linux/cryptohash.h>
 
 #include <net/inet_connection_sock.h>
 #include <net/inet_timewait_sock.h>
@@ -434,11 +435,19 @@ extern int			tcp_disconnect(struct sock *sk, int flags);
 extern void			tcp_unhash(struct sock *sk);
 
 /* From syncookies.c */
+extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
 extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, 
 				    struct ip_options *opt);
 extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, 
 				     __u16 *mss);
 extern __u32 cookie_init_timestamp(struct request_sock *req);
+extern __u32 cookie_check_timestamp(__u32 ts,
+				    struct tcp_options_received *tcp_opt);
+
+/* From net/ipv6/syncookies.c */
+extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
+extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb,
+				     __u16 *mss);
 
 /* tcp_output.c */
 
@@ -1336,6 +1345,7 @@ extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo);
 extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
 
 extern struct request_sock_ops tcp_request_sock_ops;
+extern struct request_sock_ops tcp6_request_sock_ops;
 
 extern int tcp_v4_destroy_sock(struct sock *sk);
 
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index eb5d804..4915d8d 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -10,8 +10,6 @@
  *      2 of the License, or (at your option) any later version.
  *
  *  $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $
- *
- *  Missing: IPv6 support.
  */
 
 #include <linux/tcp.h>
@@ -23,7 +21,8 @@
 
 extern int sysctl_tcp_syncookies;
 
-static __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+__u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+EXPORT_SYMBOL(syncookie_secret);
 
 static __init int init_syncookies(void)
 {
@@ -216,8 +215,7 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
  * The next 4 lsb are for rcv_wscale
  * The next 1 lsb are for sack_ok
  */
-static __u32 cookie_check_timestamp(__u32 ts,
-				    struct tcp_options_received *tcp_opt)
+__u32 cookie_check_timestamp(__u32 ts, struct tcp_options_received *tcp_opt)
 {
 	__u32 init_ts = ts & TSMASK;
 
@@ -249,6 +247,7 @@ static __u32 cookie_check_timestamp(__u32 ts,
 
 	return init_ts;
 }
+EXPORT_SYMBOL(cookie_check_timestamp);
 
 struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 			     struct ip_options *opt)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 95fa8dc..018ffc3 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5326,6 +5326,7 @@ discard:
 
 EXPORT_SYMBOL(sysctl_tcp_ecn);
 EXPORT_SYMBOL(sysctl_tcp_reordering);
+EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
 EXPORT_SYMBOL(tcp_parse_options);
 EXPORT_SYMBOL(tcp_rcv_established);
 EXPORT_SYMBOL(tcp_rcv_state_process);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 648f84e..b4d4fb8 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -35,6 +35,8 @@
 #endif
 
 int sysctl_tcp_syncookies __read_mostly = SYNC_INIT;
+EXPORT_SYMBOL(sysctl_tcp_syncookies);
+
 int sysctl_tcp_abort_on_overflow __read_mostly;
 
 struct inet_timewait_death_row tcp_death_row = {
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 0c900e0..e07c32f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2570,6 +2570,7 @@ void tcp_send_probe0(struct sock *sk)
 	}
 }
 
+EXPORT_SYMBOL(tcp_select_initial_window);
 EXPORT_SYMBOL(tcp_connect);
 EXPORT_SYMBOL(tcp_make_synack);
 EXPORT_SYMBOL(tcp_simple_retransmit);
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 24f3aa0..ae14617 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -16,6 +16,7 @@ ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
 ipv6-$(CONFIG_NETFILTER) += netfilter.o
 ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
 ipv6-$(CONFIG_PROC_FS) += proc.o
+ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
 
 ipv6-objs += $(ipv6-y)
 
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
new file mode 100644
index 0000000..9f64d9a
--- /dev/null
+++ b/net/ipv6/syncookies.c
@@ -0,0 +1,284 @@
+/*
+ *  IPv6 Syncookies implementation for the Linux kernel
+ *
+ *  Authors:
+ *  Glenn Griffin	<ggriffin.kernel@gmail.com>
+ *
+ *  Based on IPv4 implementation by Andi Kleen
+ *  linux/net/ipv4/syncookies.c
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/tcp.h>
+#include <linux/random.h>
+#include <linux/cryptohash.h>
+#include <linux/kernel.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+
+extern int sysctl_tcp_syncookies;
+extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+
+#define COOKIEBITS 24	/* Upper bits store count */
+#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+
+/*
+ * This table has to be sorted and terminated with (__u16)-1.
+ * XXX generate a better table.
+ * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ *
+ * Taken directly from ipv4 implementation.
+ * Should this list be modified for ipv6 use or is it close enough?
+ * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart
+ */
+static __u16 const msstab[] = {
+	64 - 1,
+	256 - 1,
+	512 - 1,
+	536 - 1,
+	1024 - 1,
+	1440 - 1,
+	1460 - 1,
+	4312 - 1,
+	(__u16)-1
+};
+/* The number doesn't include the -1 terminator */
+#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
+
+/*
+ * This (misnamed) value is the age of syncookie which is permitted.
+ * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
+ * sysctl_tcp_retries1. It's a rather complicated formula (exponential
+ * backoff) to compute at runtime so it's currently hardcoded here.
+ */
+#define COUNTER_TRIES 4
+
+static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
+					   struct request_sock *req,
+					   struct dst_entry *dst)
+{
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	struct sock *child;
+
+	child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst);
+	if (child)
+		inet_csk_reqsk_queue_add(sk, req, child);
+	else
+		reqsk_free(req);
+
+	return child;
+}
+
+static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+
+static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
+		       __be16 sport, __be16 dport, u32 count, int c)
+{
+	__u32 *tmp = __get_cpu_var(cookie_scratch);
+
+	/*
+	 * we have 320 bits of information to hash, copy in the remaining
+	 * 192 bits required for sha_transform, from the syncookie_secret
+	 * and overwrite the digest with the secret
+	 */
+	memcpy(tmp + 10, syncookie_secret[c], 44);
+	memcpy(tmp, saddr, 16);
+	memcpy(tmp + 4, daddr, 16);
+	tmp[8] = ((__force u32)sport << 16) + (__force u32)dport;
+	tmp[9] = count;
+	sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
+
+	return tmp[17];
+}
+
+static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr,
+				   struct in6_addr *daddr,
+				   __be16 sport, __be16 dport, __u32 sseq,
+				   __u32 count, __u32 data)
+{
+	return (cookie_hash(saddr, daddr, sport, dport, 0, 0) +
+		sseq + (count << COOKIEBITS) +
+		((cookie_hash(saddr, daddr, sport, dport, count, 1) + data)
+		& COOKIEMASK));
+}
+
+static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr,
+				  struct in6_addr *daddr, __be16 sport,
+				  __be16 dport, __u32 sseq, __u32 count,
+				  __u32 maxdiff)
+{
+	__u32 diff;
+
+	cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq;
+
+	diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS);
+	if (diff >= maxdiff)
+		return (__u32)-1;
+
+	return (cookie -
+		cookie_hash(saddr, daddr, sport, dport, count - diff, 1))
+		& COOKIEMASK;
+}
+
+__u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	const struct tcphdr *th = tcp_hdr(skb);
+	int mssind;
+	const __u16 mss = *mssp;
+
+	tcp_sk(sk)->last_synq_overflow = jiffies;
+
+	for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
+		;
+	*mssp = msstab[mssind] + 1;
+
+	NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESSENT);
+
+	return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source,
+				     th->dest, ntohl(th->seq),
+				     jiffies / (HZ * 60), mssind);
+}
+
+static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	const struct tcphdr *th = tcp_hdr(skb);
+	__u32 seq = ntohl(th->seq) - 1;
+	__u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr,
+					    th->source, th->dest, seq,
+					    jiffies / (HZ * 60), COUNTER_TRIES);
+
+	return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+}
+
+struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
+{
+	struct inet_request_sock *ireq;
+	struct inet6_request_sock *ireq6;
+	struct tcp_request_sock *treq;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct tcp_sock *tp = tcp_sk(sk);
+	const struct tcphdr *th = tcp_hdr(skb);
+	__u32 cookie = ntohl(th->ack_seq) - 1;
+	struct sock *ret = sk;
+	struct request_sock *req;
+	int mss;
+	struct dst_entry *dst;
+	__u8 rcv_wscale;
+	struct tcp_options_received tcp_opt;
+	__u32 xmit_ts = 0;
+
+	if (!sysctl_tcp_syncookies || !th->ack)
+		goto out;
+
+	if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) ||
+		(mss = cookie_check(skb, cookie)) == 0) {
+		NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESFAILED);
+		goto out;
+	}
+
+	NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV);
+
+	/* check for timestamp cookie support */
+	memset(&tcp_opt, 0, sizeof(tcp_opt));
+	tcp_parse_options(skb, &tcp_opt, 0, 0);
+
+	if (tcp_opt.saw_tstamp)
+		xmit_ts = cookie_check_timestamp(tcp_opt.rcv_tsecr, &tcp_opt);
+
+	ret = NULL;
+	req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
+	if (!req)
+		goto out;
+
+	ireq = inet_rsk(req);
+	ireq6 = inet6_rsk(req);
+	treq = tcp_rsk(req);
+	ireq6->pktopts = NULL;
+
+	if (security_inet_conn_request(sk, skb, req)) {
+		reqsk_free(req);
+		goto out;
+	}
+
+	req->mss = mss;
+	ireq->rmt_port = th->source;
+	ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
+	ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
+	if (ipv6_opt_accepted(sk, skb) ||
+	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+		atomic_inc(&skb->users);
+		ireq6->pktopts = skb;
+	}
+
+	ireq6->iif = sk->sk_bound_dev_if;
+	/* So that link locals have meaning */
+	if (!sk->sk_bound_dev_if &&
+	    ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
+		ireq6->iif = inet6_iif(skb);
+
+	req->expires		= 0UL;
+	req->retrans		= 0;
+	ireq->snd_wscale        = tcp_opt.snd_wscale;
+	ireq->rcv_wscale        = tcp_opt.rcv_wscale;
+	ireq->sack_ok           = tcp_opt.sack_ok;
+	ireq->wscale_ok         = tcp_opt.wscale_ok;
+	ireq->tstamp_ok         = tcp_opt.tstamp_ok;
+	req->ts_recent          = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
+	treq->rcv_isn		= ntohl(th->seq) - 1;
+	treq->snt_isn		= cookie;
+	treq->ts_off		= xmit_ts ? tcp_opt.rcv_tsecr - xmit_ts : 0;
+
+	/*
+	 * We need to lookup the dst_entry to get the correct window size.
+	 * This is taken from tcp_v6_syn_recv_sock.  Somebody please enlighten
+	 * me if there is a preferred way.
+	 */
+	{
+		struct in6_addr *final_p = NULL, final;
+		struct flowi fl;
+		memset(&fl, 0, sizeof(fl));
+		fl.proto = IPPROTO_TCP;
+		ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
+		if (np->opt && np->opt->srcrt) {
+			struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+			ipv6_addr_copy(&final, &fl.fl6_dst);
+			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+			final_p = &final;
+		}
+		ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
+		fl.oif = sk->sk_bound_dev_if;
+		fl.fl_ip_dport = inet_rsk(req)->rmt_port;
+		fl.fl_ip_sport = inet_sk(sk)->sport;
+		security_req_classify_flow(req, &fl);
+		if (ip6_dst_lookup(sk, &dst, &fl)) {
+			reqsk_free(req);
+			goto out;
+		}
+		if (final_p)
+			ipv6_addr_copy(&fl.fl6_dst, final_p);
+		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+			goto out;
+	}
+
+	req->window_clamp = tcp_sk(sk)->window_clamp ?
+			    : dst_metric(dst, RTAX_WINDOW);
+
+	tcp_select_initial_window(tcp_full_space(sk), req->mss,
+				  &req->rcv_wnd, &req->window_clamp,
+				  ireq->wscale_ok, &rcv_wscale);
+
+	ireq->rcv_wscale = rcv_wscale;
+
+	ret = get_cookie_sock(sk, skb, req, dst);
+
+out:	return ret;
+}
+
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 896ebd0..7a48263 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -514,6 +514,20 @@ done:
 	return err;
 }
 
+static inline void syn_flood_warning(struct sk_buff *skb)
+{
+#ifdef CONFIG_SYN_COOKIES
+	if (sysctl_tcp_syncookies)
+		printk(KERN_INFO
+		       "TCPv6: Possible SYN flooding on port %d. "
+		       "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
+	else
+#endif
+		printk(KERN_INFO
+		       "TCPv6: Possible SYN flooding on port %d. "
+		       "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
+}
+
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
 {
 	if (inet6_rsk(req)->pktopts)
@@ -917,7 +931,7 @@ done_opts:
 }
 #endif
 
-static struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
+struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
 	.family		=	AF_INET6,
 	.obj_size	=	sizeof(struct tcp6_request_sock),
 	.rtx_syn_ack	=	tcp_v6_send_synack,
@@ -1215,9 +1229,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 		return NULL;
 	}
 
-#if 0 /*def CONFIG_SYN_COOKIES*/
+#ifdef CONFIG_SYN_COOKIES
 	if (!th->rst && !th->syn && th->ack)
-		sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
+		sk = cookie_v6_check(sk, skb);
 #endif
 	return sk;
 }
@@ -1233,6 +1247,11 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct request_sock *req = NULL;
 	__u32 isn = TCP_SKB_CB(skb)->when;
+#ifdef CONFIG_SYN_COOKIES
+	int want_cookie = 0;
+#else
+#define want_cookie 0
+#endif
 
 	if (skb->protocol == htons(ETH_P_IP))
 		return tcp_v4_conn_request(sk, skb);
@@ -1240,12 +1259,14 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (!ipv6_unicast_destination(skb))
 		goto drop;
 
-	/*
-	 *	There are no SYN attacks on IPv6, yet...
-	 */
 	if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
 		if (net_ratelimit())
-			printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
+			syn_flood_warning(skb);
+#ifdef CONFIG_SYN_COOKIES
+		if (sysctl_tcp_syncookies)
+			want_cookie = 1;
+		else
+#endif
 		goto drop;
 	}
 
@@ -1266,29 +1287,40 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 
 	tcp_parse_options(skb, &tmp_opt, 0, 0);
 
+	if (want_cookie && !tmp_opt.saw_tstamp)
+		tcp_clear_options(&tmp_opt);
+
 	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 	tcp_openreq_init(req, &tmp_opt, skb);
 
 	treq = inet6_rsk(req);
 	ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
 	ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
-	TCP_ECN_create_request(req, tcp_hdr(skb));
 	treq->pktopts = NULL;
-	if (ipv6_opt_accepted(sk, skb) ||
-	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
-	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
-		atomic_inc(&skb->users);
-		treq->pktopts = skb;
-	}
-	treq->iif = sk->sk_bound_dev_if;
+	if (!want_cookie)
+		TCP_ECN_create_request(req, tcp_hdr(skb));
+
+	if (want_cookie) {
+#ifdef CONFIG_SYN_COOKIES
+		tcp_rsk(req)->want_cookie_ts = tmp_opt.saw_tstamp;
+#endif
+		isn = cookie_v6_init_sequence(sk, skb, &req->mss);
+	} else if (!isn) {
+		if (ipv6_opt_accepted(sk, skb) ||
+		    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+		    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+			atomic_inc(&skb->users);
+			treq->pktopts = skb;
+		}
+		treq->iif = sk->sk_bound_dev_if;
 
-	/* So that link locals have meaning */
-	if (!sk->sk_bound_dev_if &&
-	    ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
-		treq->iif = inet6_iif(skb);
+		/* So that link locals have meaning */
+		if (!sk->sk_bound_dev_if &&
+		    ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
+			treq->iif = inet6_iif(skb);
 
-	if (isn == 0)
 		isn = tcp_v6_init_sequence(skb);
+	}
 
 	tcp_rsk(req)->snt_isn = isn;
 
@@ -1297,8 +1329,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (tcp_v6_send_synack(sk, req, NULL))
 		goto drop;
 
-	inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
-	return 0;
+	if (!want_cookie) {
+		inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
+		return 0;
+	}
 
 drop:
 	if (req)
-- 
1.5.4


^ permalink raw reply related

* [PATCH 2/3] Enable the use of TCP options with syncookies
From: Glenn Griffin @ 2008-02-15 17:47 UTC (permalink / raw)
  To: netdev, linux-kernel; +Cc: Glenn Griffin
In-Reply-To: <1203097630-13237-1-git-send-email-ggriffin.kernel@gmail.com>

Allow the use of extended tcp options when syncookies are in use and the
client supports tcp timestamps.

The general concept is to encode the tcp options as the initial timestamp
that we send to the requestor in our synack.  We can then decode the
timestamp echo reply value on the returning ack.

This implementation encodes the following options in the timestamp,
snd_wscale, rcv_wscale, sack_ok, and also the necessary bits to calculate
the rtt, and ts_off accurately.  Note that there are still 5 unused bits
that could be used for future options.

Signed-off-by: Glenn Griffin <ggriffin.kernel@gmail.com>
---
 include/linux/tcp.h   |    3 ++
 include/net/tcp.h     |    4 ++
 net/ipv4/syncookies.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++--
 net/ipv4/tcp_ipv4.c   |    5 +--
 net/ipv4/tcp_output.c |   10 +++++-
 5 files changed, 104 insertions(+), 8 deletions(-)

diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 68387dc..f5a23e1 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -233,6 +233,9 @@ struct tcp_request_sock {
 	u32			 	rcv_isn;
 	u32			 	snt_isn;
 	u32				ts_off;
+#ifdef CONFIG_SYN_COOKIES
+	u8				want_cookie_ts;
+#endif
 };
 
 static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index c935de7..42b36f5 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -438,6 +438,7 @@ extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 				    struct ip_options *opt);
 extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, 
 				     __u16 *mss);
+extern __u32 cookie_init_timestamp(struct request_sock *req);
 
 /* tcp_output.c */
 
@@ -958,6 +959,9 @@ static inline void tcp_openreq_init(struct request_sock *req,
 	ireq->acked = 0;
 	ireq->ecn_ok = 0;
 	ireq->rmt_port = tcp_hdr(skb)->source;
+#ifdef CONFIG_SYN_COOKIES
+	tcp_rsk(req)->want_cookie_ts = 0;
+#endif
 }
 
 extern void tcp_enter_memory_pressure(void);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index f470fe4..eb5d804 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -35,6 +35,9 @@ module_init(init_syncookies);
 #define COOKIEBITS 24	/* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
+#define TSBITS 18
+#define TSMASK (((__u32)1 << TSBITS) - 1)
+
 static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
 		       u32 count, int c)
 {
@@ -144,6 +147,23 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
 				     jiffies / (HZ * 60), mssind);
 }
 
+__u32 cookie_init_timestamp(struct request_sock *req)
+{
+	struct inet_request_sock *ireq = inet_rsk(req);
+	__u32 init_ts = 0;
+
+	if (ireq->wscale_ok) {
+		init_ts |= ireq->snd_wscale << TSBITS;
+		init_ts |= ireq->rcv_wscale << (4 + TSBITS);
+	}
+	init_ts |= ireq->sack_ok << (8 + TSBITS);
+
+	init_ts |= tcp_time_stamp & TSMASK;
+
+	return init_ts;
+}
+
+
 /*
  * This (misnamed) value is the age of syncookie which is permitted.
  * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
@@ -184,6 +204,52 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
 	return child;
 }
 
+/* when syncookies are in effect and tcp timestamps are enabled we will store
+ * additional tcp options encoded in the timestamp value.
+ *
+ * The 18 lsb of tcp timestamp is stored in the 18 lsb of the tcp timestamp sent
+ *
+ * 18 bits should be enough to contain a very conservative 2*MSL on a 1000 HZ
+ * system
+ *
+ * The next 4 lsb are for snd_wscale
+ * The next 4 lsb are for rcv_wscale
+ * The next 1 lsb are for sack_ok
+ */
+static __u32 cookie_check_timestamp(__u32 ts,
+				    struct tcp_options_received *tcp_opt)
+{
+	__u32 init_ts = ts & TSMASK;
+
+	 /*
+	  * check if tcp_time_stamp overflowed 18bits
+	  * while waiting for response
+	  */
+	if ((tcp_time_stamp & TSMASK) >= init_ts)
+		/* likely no overflow occurred */
+		init_ts |= tcp_time_stamp & (~TSMASK);
+	else
+		/*
+		 * overflow occurred, but we can be sure it's only one bit
+		 * since the cookie_check verifies the cookie was generated
+		 * within the last 4 minutes
+		 */
+		init_ts |= ((tcp_time_stamp >> TSBITS) - 1) << TSBITS;
+
+	tcp_opt->tstamp_ok = 1;
+	tcp_opt->snd_wscale = (ts >> TSBITS) & 0xf;
+	tcp_opt->rcv_wscale = (ts >> (TSBITS + 4)) & 0xf;
+	tcp_opt->sack_ok = (ts >> (TSBITS + 8)) & 0x1;
+
+	if (tcp_opt->sack_ok)
+		tcp_sack_reset(tcp_opt);
+
+	if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale)
+		tcp_opt->wscale_ok = 1;
+
+	return init_ts;
+}
+
 struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 			     struct ip_options *opt)
 {
@@ -197,6 +263,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 	int mss;
 	struct rtable *rt;
 	__u8 rcv_wscale;
+	struct tcp_options_received tcp_opt;
+	__u32 xmit_ts = 0;
 
 	if (!sysctl_tcp_syncookies || !th->ack)
 		goto out;
@@ -209,6 +277,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 
 	NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV);
 
+	/* check for timestamp cookie support */
+	memset(&tcp_opt, 0, sizeof(tcp_opt));
+	tcp_parse_options(skb, &tcp_opt, 0, 0);
+
+	if (tcp_opt.saw_tstamp)
+		xmit_ts = cookie_check_timestamp(tcp_opt.rcv_tsecr, &tcp_opt);
+
 	ret = NULL;
 	req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */
 	if (!req)
@@ -222,11 +297,18 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 	treq = tcp_rsk(req);
 	treq->rcv_isn		= ntohl(th->seq) - 1;
 	treq->snt_isn		= cookie;
+	treq->ts_off		= xmit_ts ? tcp_opt.rcv_tsecr - xmit_ts : 0;
 	req->mss		= mss;
 	ireq->rmt_port		= th->source;
 	ireq->loc_addr		= ip_hdr(skb)->daddr;
 	ireq->rmt_addr		= ip_hdr(skb)->saddr;
 	ireq->opt		= NULL;
+	ireq->snd_wscale	= tcp_opt.snd_wscale;
+	ireq->rcv_wscale	= tcp_opt.rcv_wscale;
+	ireq->sack_ok		= tcp_opt.sack_ok;
+	ireq->wscale_ok		= tcp_opt.wscale_ok;
+	ireq->tstamp_ok		= tcp_opt.tstamp_ok;
+	req->ts_recent		= tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
 
 	/* We throwed the options of the initial SYN away, so we hope
 	 * the ACK carries the same options again (see RFC1122 4.2.3.8)
@@ -241,8 +323,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 		}
 	}
 
-	ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0;
-	ireq->wscale_ok	 = ireq->sack_ok = 0;
 	req->expires	= 0UL;
 	req->retrans	= 0;
 
@@ -271,10 +351,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 	}
 
 	/* Try to redo what tcp_v4_send_synack did. */
-	req->window_clamp = dst_metric(&rt->u.dst, RTAX_WINDOW);
+	req->window_clamp = tcp_sk(sk)->window_clamp ?
+			    : dst_metric(&rt->u.dst, RTAX_WINDOW);
+
 	tcp_select_initial_window(tcp_full_space(sk), req->mss,
 				  &req->rcv_wnd, &req->window_clamp,
-				  0, &rcv_wscale);
+				  ireq->wscale_ok, &rcv_wscale);
 	/* BTW win scale with syncookies is 0 by definition */
 	ireq->rcv_wscale  = rcv_wscale;
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 267eda9..e20f78e 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1297,10 +1297,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 
 	tcp_parse_options(skb, &tmp_opt, 0, 0);
 
-	if (want_cookie) {
+	if (want_cookie && !tmp_opt.saw_tstamp)
 		tcp_clear_options(&tmp_opt);
-		tmp_opt.saw_tstamp = 0;
-	}
 
 	if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) {
 		/* Some OSes (unknown ones, but I see them on web server, which
@@ -1328,6 +1326,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (want_cookie) {
 #ifdef CONFIG_SYN_COOKIES
 		syn_flood_warning(skb);
+		tcp_rsk(req)->want_cookie_ts = tmp_opt.saw_tstamp;
 #endif
 		isn = cookie_v4_init_sequence(sk, skb, &req->mss);
 	} else if (!isn) {
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 81f1383..0c900e0 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2227,7 +2227,15 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
 	th->window = htons(min(req->rcv_wnd, 65535U));
 
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
-	tcp_rsk(req)->ts_off = 1000 - TCP_SKB_CB(skb)->when;
+
+#ifdef CONFIG_SYN_COOKIES
+	if (tcp_rsk(req)->want_cookie_ts)
+		tcp_rsk(req)->ts_off = cookie_init_timestamp(req) -
+				       TCP_SKB_CB(skb)->when;
+	else
+#endif
+		tcp_rsk(req)->ts_off = 1000 - TCP_SKB_CB(skb)->when;
+
 	tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
 			      ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,
 			      TCP_SKB_CB(skb)->when + tcp_rsk(req)->ts_off,
-- 
1.5.4


^ permalink raw reply related

* [PATCH 1/3] Support arbitrary initial TCP timestamps
From: Glenn Griffin @ 2008-02-15 17:47 UTC (permalink / raw)
  To: netdev, linux-kernel; +Cc: Glenn Griffin

Introduce the ability to send arbitrary initial tcp timestamps that are not
tied directly to jiffies.  The basic conecpt is every tcp_request_sock and
tcp_sock now has a ts_off offset that represents the difference between
tcp_time_stamp and the timestamp we send and expect to
receive.

This has the advantage of not divulging system information (uptime)
depending on the policy chosen for the initial timestamps.

A policy where ts_off is always set to zero should produce no change in
behavior.  The policy implemented is not intended for real use, but just as
a simple example.  A realistic example would probably be similar to the tcp
init sequence generator.

Signed-off-by: Glenn Griffin <ggriffin.kernel@gmail.com>
---
 include/linux/tcp.h      |    6 ++++++
 include/net/tcp.h        |    2 +-
 net/ipv4/tcp_input.c     |   12 ++++++------
 net/ipv4/tcp_ipv4.c      |    2 +-
 net/ipv4/tcp_minisocks.c |    5 +++--
 net/ipv4/tcp_output.c    |    8 +++++---
 net/ipv6/tcp_ipv6.c      |    2 +-
 7 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 08027f1..68387dc 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -232,6 +232,7 @@ struct tcp_request_sock {
 #endif
 	u32			 	rcv_isn;
 	u32			 	snt_isn;
+	u32				ts_off;
 };
 
 static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
@@ -311,6 +312,11 @@ struct tcp_sock {
 	struct tcp_options_received rx_opt;
 
 /*
+ * 	offset of transmitted tcp timestamp from jiffies
+ */
+	u32	ts_off;
+
+/*
  *	Slow start and congestion control (see also Nagle, and Karn & Partridge)
  */
  	u32	snd_ssthresh;	/* Slow start size threshold		*/
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 7de4ea3..c935de7 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -395,7 +395,7 @@ extern int			tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
 
 extern void			tcp_parse_options(struct sk_buff *skb,
 						  struct tcp_options_received *opt_rx,
-						  int estab);
+						  int estab, u32 tsecr_off);
 
 /*
  *	TCP v4 functions exported for the inet6 API
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 19c449f..95fa8dc 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3264,7 +3264,7 @@ uninteresting_ack:
  * the fast version below fails.
  */
 void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
-		       int estab)
+		       int estab, u32 tsecr_off)
 {
 	unsigned char *ptr;
 	struct tcphdr *th = tcp_hdr(skb);
@@ -3322,7 +3322,7 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
 				     (!estab && sysctl_tcp_timestamps))) {
 					opt_rx->saw_tstamp = 1;
 					opt_rx->rcv_tsval = ntohl(get_unaligned((__be32 *)ptr));
-					opt_rx->rcv_tsecr = ntohl(get_unaligned((__be32 *)(ptr+4)));
+					opt_rx->rcv_tsecr = ntohl(get_unaligned((__be32 *)(ptr+4))) - tsecr_off;
 				}
 				break;
 			case TCPOPT_SACK_PERM:
@@ -3374,11 +3374,11 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
 			++ptr;
 			tp->rx_opt.rcv_tsval = ntohl(*ptr);
 			++ptr;
-			tp->rx_opt.rcv_tsecr = ntohl(*ptr);
+			tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->ts_off;
 			return 1;
 		}
 	}
-	tcp_parse_options(skb, &tp->rx_opt, 1);
+	tcp_parse_options(skb, &tp->rx_opt, 1, tp->ts_off);
 	return 1;
 }
 
@@ -4615,7 +4615,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 			++ptr;
 			tp->rx_opt.rcv_tsval = ntohl(*ptr);
 			++ptr;
-			tp->rx_opt.rcv_tsecr = ntohl(*ptr);
+			tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->ts_off;
 
 			/* If PAWS failed, check it more carefully in slow path */
 			if ((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) < 0)
@@ -4824,7 +4824,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	int saved_clamp = tp->rx_opt.mss_clamp;
 
-	tcp_parse_options(skb, &tp->rx_opt, 0);
+	tcp_parse_options(skb, &tp->rx_opt, 0, tp->ts_off);
 
 	if (th->ack) {
 		/* rfc793:
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 63414ea..267eda9 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1295,7 +1295,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	tmp_opt.mss_clamp = 536;
 	tmp_opt.user_mss  = tcp_sk(sk)->rx_opt.user_mss;
 
-	tcp_parse_options(skb, &tmp_opt, 0);
+	tcp_parse_options(skb, &tmp_opt, 0, 0);
 
 	if (want_cookie) {
 		tcp_clear_options(&tmp_opt);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index b61b768..648f84e 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -102,7 +102,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
 
 	tmp_opt.saw_tstamp = 0;
 	if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
-		tcp_parse_options(skb, &tmp_opt, 0);
+		tcp_parse_options(skb, &tmp_opt, 0, 0);
 
 		if (tmp_opt.saw_tstamp) {
 			tmp_opt.ts_recent	= tcptw->tw_ts_recent;
@@ -442,6 +442,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
 			inet_csk_reset_keepalive_timer(newsk,
 						       keepalive_time_when(newtp));
 
+		newtp->ts_off = treq->ts_off;
 		newtp->rx_opt.tstamp_ok = ireq->tstamp_ok;
 		if ((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) {
 			if (sysctl_tcp_fack)
@@ -502,7 +503,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
 
 	tmp_opt.saw_tstamp = 0;
 	if (th->doff > (sizeof(struct tcphdr)>>2)) {
-		tcp_parse_options(skb, &tmp_opt, 0);
+		tcp_parse_options(skb, &tmp_opt, 0, tcp_rsk(req)->ts_off);
 
 		if (tmp_opt.saw_tstamp) {
 			tmp_opt.ts_recent = req->ts_recent;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index ed750f9..81f1383 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -583,7 +583,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 				      (sysctl_flags & SYSCTL_FLAG_SACK),
 				      (sysctl_flags & SYSCTL_FLAG_WSCALE),
 				      tp->rx_opt.rcv_wscale,
-				      tcb->when,
+				      tcb->when + tp->ts_off,
 				      tp->rx_opt.ts_recent,
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -592,7 +592,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 				      NULL);
 	} else {
 		tcp_build_and_update_options((__be32 *)(th + 1),
-					     tp, tcb->when,
+					     tp, tcb->when + tp->ts_off,
 #ifdef CONFIG_TCP_MD5SIG
 					     md5 ? &md5_hash_location :
 #endif
@@ -2227,9 +2227,10 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
 	th->window = htons(min(req->rcv_wnd, 65535U));
 
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
+	tcp_rsk(req)->ts_off = 1000 - TCP_SKB_CB(skb)->when;
 	tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
 			      ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,
-			      TCP_SKB_CB(skb)->when,
+			      TCP_SKB_CB(skb)->when + tcp_rsk(req)->ts_off,
 			      req->ts_recent,
 			      (
 #ifdef CONFIG_TCP_MD5SIG
@@ -2335,6 +2336,7 @@ int tcp_connect(struct sock *sk)
 
 	/* Send it off. */
 	TCP_SKB_CB(buff)->when = tcp_time_stamp;
+	tp->ts_off = 2000 - TCP_SKB_CB(buff)->when;
 	tp->retrans_stamp = TCP_SKB_CB(buff)->when;
 	skb_header_release(buff);
 	__tcp_add_write_queue_tail(sk, buff);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 12750f2..896ebd0 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1264,7 +1264,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 	tmp_opt.user_mss = tp->rx_opt.user_mss;
 
-	tcp_parse_options(skb, &tmp_opt, 0);
+	tcp_parse_options(skb, &tmp_opt, 0, 0);
 
 	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 	tcp_openreq_init(req, &tmp_opt, skb);
-- 
1.5.4


^ permalink raw reply related

* Re: [PATCH] drivers/base: export gpl (un)register_memory_notifier
From: Dave Hansen @ 2008-02-15 16:55 UTC (permalink / raw)
  To: Christoph Raisch
  Cc: apw, Greg KH, Jan-Bernd Themann, linux-kernel, linuxppc-dev,
	netdev, ossthema, Badari Pulavarty, Thomas Q Klein, tklein
In-Reply-To: <OF58A8E0B3.B5CC265E-ONC12573F0.00496E2B-C12573F0.0049850F@de.ibm.com>

On Fri, 2008-02-15 at 14:22 +0100, Christoph Raisch wrote:
> A translation from kernel to ehea_bmap space should be fast and
> predictable
> (ruling out hashes).
> If a driver doesn't know anything else about the mapping structure,
> the normal solution in kernel for this type of problem is a multi
> level
> look up table
> like pgd->pud->pmd->pte
> This doesn't sound right to be implemented in a device driver.
> 
> We didn't see from the existing code that such a mapping to a
> contiguous
> space already exists.
> Maybe we've missed it.

I've been thinking about that, and I don't think you really *need* to
keep a comprehensive map like that.  

When the memory is in a particular configuration (range of memory
present along with unique set of holes) you get a unique ehea_bmap
configuration.  That layout is completely predictable.

So, if at any time you want to figure out what the ehea_bmap address for
a particular *Linux* virtual address is, you just need to pretend that
you're creating the entire ehea_bmap, use the same algorithm and figure
out host you would have placed things, and use that result.

Now, that's going to be a slow, crappy linear search (but maybe not as
slow as recreating the silly thing).  So, you might eventually run into
some scalability problems with a lot of packets going around.  But, I'd
be curious if you do in practice.

The other idea is that you create a mapping that is precisely 1:1 with
kernel memory.  Let's say you have two sections present, 0 and 100.  You
have a high_section_index of 100, and you vmalloc() a 100 entry array.

You need to create a *CONTIGUOUS* ehea map?  Create one like this:

EHEA_VADDR->Linux Section
0->0
1->0
2->0
3->0
...
100->100

It's contiguous.  Each area points to a valid Linux memory address.
It's also discernable in O(1) to what EHEA address a given Linux address
is mapped.  You just have a couple of duplicate entries.  

-- Dave


^ permalink raw reply

* Re: [PATCH] Make sure sockets implement splice_read
From: Andi Kleen @ 2008-02-15 16:46 UTC (permalink / raw)
  To: Rémi Denis-Courmont; +Cc: Andi Kleen, David Miller, netdev
In-Reply-To: <200802151840.16824.rdenis@simphalempin.com>

Rémi Denis-Courmont <rdenis@simphalempin.com> writes:

> Le Friday 15 February 2008 18:30:11 Andi Kleen, vous avez écrit :
>> David Miller <davem@davemloft.net> writes:
>> > From: Rémi_Denis-Courmont <rdenis@simphalempin.com>
>> > Date: Thu, 14 Feb 2008 18:53:34 +0200
>> >
>> >> Fixes a segmentation fault when trying to splice from a non-TCP socket.
>> >>
>> >> Signed-off-by: Rémi Denis-Courmont <rdenis@simphalempin.com>
>> >
>> > Applied, thank you.
>>
>> That's also a stable candidate, isn't it?
>
> Should go to 2.6.25-rc2, but the offending code is not in any stable release.

You're right. I misinterpreted git describe output for this one. Sorry.

-Andi

^ permalink raw reply

* Re: [PATCH] Make sure sockets implement splice_read
From: Rémi Denis-Courmont @ 2008-02-15 16:40 UTC (permalink / raw)
  To: Andi Kleen; +Cc: David Miller, netdev
In-Reply-To: <p73k5l6yygc.fsf@bingen.suse.de>

Le Friday 15 February 2008 18:30:11 Andi Kleen, vous avez écrit :
> David Miller <davem@davemloft.net> writes:
> > From: Rémi_Denis-Courmont <rdenis@simphalempin.com>
> > Date: Thu, 14 Feb 2008 18:53:34 +0200
> >
> >> Fixes a segmentation fault when trying to splice from a non-TCP socket.
> >>
> >> Signed-off-by: Rémi Denis-Courmont <rdenis@simphalempin.com>
> >
> > Applied, thank you.
>
> That's also a stable candidate, isn't it?

Should go to 2.6.25-rc2, but the offending code is not in any stable release.

-- 
Rémi Denis-Courmont
http://www.remlab.net/

^ permalink raw reply

* Re: [PATCH] Make sure sockets implement splice_read
From: Andi Kleen @ 2008-02-15 16:30 UTC (permalink / raw)
  To: David Miller; +Cc: rdenis, netdev
In-Reply-To: <20080215.023601.219994317.davem@davemloft.net>

David Miller <davem@davemloft.net> writes:

> From: Rémi_Denis-Courmont <rdenis@simphalempin.com>
> Date: Thu, 14 Feb 2008 18:53:34 +0200
>
>> Fixes a segmentation fault when trying to splice from a non-TCP socket.
>> 
>> Signed-off-by: Rémi Denis-Courmont <rdenis@simphalempin.com>
>
> Applied, thank you.

That's also a stable candidate, isn't it? 

-Andi

^ 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