* [ANNOUNCE] bridge-utils 1.5
From: Stephen Hemminger @ 2011-03-29 1:13 UTC (permalink / raw)
To: netdev, bridge; +Cc: linux-kernel
The Bridge Utilities haven't been re-released in a very long time.
The only new feature is the introduction of hairpin mode.
Note: this is probably the last release of these utilities because
I am actively working on intergrating bridge utility into iproute2
using netlink.
Package download:
http://sourceforge.net/projects/bridge/files/bridge/bridge-utils-1.5.tar.gz/download
Repository:
git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git
Information:
http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge
Report problems (or enhancements) to the netdev@vger.kernel.org mailing list.
Changelog:
Anton Danilov (1):
show selected bridge
Fischer, Anna (1):
bridge-utils: Add 'hairpin' port forwarding mode
Stephen Hemminger (8):
don't install libbridge.a
use proper version of install in doc/Makefile
Check for fopen() failing
Skip . and .. in foreach_bridge test
Handle unknown attributes more gracefully
bridge-utils 1.5
update mailing address
Update URL of git repository
^ permalink raw reply
* Re: [PATCH v2] ROSE: prevent heap corruption with bad facilities
From: Ben Hutchings @ 2011-03-29 1:16 UTC (permalink / raw)
To: ralf; +Cc: drosenberg, netdev, security, David Miller
In-Reply-To: <20110327.175936.189721420.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 854 bytes --]
On Sun, 2011-03-27 at 17:59 -0700, David Miller wrote:
> From: Ben Hutchings <ben@decadent.org.uk>
> Date: Sun, 20 Mar 2011 16:48:05 +0000
>
> > Subject: [PATCH] rose: Add length checks to CALL_REQUEST parsing
> >
> > Define some constant offsets for CALL_REQUEST based on the description
> > at <http://www.techfest.com/networking/wan/x25plp.htm> and the
> > definition of ROSE as using 10-digit (5-byte) addresses. Use them
> > consistently. Validate all implicit and explicit facilities lengths.
> > Validate the address length byte rather than either trusting or
> > assuming its value.
> >
> > Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
>
> Applied.
Ralf, I would really appreciate it if you could test this soon...
Ben.
--
Ben Hutchings
Once a job is fouled up, anything done to improve it makes it worse.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply
* Re: zero copy for relay server
From: Changli Gao @ 2011-03-29 2:00 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Viral Mehta, netdev@vger.kernel.org
In-Reply-To: <1301337257.2506.8.camel@edumazet-laptop>
On Tue, Mar 29, 2011 at 2:34 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le lundi 28 mars 2011 à 23:48 +0530, Viral Mehta a écrit :
>
>> Still, these are two system calls.
>
> Yes. Is it a problem ? What kind ?
I think he concerns the overhead of system calls. In order to omit a
system call, I think you can implement sth. like this:
splice2(infd, outfd, pipefd, ...)
What you need do is maintaining pipes by yourself.
>> 2. I believe underlying PIPE that we are using will also have some size limit
>> (like in user space 4K or 64K, not sure)
>
> What kind of socket is able to deliver more than 64K frames ?
You can enlarge the size with fcntl(pipefd, F_SETPIPE_SZ,...).
>
>>
>> So, all in all
>> Why cant we have just one system call which really transfers "length"
>> bytes of data form one socket to another ? Recv "length" bytes of data
>> from socket A and send to socket B.
>>
>> I wanted to understand if there are any limitations or concerns that we still do
>> not have any such system call .... ?
>>
>
> The answer is : Once you try to implement this, you'll discover it'll be
> splice() based, using pipe as a buffer between the sockets.
Yes, but I think the internal buffer of pipe is pages, and it limits
its use in socket context. See skb_splice_bits(), and I am afraid copy
usually happens. Maybe the buffer of pipe should be any data but with
proper tear down functions.
>
> sendfile() is based on top of splice(), but it's faster to use splice().
>
>
Why? Thanks.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* [PATCH] drivers/net: Remove IRQF_SAMPLE_RANDOM flag from network drivers
From: Javier Martinez Canillas @ 2011-03-29 2:27 UTC (permalink / raw)
To: David Miller
Cc: Ben Hutchings, Florian Fainelli, Eric Dumazet, netdev,
kernel-janitors, linux-kernel, Javier Martinez Canillas
The IRQF_SAMPLE_RANDOM flag is marked as deprecated and will be removed.
Every input point to the kernel's entropy pool have to better document the
type of entropy source it is.
drivers/char/random.c now implements a set of interfaces that can be used for
devices to collect enviromental noise. IRQF_SAMPLE_RANDOM will be replaced
with these add_*_randomness exported functions.
Network drivers are not a good source of entropy. They use as a source of
entropy essentially a remote host. Which means that the source of entropy can
be potentially controlled by an attacker. Also, with heavy workloads the
entropy decreases due to less hardware interrupts happening thanks to irq
mitigation and NAPI.
If a system relies in its network interface as a entropy source it has a false
sense of security. Systems that don't have devices whose drivers are good
sources of entropy, should either use a hardware random number generator or
feed the kernel's entropy pool from userspace using other sources of entropy
such as EGD, video_entropyd, timer_entropyd and audio-entropyd.
Signed-off-by: Javier Martinez Canillas <martinez.javier@gmail.com>
---
drivers/net/atlx/atl1.c | 2 +-
drivers/net/bcm63xx_enet.c | 4 ++--
drivers/net/cris/eth_v10.c | 4 ++--
drivers/net/ibmlana.c | 3 ++-
drivers/net/macb.c | 3 +--
drivers/net/netxen/netxen_nic_main.c | 2 +-
drivers/net/niu.c | 3 +--
drivers/net/qla3xxx.c | 2 +-
drivers/net/tg3.c | 4 ++--
drivers/net/xen-netfront.c | 3 +--
10 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 67f40b9..e973d05 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -2572,7 +2572,7 @@ static s32 atl1_up(struct atl1_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int err;
- int irq_flags = IRQF_SAMPLE_RANDOM;
+ int irq_flags = 0;
/* hardware has been reset, we need to reload some things */
atlx_set_multi(netdev);
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index e94a966a..2af413f 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -839,8 +839,8 @@ static int bcm_enet_open(struct net_device *dev)
if (ret)
goto out_phy_disconnect;
- ret = request_irq(priv->irq_rx, bcm_enet_isr_dma,
- IRQF_SAMPLE_RANDOM | IRQF_DISABLED, dev->name, dev);
+ ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, IRQF_DISABLED,
+ dev->name, dev);
if (ret)
goto out_freeirq;
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 80c2fee..e759d74 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -491,8 +491,8 @@ e100_open(struct net_device *dev)
/* allocate the irq corresponding to the receiving DMA */
- if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt,
- IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) {
+ if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, cardname,
+ (void *)dev)) {
goto grace_exit0;
}
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 94d9969..f872f96 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -782,7 +782,8 @@ static int ibmlana_open(struct net_device *dev)
/* register resources - only necessary for IRQ */
- result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
+ result = request_irq(priv->realirq, irq_handler, IRQF_SHARED,
+ dev->name, dev);
if (result != 0) {
printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq);
return result;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 79ccb54..2cb4e792 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -1171,8 +1171,7 @@ static int __init macb_probe(struct platform_device *pdev)
}
dev->irq = platform_get_irq(pdev, 0);
- err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM,
- dev->name, dev);
+ err = request_irq(dev->irq, macb_interrupt, 0, dev->name, dev);
if (err) {
printk(KERN_ERR
"%s: Unable to request IRQ %d (error %d)\n",
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 83348dc..9336715 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -905,7 +905,7 @@ netxen_nic_request_irq(struct netxen_adapter *adapter)
struct nx_host_sds_ring *sds_ring;
int err, ring;
- unsigned long flags = IRQF_SAMPLE_RANDOM;
+ unsigned long flags = 0;
struct net_device *netdev = adapter->netdev;
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 32678b6..681a42c 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -6071,8 +6071,7 @@ static int niu_request_irq(struct niu *np)
for (i = 0; i < np->num_ldg; i++) {
struct niu_ldg *lp = &np->ldg[i];
- err = request_irq(lp->irq, niu_interrupt,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED,
np->irq_name[i], lp);
if (err)
goto out_free_irqs;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 348b4f136..f3f737b 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -3468,7 +3468,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
{
struct net_device *ndev = qdev->ndev;
int err;
- unsigned long irq_flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED;
+ unsigned long irq_flags = IRQF_SHARED;
unsigned long hw_flags;
if (ql_alloc_mem_resources(qdev)) {
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index ebec888..89b76f0 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -8839,12 +8839,12 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num)
fn = tg3_msi;
if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
fn = tg3_msi_1shot;
- flags = IRQF_SAMPLE_RANDOM;
+ flags = 0;
} else {
fn = tg3_interrupt;
if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
fn = tg3_interrupt_tagged;
- flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
+ flags = IRQF_SHARED;
}
return request_irq(tnapi->irq_vec, fn, flags, name, tnapi);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 5c8d9c3..c06f5a0 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1416,8 +1416,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
goto fail;
err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
- IRQF_SAMPLE_RANDOM, netdev->name,
- netdev);
+ 0, netdev->name, netdev);
if (err < 0)
goto fail;
netdev->irq = err;
--
1.7.2.5
^ permalink raw reply related
* [PATCH 1/2] via-ircc: Use pci_{get,set}_drvdata() instead of static pointer variable
From: Ben Hutchings @ 2011-03-29 3:10 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Andrew Buckeridge, Samuel Ortiz
via-ircc still maintains its own array of device pointers in Linux 2.4
style. Worse, it always uses index 0, so it will crash if there are
multiple suitable devices in the system.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
It seems that a bunch of 'FIXME' comments with hints aren't enough to
attract kernel janitors (they've been there since the start of git
history).
This is really cleanup in preparation for another fix. Andrew
Buckeridge has tested this as far as loading the driver, but the IrDA
header isn't connected on his system.
Ben.
drivers/net/irda/via-ircc.c | 82 ++++++++-----------------------------------
1 files changed, 15 insertions(+), 67 deletions(-)
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 67c0ad4..cc6faca 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -75,15 +75,9 @@ static int dongle_id = 0; /* default: probe */
/* We can't guess the type of connected dongle, user *must* supply it. */
module_param(dongle_id, int, 0);
-/* FIXME : we should not need this, because instances should be automatically
- * managed by the PCI layer. Especially that we seem to only be using the
- * first entry. Jean II */
-/* Max 4 instances for now */
-static struct via_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
-
/* Some prototypes */
-static int via_ircc_open(int i, chipio_t * info, unsigned int id);
-static int via_ircc_close(struct via_ircc_cb *self);
+static int via_ircc_open(struct pci_dev *pdev, chipio_t * info,
+ unsigned int id);
static int via_ircc_dma_receive(struct via_ircc_cb *self);
static int via_ircc_dma_receive_complete(struct via_ircc_cb *self,
int iobase);
@@ -215,7 +209,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi
pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0));
pci_write_config_byte(pcidev,0x5a,0xc0);
WriteLPCReg(0x28, 0x70 );
- if (via_ircc_open(0, &info,0x3076) == 0)
+ if (via_ircc_open(pcidev, &info, 0x3076) == 0)
rc=0;
} else
rc = -ENODEV; //IR not turn on
@@ -254,7 +248,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi
info.irq=FirIRQ;
info.dma=FirDRQ1;
info.dma2=FirDRQ0;
- if (via_ircc_open(0, &info,0x3096) == 0)
+ if (via_ircc_open(pcidev, &info, 0x3096) == 0)
rc=0;
} else
rc = -ENODEV; //IR not turn on !!!!!
@@ -264,48 +258,10 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi
return rc;
}
-/*
- * Function via_ircc_clean ()
- *
- * Close all configured chips
- *
- */
-static void via_ircc_clean(void)
-{
- int i;
-
- IRDA_DEBUG(3, "%s()\n", __func__);
-
- for (i=0; i < ARRAY_SIZE(dev_self); i++) {
- if (dev_self[i])
- via_ircc_close(dev_self[i]);
- }
-}
-
-static void __devexit via_remove_one (struct pci_dev *pdev)
-{
- IRDA_DEBUG(3, "%s()\n", __func__);
-
- /* FIXME : This is ugly. We should use pci_get_drvdata(pdev);
- * to get our driver instance and call directly via_ircc_close().
- * See vlsi_ir for details...
- * Jean II */
- via_ircc_clean();
-
- /* FIXME : This should be in via_ircc_close(), because here we may
- * theoritically disable still configured devices :-( - Jean II */
- pci_disable_device(pdev);
-}
-
static void __exit via_ircc_cleanup(void)
{
IRDA_DEBUG(3, "%s()\n", __func__);
- /* FIXME : This should be redundant, as pci_unregister_driver()
- * should call via_remove_one() on each device.
- * Jean II */
- via_ircc_clean();
-
/* Cleanup all instances of the driver */
pci_unregister_driver (&via_driver);
}
@@ -324,12 +280,13 @@ static const struct net_device_ops via_ircc_fir_ops = {
};
/*
- * Function via_ircc_open (iobase, irq)
+ * Function via_ircc_open(pdev, iobase, irq)
*
* Open driver instance
*
*/
-static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
+static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info,
+ unsigned int id)
{
struct net_device *dev;
struct via_ircc_cb *self;
@@ -337,9 +294,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
IRDA_DEBUG(3, "%s()\n", __func__);
- if (i >= ARRAY_SIZE(dev_self))
- return -ENOMEM;
-
/* Allocate new instance of the driver */
dev = alloc_irdadev(sizeof(struct via_ircc_cb));
if (dev == NULL)
@@ -349,13 +303,8 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
self->netdev = dev;
spin_lock_init(&self->lock);
- /* FIXME : We should store our driver instance in the PCI layer,
- * using pci_set_drvdata(), not in this array.
- * See vlsi_ir for details... - Jean II */
- /* FIXME : 'i' is always 0 (see via_init_one()) :-( - Jean II */
- /* Need to store self somewhere */
- dev_self[i] = self;
- self->index = i;
+ pci_set_drvdata(pdev, self);
+
/* Initialize Resource */
self->io.cfg_base = info->cfg_base;
self->io.fir_base = info->fir_base;
@@ -463,25 +412,24 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
err_out2:
release_region(self->io.fir_base, self->io.fir_ext);
err_out1:
+ pci_set_drvdata(pdev, NULL);
free_netdev(dev);
- dev_self[i] = NULL;
return err;
}
/*
- * Function via_ircc_close (self)
+ * Function via_remove_one(pdev)
*
* Close driver instance
*
*/
-static int via_ircc_close(struct via_ircc_cb *self)
+static void __devexit via_remove_one(struct pci_dev *pdev)
{
+ struct via_ircc_cb *self = pci_get_drvdata(pdev);
int iobase;
IRDA_DEBUG(3, "%s()\n", __func__);
- IRDA_ASSERT(self != NULL, return -1;);
-
iobase = self->io.fir_base;
ResetChip(iobase, 5); //hardware reset.
@@ -498,11 +446,11 @@ static int via_ircc_close(struct via_ircc_cb *self)
if (self->rx_buff.head)
dma_free_coherent(NULL, self->rx_buff.truesize,
self->rx_buff.head, self->rx_buff_dma);
- dev_self[self->index] = NULL;
+ pci_set_drvdata(pdev, NULL);
free_netdev(self->netdev);
- return 0;
+ pci_disable_device(pdev);
}
/*
--
1.7.4.1
^ permalink raw reply related
* [PATCH 2/2] via-ircc: Pass PCI device pointer to dma_{alloc,free}_coherent()
From: Ben Hutchings @ 2011-03-29 3:12 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Andrew Buckeridge, Samuel Ortiz, 619450
In-Reply-To: <1301368243.26693.751.camel@localhost>
via-ircc has been passing a NULL pointer to DMA allocation functions,
which is completely invalid and results in a BUG on PowerPC. Now
that we always have the device pointer available, pass it in.
Reference: http://bugs.debian.org/619450
Reported-by: Andrew Buckeridge <andrewb@bgc.com.au>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Tested-by: Andrew Buckeridge <andrewb@bgc.com.au> [against 2.6.32]
---
drivers/net/irda/via-ircc.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index cc6faca..186cd28 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -363,7 +363,7 @@ static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info,
/* Allocate memory if needed */
self->rx_buff.head =
- dma_alloc_coherent(NULL, self->rx_buff.truesize,
+ dma_alloc_coherent(&pdev->dev, self->rx_buff.truesize,
&self->rx_buff_dma, GFP_KERNEL);
if (self->rx_buff.head == NULL) {
err = -ENOMEM;
@@ -372,7 +372,7 @@ static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info,
memset(self->rx_buff.head, 0, self->rx_buff.truesize);
self->tx_buff.head =
- dma_alloc_coherent(NULL, self->tx_buff.truesize,
+ dma_alloc_coherent(&pdev->dev, self->tx_buff.truesize,
&self->tx_buff_dma, GFP_KERNEL);
if (self->tx_buff.head == NULL) {
err = -ENOMEM;
@@ -404,10 +404,10 @@ static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info,
via_hw_init(self);
return 0;
err_out4:
- dma_free_coherent(NULL, self->tx_buff.truesize,
+ dma_free_coherent(&pdev->dev, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
err_out3:
- dma_free_coherent(NULL, self->rx_buff.truesize,
+ dma_free_coherent(&pdev->dev, self->rx_buff.truesize,
self->rx_buff.head, self->rx_buff_dma);
err_out2:
release_region(self->io.fir_base, self->io.fir_ext);
@@ -441,10 +441,10 @@ static void __devexit via_remove_one(struct pci_dev *pdev)
__func__, self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
- dma_free_coherent(NULL, self->tx_buff.truesize,
+ dma_free_coherent(&pdev->dev, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
if (self->rx_buff.head)
- dma_free_coherent(NULL, self->rx_buff.truesize,
+ dma_free_coherent(&pdev->dev, self->rx_buff.truesize,
self->rx_buff.head, self->rx_buff_dma);
pci_set_drvdata(pdev, NULL);
--
1.7.4.1
^ permalink raw reply related
* [PATCH] via-rhine: trivial sparse annotation in vlan_tci helper
From: Harvey Harrison @ 2011-03-29 3:08 UTC (permalink / raw)
To: netdev
Noticed by sparse:
drivers/net/via-rhine.c:1706:16: warning: cast to restricted __be16
Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
---
drivers/net/via-rhine.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 5e7f069..707f7f8 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1703,7 +1703,7 @@ static void rhine_tx(struct net_device *dev)
static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size)
{
u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2;
- return ntohs(*(u16 *)trailer);
+ return be16_to_cpup((__be16 *)trailer);
}
/* Process up to limit frames from receive ring */
--
1.7.4
^ permalink raw reply related
* Re: zero copy for relay server
From: Eric Dumazet @ 2011-03-29 4:23 UTC (permalink / raw)
To: Changli Gao; +Cc: Viral Mehta, netdev@vger.kernel.org
In-Reply-To: <AANLkTimWf4kyi4HJFToXP=HH==hQgObQsHYyRfrSe0FS@mail.gmail.com>
Le mardi 29 mars 2011 à 10:00 +0800, Changli Gao a écrit :
> On Tue, Mar 29, 2011 at 2:34 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> I think he concerns the overhead of system calls. In order to omit a
> system call, I think you can implement sth. like this:
>
> splice2(infd, outfd, pipefd, ...)
>
Yes, but given no numbers are given, and no code yet written, I ask the
question.
Giving 4 file descriptors to a single syscall sounds convoluted.
> What you need do is maintaining pipes by yourself.
>
> >> 2. I believe underlying PIPE that we are using will also have some size limit
> >> (like in user space 4K or 64K, not sure)
> >
> > What kind of socket is able to deliver more than 64K frames ?
>
> You can enlarge the size with fcntl(pipefd, F_SETPIPE_SZ,...).
>
Not really useful, since splice() internals use automatic arrays sized
with PIPE_DEF_BUFFERS.
You can enlarge the size of pipe, but still we are limited to at most
64K in skb_splice_bits() for example [On x86 and its 4KB pages]
This doesnt matter, since skb are limited to 16 pages anyway (or 64Kb)
F_SETPIPE_SZ only can increase size of pipe ringbuffer (which should be
empty or contain at most one skb), therefore increasing dcache needs.
> >
> > sendfile() is based on top of splice(), but it's faster to use splice().
> >
> >
>
> Why? Thanks.
>
The real cost is not syscall overhead, but context switches and cache
misses. Adding a "super syscall" adds kernel text and increases icache
misses on real machine (I am not talking about machine used in micro
benchmarks)
Most likely, GRO can significantly speed this workload, while a syscall
avoidance wont.
^ permalink raw reply
* Re: [PATCH] net: Always allocate at least 16 skb frags regardless of page size
From: David Miller @ 2011-03-29 5:27 UTC (permalink / raw)
To: anton; +Cc: eric.dumazet, herbert, netdev
In-Reply-To: <20110328115726.4cca214d@kryten>
From: Anton Blanchard <anton@samba.org>
Date: Mon, 28 Mar 2011 11:57:26 +1100
>
> When analysing performance of the cxgb3 on a ppc64 box I noticed that
> we weren't doing much GRO merging. It turns out we are limited by the
> number of SKB frags:
>
> #define MAX_SKB_FRAGS (65536/PAGE_SIZE + 2)
>
> With a 4kB page size we have 18 frags, but with a 64kB page size we
> only have 3 frags.
>
> I ran a single stream TCP bandwidth test to compare the performance of
> different values of MAX_SKB_FRAGS on the receiver:
>
> MAX_SKB_FRAGS Mbps
> 3 7080
> 8 7931 (+12%)
> 16 8335 (+17%)
> 32 8349 (+17%)
>
> Performance continues to increase up to 16 frags then levels off so
> the patch below puts a lower bound of 16 on MAX_SKB_FRAGS.
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
Thanks for investigating this and fixing the problem.
Applied.
^ permalink raw reply
* Re: [PATCH] cxgb3: Apply interrupt coalescing settings to all queues
From: David Miller @ 2011-03-29 5:27 UTC (permalink / raw)
To: divy; +Cc: anton, netdev
In-Reply-To: <4D90C862.2080207@chelsio.com>
From: Divy Le Ray <divy@chelsio.com>
Date: Mon, 28 Mar 2011 10:41:54 -0700
> On 03/27/2011 07:50 PM, Anton Blanchard wrote:
>>
>>
>> While testing the performance of different receive interrupt
>> coalescing settings on a single stream TCP benchmark, I noticed two
>> very different results. With rx-usecs=50, most of the time a
>> connection would hit 8280 Mbps but once in a while it would hit
>> 9330 Mbps.
>>
>> It turns out we are only applying the interrupt coalescing settings
>> to the first queue and whenever the rx hash would direct us onto
>> that queue we ran faster.
>>
>> With this patch applied and rx-usecs=50, I get 9330 Mbps
>> consistently.
>>
>> Signed-off-by: Anton Blanchard <anton@samba.org>
>
> Acked-by: Divy Le Ray <divy@chelsio.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] drivers net: Fix declaration ordering in inline functions.
From: David Miller @ 2011-03-29 5:27 UTC (permalink / raw)
To: balajig81; +Cc: netdev
In-Reply-To: <1301282119-2887-1-git-send-email-balajig81@gmail.com>
From: "G.Balaji" <balajig81@gmail.com>
Date: Mon, 28 Mar 2011 08:45:19 +0530
> The correct usage should be "static inline void" instead of "static void inline"
>
> Signed-off-by: G.Balaji <balajig81@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH v2] netdev: bfin_mac: document TE setting in RMII modes
From: David Miller @ 2011-03-29 5:27 UTC (permalink / raw)
To: vapier; +Cc: netdev, uclinux-dist-devel
In-Reply-To: <1301301193-18012-1-git-send-email-vapier@gentoo.org>
From: Mike Frysinger <vapier@gentoo.org>
Date: Mon, 28 Mar 2011 04:33:13 -0400
> The current code sometimes generates build warnings due to how it checks
> the silicon revision, so clean it up and properly document things.
>
> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Applied.
^ permalink raw reply
* [PATCH net-next-2.6 v1] sctp: Add Auto-ASCONF support
From: Michio Honda @ 2011-03-29 5:42 UTC (permalink / raw)
To: netdev; +Cc: lksctp-developers
SCTP reconfigure the IP addresses in the association by using ASCONF chunks as mentioned in RFC5061.
For example, we can start to use the newly configured IP address in the existing association.
ASCONF operation is invoked in two ways:
First is done by the application to call sctp_bindx() system call.
Second is automatic operation in the SCTP stack with address events in the host computer (called auto_asconf) .
The former is already implemented, but the latter is not yet. This patch enables it with one sysctl parameter and setsockopt() system call.
Signed-off-by: Michio Honda <micchie@sfc.wide.ad.jp>
---
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 11684d9..11c3060 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -767,6 +767,7 @@ enum {
NET_SCTP_SNDBUF_POLICY = 15,
NET_SCTP_SACK_TIMEOUT = 16,
NET_SCTP_RCVBUF_POLICY = 17,
+ NET_SCTP_AUTO_ASCONF_ENABLE = 18,
};
/* /proc/sys/net/bridge */
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index c70d8cc..d7a4ee3 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -441,4 +441,8 @@ enum {
*/
#define SCTP_AUTH_RANDOM_LENGTH 32
+/* ASCONF PARAMETERS */
+#define SCTP_ASCONF_V4_PARAM_LEN 16
+#define SCTP_ASCONF_V6_PARAM_LEN 28
+
#endif /* __sctp_constants_h__ */
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 505845d..7161932 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -121,6 +121,7 @@ extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
+void sctp_addr_wq_mgmt(union sctp_addr *, int);
/*
* sctp/socket.c
@@ -135,6 +136,8 @@ void sctp_sock_rfree(struct sk_buff *skb);
void sctp_copy_sock(struct sock *newsk, struct sock *sk,
struct sctp_association *asoc);
extern struct percpu_counter sctp_sockets_allocated;
+int sctp_asconf_mgmt(struct sctp_endpoint *, struct sock *sk);
+void sctp_add_addr_to_laddr(struct sockaddr *, struct sctp_association *);
/*
* sctp/primitive.c
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index 9352d12..498a3cf 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -259,6 +259,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf);
int sctp_process_asconf_ack(struct sctp_association *asoc,
struct sctp_chunk *asconf_ack);
+void sctp_path_check_and_react(struct sctp_association *, struct sockaddr *);
struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
__u32 new_cum_tsn, size_t nstreams,
struct sctp_fwdtsn_skip *skiplist);
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index cc9185c..0c6a6f4 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -205,6 +205,11 @@ extern struct sctp_globals {
* It is a list of sctp_sockaddr_entry.
*/
struct list_head local_addr_list;
+ int auto_asconf_enable;
+ struct list_head addr_waitq;
+ struct timer_list addr_wq_timer;
+ struct list_head auto_asconf_eplist;
+ spinlock_t addr_wq_lock;
/* Lock that protects the local_addr_list writers */
spinlock_t addr_list_lock;
@@ -264,6 +269,11 @@ extern struct sctp_globals {
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_local_addr_list (sctp_globals.local_addr_list)
#define sctp_local_addr_lock (sctp_globals.addr_list_lock)
+#define sctp_auto_asconf_eplist (sctp_globals.auto_asconf_eplist)
+#define sctp_addr_waitq (sctp_globals.addr_waitq)
+#define sctp_addr_wq_timer (sctp_globals.addr_wq_timer)
+#define sctp_addr_wq_lock (sctp_globals.addr_wq_lock)
+#define sctp_auto_asconf_enable (sctp_globals.auto_asconf_enable)
#define sctp_scope_policy (sctp_globals.ipv4_scope_policy)
#define sctp_addip_enable (sctp_globals.addip_enable)
#define sctp_addip_noauth (sctp_globals.addip_noauth_enable)
@@ -796,6 +806,16 @@ struct sctp_sockaddr_entry {
__u8 valid;
};
+#define SCTP_NEWADDR 1
+#define SCTP_DELADDR 2
+#define SCTP_ADDRESS_TICK_DELAY 500
+struct sctp_addr_wait {
+ struct list_head list;
+ struct rcu_head rcu;
+ union sctp_addr a;
+ int cmd;
+};
+
typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *);
/* This structure holds lists of chunks as we are assembling for
@@ -1239,6 +1259,7 @@ sctp_scope_t sctp_scope(const union sctp_addr *);
int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
int sctp_is_any(struct sock *sk, const union sctp_addr *addr);
int sctp_addr_is_valid(const union sctp_addr *addr);
+int sctp_is_ep_boundall(struct sock *sk);
/* What type of endpoint? */
@@ -1267,6 +1288,7 @@ struct sctp_ep_common {
/* Fields to help us manage our entries in the hash tables. */
struct hlist_node node;
int hashent;
+ struct list_head auto_asconf_list;
/* Runtime type information. What kind of endpoint is this? */
sctp_endpoint_type_t type;
@@ -1901,6 +1923,17 @@ struct sctp_association {
* after reaching 4294967295.
*/
__u32 addip_serial;
+ /* list of valid addresses in association local
+ * This list is needed to ensure base.bind_addr being a valid address
+ * list of the endpoint-wide. When one of associations receives
+ * ASCONF-ACK, that address is added to this list. When all
+ * associations belonging to the same endpoint receive ASCONF-ACKs,
+ * that address is added to base.bind_addr
+ */
+ struct list_head asoc_laddr_list;
+ union sctp_addr *asconf_addr_del_pending;
+ __u32 asconf_del_pending_cid;
+ int src_out_of_asoc_ok;
/* SCTP AUTH: list of the endpoint shared keys. These
* keys are provided out of band by the user applicaton
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index e73ebda..75c96b1 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -91,6 +91,7 @@ typedef __s32 sctp_assoc_t;
#define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */
#define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */
#define SCTP_GET_ASSOC_NUMBER 28 /* Read only */
+#define SCTP_AUTO_ASCONF 29
/* Internal Socket Options. Some of the sctp library functions are
* implemented using these socket options.
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 6b04287..082f1f0 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -280,6 +280,10 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
if (sctp_addip_noauth)
asoc->peer.asconf_capable = 1;
+ asoc->asconf_addr_del_pending = NULL;
+ asoc->asconf_del_pending_cid = 0;
+ asoc->src_out_of_asoc_ok = 0;
+ INIT_LIST_HEAD(&asoc->asoc_laddr_list);
/* Create an input queue. */
sctp_inq_init(&asoc->base.inqueue);
sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv);
@@ -446,6 +450,18 @@ void sctp_association_free(struct sctp_association *asoc)
/* Free any cached ASCONF_ACK chunk. */
sctp_assoc_free_asconf_acks(asoc);
+ /* Free pending address space being deleted */
+ if (asoc->asconf_addr_del_pending != NULL)
+ kfree(asoc->asconf_addr_del_pending);
+ if (!list_empty(&asoc->asoc_laddr_list)) {
+ struct sctp_sockaddr_entry *laddr, *tmp;
+ list_for_each_entry_safe(laddr, tmp, &asoc->asoc_laddr_list, \
+ list) {
+ list_del(&laddr->list);
+ kfree(laddr);
+ }
+ }
+
/* Free any cached ASCONF chunk. */
if (asoc->addip_last_asconf)
sctp_chunk_free(asoc->addip_last_asconf);
@@ -620,6 +636,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
if (!mod_timer(&active->T3_rtx_timer,
jiffies + active->rto))
sctp_transport_hold(active);
+ active->flight_size += peer->flight_size;
}
asoc->peer.transport_count--;
@@ -1277,7 +1294,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
*/
void sctp_assoc_update_retran_path(struct sctp_association *asoc)
{
- struct sctp_transport *t, *next;
+ struct sctp_transport *t, *next, *unconfirmed;
struct list_head *head = &asoc->peer.transport_addr_list;
struct list_head *pos;
@@ -1287,7 +1304,7 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
/* Find the next transport in a round-robin fashion. */
t = asoc->peer.retran_path;
pos = &t->transports;
- next = NULL;
+ next = unconfirmed = NULL;
while (1) {
/* Skip the head. */
@@ -1318,11 +1335,15 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
*/
if (t->state != SCTP_UNCONFIRMED && !next)
next = t;
+ else if (t->state == SCTP_UNCONFIRMED)
+ unconfirmed = t;
}
}
if (t)
asoc->peer.retran_path = t;
+ else if (unconfirmed)
+ asoc->peer.retran_path = t = unconfirmed;
SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
" %p addr: ",
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index faf71d1..426715f 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -536,6 +536,23 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
return 0;
}
+int sctp_is_ep_boundall(struct sock *sk)
+{
+ struct sctp_bind_addr *bp;
+ struct sctp_sockaddr_entry *addr;
+
+ bp = &sctp_sk(sk)->ep->base.bind_addr;
+ if (sctp_list_single_entry(&bp->address_list)) {
+ addr = list_entry(bp->address_list.next,
+ struct sctp_sockaddr_entry, list);
+ if (sctp_is_any(sk, &addr->a))
+ return 1;
+ else
+ return 0;
+ }
+ return 1;
+}
+
/********************************************************************
* 3rd Level Abstractions
********************************************************************/
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 865ce7b..471facd 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -105,6 +105,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
addr->valid = 1;
spin_lock_bh(&sctp_local_addr_lock);
list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
+ sctp_addr_wq_mgmt(&addr->a, SCTP_NEWADDR);
spin_unlock_bh(&sctp_local_addr_lock);
}
break;
@@ -115,6 +116,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
if (addr->a.sa.sa_family == AF_INET6 &&
ipv6_addr_equal(&addr->a.v6.sin6_addr,
&ifa->addr)) {
+ sctp_addr_wq_mgmt(&addr->a, SCTP_DELADDR);
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
@@ -332,8 +334,26 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
matchlen = bmatchlen;
}
}
+ if (laddr->state == SCTP_ADDR_NEW && asoc->src_out_of_asoc_ok) {
+ bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
+ if (!baddr || (matchlen < bmatchlen)) {
+ baddr = &laddr->a;
+ matchlen = bmatchlen;
+ }
+ }
+ }
+ if (baddr == NULL) {
+ /* We don't have a valid src addr in "endpoint-wide".
+ * Looking up in assoc-locally valid address list.
+ */
+ list_for_each_entry(laddr, &asoc->asoc_laddr_list, list) {
+ bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
+ if (!baddr || (matchlen < bmatchlen)) {
+ baddr = &laddr->a;
+ matchlen = bmatchlen;
+ }
+ }
}
-
if (baddr) {
memcpy(saddr, baddr, sizeof(union sctp_addr));
SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 26dc005..033ea20 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -344,7 +344,14 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
break;
}
} else {
- list_add_tail(&chunk->list, &q->control_chunk_list);
+ /* We add the ASCONF for the only one newly added address at
+ * the front of the queue
+ */
+ if (q->asoc->src_out_of_asoc_ok && \
+ chunk->chunk_hdr->type == SCTP_CID_ASCONF)
+ list_add(&chunk->list, &q->control_chunk_list);
+ else
+ list_add_tail(&chunk->list, &q->control_chunk_list);
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
}
@@ -850,6 +857,24 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
case SCTP_CID_SHUTDOWN:
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ASCONF:
+ /* RFC 5061, 5.3
+ * F1) This means that until such time as the ASCONF
+ * containing the add is acknowledged, the sender MUST
+ * NOT use the new IP address as a source for ANY SCTP
+ * packet except on carrying an ASCONF Chunk.
+ */
+ if (asoc->src_out_of_asoc_ok) {
+ SCTP_DEBUG_PRINTK("outq_flush: out_of_asoc_ok, transmit chunk type %d\n",
+ chunk->chunk_hdr->type);
+ packet = &transport->packet;
+ sctp_packet_config(packet, vtag,
+ asoc->peer.ecn_capable);
+ sctp_packet_append_chunk(packet, chunk);
+ error = sctp_packet_transmit(packet);
+ if (error < 0)
+ return error;
+ goto sctp_flush_out;
+ }
case SCTP_CID_FWD_TSN:
status = sctp_packet_transmit_chunk(packet, chunk,
one_packet);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 152976e..2859c16 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -510,12 +510,20 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
- if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
+ if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC &&
+ asoc->src_out_of_asoc_ok == 0))
continue;
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
goto out_unlock;
}
rcu_read_unlock();
+ /* We don't have a valid src addr in "endpoint-wide".
+ * Looking up in assoc-locally valid address list.
+ */
+ list_for_each_entry(laddr, &asoc->asoc_laddr_list, list) {
+ if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
+ goto out_unlock;
+ }
/* None of the bound addresses match the source address of the
* dst. So release it.
@@ -636,6 +644,182 @@ static void sctp_v4_ecn_capable(struct sock *sk)
INET_ECN_xmit(sk);
}
+void sctp_addr_wq_timeout_handler(unsigned long arg)
+{
+ struct sctp_addr_wait *addrw = NULL;
+ union sctp_addr *addr = NULL;
+ struct sctp_ep_common *epb = NULL;
+ struct sctp_endpoint *ep = NULL;
+ int cnt = 0;
+
+ spin_lock_bh(&sctp_addr_wq_lock);
+retry_wq:
+ if (list_empty(&sctp_addr_waitq)) {
+ SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: nothing in addr waitq\n");
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ }
+ addrw = list_first_entry(&sctp_addr_waitq, struct sctp_addr_wait, list);
+ if (addrw->cmd != SCTP_NEWADDR && addrw->cmd != SCTP_DELADDR) {
+ SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: cmd is neither NEWADDR nor DELADDR\n");
+ list_del(&addrw->list);
+ kfree(addrw);
+ goto retry_wq;
+ }
+
+ addr = &addrw->a;
+ SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ",
+ " for cmd %d at entry %p\n", &sctp_addr_waitq, addr, addrw->cmd,
+ addrw);
+
+ /* Now we send an ASCONF for each association */
+ /* Note. we currently don't handle link local IPv6 addressees */
+ if (addr->sa.sa_family == AF_INET6) {
+ struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr;
+
+ if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
+ SCTP_DEBUG_PRINTK("sctp_timo_handler: link local, hence don't tell eps\n");
+ list_del(&addrw->list);
+ kfree(addrw);
+ goto retry_wq;
+ }
+ if (ipv6_chk_addr(&init_net, in6, NULL, 0) == 0 &&
+ addrw->cmd == SCTP_NEWADDR) {
+ unsigned long timeo_val;
+
+ SCTP_DEBUG_PRINTK("sctp_timo_handler: this is on DAD, trying %d sec later\n",
+ SCTP_ADDRESS_TICK_DELAY);
+ timeo_val = jiffies;
+ timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
+ (void)mod_timer(&sctp_addr_wq_timer, timeo_val);
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ }
+ }
+ list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
+ if (epb == NULL) {
+ SCTP_DEBUG_PRINTK("addrwq_timo_handler: no epb\n");
+ continue;
+ }
+ if (!sctp_is_ep_boundall(epb->sk))
+ /* ignore bound-specific endpoints */
+ continue;
+ ep = sctp_ep(epb);
+ sctp_bh_lock_sock(epb->sk);
+ if (sctp_asconf_mgmt(ep, epb->sk) < 0) {
+ SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: sctp_asconf_mgmt failed\n");
+ sctp_bh_unlock_sock(epb->sk);
+ continue;
+ }
+ sctp_bh_unlock_sock(epb->sk);
+ ++cnt;
+ }
+
+ list_del(&addrw->list);
+ kfree(addrw);
+
+ if (list_empty(&sctp_addr_waitq)) {
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ } else
+ goto retry_wq;
+
+ spin_unlock_bh(&sctp_addr_wq_lock);
+}
+
+void sctp_addr_wq_mgmt(union sctp_addr *reqaddr, int cmd)
+{
+ struct sctp_addr_wait *addrw = NULL;
+ struct sctp_addr_wait *addrw_new = NULL;
+ unsigned long timeo_val;
+ union sctp_addr *tmpaddr;
+
+ /* first, we check if an opposite message already exist in the queue.
+ * If we found such message, it is removed.
+ * This operation is a bit stupid, but the DHCP client attaches the
+ * new address after a couple of addition and deletion of that address
+ */
+
+ if (reqaddr == NULL) {
+ SCTP_DEBUG_PRINTK("sctp_addr_wq_mgmt: no address message?\n");
+ return;
+ }
+
+ spin_lock_bh(&sctp_addr_wq_lock);
+ /* Offsets existing events in addr_wq */
+ list_for_each_entry(addrw, &sctp_addr_waitq, list) {
+ if (addrw->a.sa.sa_family != reqaddr->sa.sa_family)
+ continue;
+ if (reqaddr->sa.sa_family == AF_INET) {
+ if (reqaddr->v4.sin_addr.s_addr ==
+ addrw->a.v4.sin_addr.s_addr) {
+ if (cmd != addrw->cmd) {
+ tmpaddr = &addrw->a;
+ SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ",
+ " in waitq %p\n", addrw->cmd,
+ tmpaddr, &sctp_addr_waitq);
+ list_del(&addrw->list);
+ kfree(addrw);
+ /* nothing to do anymore */
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ }
+ }
+ } else if (reqaddr->sa.sa_family == AF_INET6) {
+ if (ipv6_addr_equal(&reqaddr->v6.sin6_addr,
+ &addrw->a.v6.sin6_addr)) {
+ if (cmd != addrw->cmd) {
+ tmpaddr = &addrw->a;
+ SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt: offsets existing entry for %d ",
+ " in waitq %p\n", addrw->cmd,
+ tmpaddr, &sctp_addr_waitq);
+ list_del(&addrw->list);
+ kfree(addrw);
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ }
+ }
+ }
+ }
+
+ /* OK, we have to add the new address to the wait queue */
+ addrw_new = kzalloc(sizeof(struct sctp_addr_wait), GFP_ATOMIC);
+ if (addrw_new == NULL) {
+ SCTP_DEBUG_PRINTK("sctp_addr_weitq_mgmt no memory? return\n");
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ }
+ if (reqaddr->sa.sa_family == AF_INET) {
+ addrw_new->a.v4.sin_family = AF_INET;
+ addrw_new->a.v4.sin_addr.s_addr = reqaddr->v4.sin_addr.s_addr;
+ } else if (reqaddr->sa.sa_family == AF_INET6) {
+ addrw_new->a.v6.sin6_family = AF_INET6;
+ ipv6_addr_copy(&addrw_new->a.v6.sin6_addr,
+ &reqaddr->v6.sin6_addr);
+ } else {
+ SCTP_DEBUG_PRINTK("sctp_addr_waitq_mgmt: Unknown family of request addr, return\n");
+ kfree(addrw_new);
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ }
+ addrw_new->cmd = cmd;
+ list_add_tail(&addrw_new->list, &sctp_addr_waitq);
+ tmpaddr = &addrw_new->a;
+ SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ",
+ " in waitq %p, start a timer\n",
+ addrw_new->cmd, tmpaddr, &sctp_addr_waitq);
+
+ if (timer_pending(&sctp_addr_wq_timer)) {
+ SCTP_DEBUG_PRINTK("sctp_addr_wq_mgmt: addr_wq timer is already running\n");
+ spin_unlock_bh(&sctp_addr_wq_lock);
+ return;
+ }
+ timeo_val = jiffies;
+ timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
+ (void)mod_timer(&sctp_addr_wq_timer, timeo_val);
+ spin_unlock_bh(&sctp_addr_wq_lock);
+}
+
/* Event handler for inet address addition/deletion events.
* The sctp_local_addr_list needs to be protocted by a spin lock since
* multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -663,6 +847,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
addr->valid = 1;
spin_lock_bh(&sctp_local_addr_lock);
list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
+ sctp_addr_wq_mgmt(&addr->a, SCTP_NEWADDR);
spin_unlock_bh(&sctp_local_addr_lock);
}
break;
@@ -673,6 +858,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
if (addr->a.sa.sa_family == AF_INET &&
addr->a.v4.sin_addr.s_addr ==
ifa->ifa_local) {
+ sctp_addr_wq_mgmt(&addr->a, SCTP_DELADDR);
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
@@ -1277,6 +1463,12 @@ SCTP_STATIC __init int sctp_init(void)
/* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_local_addr_list);
+ INIT_LIST_HEAD(&sctp_addr_waitq);
+ INIT_LIST_HEAD(&sctp_auto_asconf_eplist);
+ spin_lock_init(&sctp_addr_wq_lock);
+ sctp_addr_wq_timer.expires = 0;
+ setup_timer(&sctp_addr_wq_timer, sctp_addr_wq_timeout_handler,
+ (unsigned long)NULL);
spin_lock_init(&sctp_local_addr_lock);
sctp_get_local_addr_list();
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index de98665..b5ca24a 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2651,6 +2651,61 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
return retval;
}
+void
+sctp_path_check_and_react(struct sctp_association *asoc, struct sockaddr *sa)
+{
+ struct sctp_transport *trans;
+ int addrnum, family;
+ struct sctp_sockaddr_entry *saddr;
+ struct sctp_bind_addr *bp;
+ union sctp_addr *tmpaddr;
+
+ family = sa->sa_family;
+ bp = &asoc->base.bind_addr;
+ addrnum = 0;
+ /* count up the number of local addresses in the same family */
+ list_for_each_entry(saddr, &bp->address_list, list) {
+ if (saddr->a.sa.sa_family == family) {
+ tmpaddr = &saddr->a;
+ if (family == AF_INET6 &&
+ ipv6_addr_type(&tmpaddr->v6.sin6_addr) &
+ IPV6_ADDR_LINKLOCAL) {
+ continue;
+ }
+ addrnum++;
+ }
+ }
+ if (addrnum == 1) {
+ union sctp_addr *tmpaddr;
+ tmpaddr = (union sctp_addr *)sa;
+ SCTP_DEBUG_PRINTK_IPADDR("pcheck_react: only 1 local addr in asoc %p ",
+ " family %d\n", asoc, tmpaddr, family);
+ list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+ transports) {
+ /* reset path information and release refcount to the
+ * dst_entry based on the src change */
+ sctp_transport_hold(trans);
+ trans->cwnd = min(4*asoc->pathmtu,
+ max_t(__u32, 2*asoc->pathmtu, 4380));
+ trans->ssthresh = asoc->peer.i.a_rwnd;
+ trans->rtt = 0;
+ trans->srtt = 0;
+ trans->rttvar = 0;
+ trans->rto = asoc->rto_initial;
+ dst_release(trans->dst);
+ trans->dst = NULL;
+ memset(&trans->saddr, 0, sizeof(union sctp_addr));
+ sctp_transport_route(trans, NULL,
+ sctp_sk(asoc->base.sk));
+ SCTP_DEBUG_PRINTK_IPADDR("we freed dst_entry (asoc: %p dst: ",
+ " trans: %p)\n", asoc, (&trans->ipaddr), trans);
+ trans->rto_pending = 1;
+ sctp_transport_put(trans);
+ }
+ }
+ return;
+}
+
/*
* ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF)
* 0 1 2 3
@@ -2744,11 +2799,29 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
int addr_param_len = 0;
int totallen = 0;
int i;
+ sctp_addip_param_t del_param; /* 8 Bytes (Type 0xC002, Len and CrrID) */
+ sctp_addip_param_t spr_param;
+ struct sctp_af *del_af;
+ struct sctp_af *spr_af;
+ int del_addr_param_len = 0;
+ int spr_addr_param_len = 0;
+ int del_paramlen = sizeof(sctp_addip_param_t);
+ int spr_paramlen = sizeof(sctp_addip_param_t);
+ union sctp_addr_param del_addr_param; /* (v4) 8 Bytes, (v6) 20 Bytes */
+ union sctp_addr_param spr_addr_param;
+ int v4 = 0;
+ int v6 = 0;
/* Get total length of all the address parameters. */
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
+ if (addr != NULL) {
+ if (addr->sa.sa_family == AF_INET)
+ v4 = 1;
+ else if (addr->sa.sa_family == AF_INET6)
+ v6 = 1;
+ }
af = sctp_get_af_specific(addr->v4.sin_family);
addr_param_len = af->to_addr_param(addr, &addr_param);
@@ -2757,6 +2830,40 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
addr_buf += af->sockaddr_len;
}
+ /* Add the length of a pending address being deleted */
+ if (flags == SCTP_PARAM_ADD_IP && asoc->asconf_addr_del_pending) {
+ if ((asoc->asconf_addr_del_pending->sa.sa_family == AF_INET
+ && v4) ||
+ (asoc->asconf_addr_del_pending->sa.sa_family == AF_INET6
+ && v6)) {
+ del_af = sctp_get_af_specific(
+ asoc->asconf_addr_del_pending->sa.sa_family);
+ del_addr_param_len = del_af->to_addr_param(
+ asoc->asconf_addr_del_pending, &del_addr_param);
+ totallen += del_paramlen;
+ totallen += del_addr_param_len;
+ SCTP_DEBUG_PRINTK("mkasconf_update_ip: now we picked del_pending addr, totallen for all addresses is %d\n",
+ totallen);
+ /* for Set Primary (equal size as del parameters */
+ totallen += del_paramlen;
+ totallen += del_addr_param_len;
+ }
+ if (v4) {
+ if (totallen != SCTP_ASCONF_V4_PARAM_LEN * 2 &&
+ totallen != SCTP_ASCONF_V4_PARAM_LEN * 3) {
+ SCTP_DEBUG_PRINTK("mkasconf_update_ip: incorrect total length of ASCONF parameters, del + add MUST be 32 bytes, but %d bytes\n", totallen);
+ return NULL;
+ }
+ } else if (v6) {
+ if (totallen != SCTP_ASCONF_V6_PARAM_LEN * 2 &&
+ totallen != SCTP_ASCONF_V6_PARAM_LEN * 3) {
+ SCTP_DEBUG_PRINTK("mkasconf_update_ip: incorrect total length of ASCONF parameters, del + add MUST be 56 bytes, but %d bytes\n", totallen);
+ return NULL;
+ }
+ }
+ }
+ SCTP_DEBUG_PRINTK("mkasconf_update_ip: call mkasconf() for %d bytes\n",
+ totallen);
/* Create an asconf chunk with the required length. */
retval = sctp_make_asconf(asoc, laddr, totallen);
@@ -2778,6 +2885,32 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
addr_buf += af->sockaddr_len;
}
+ if (flags == SCTP_PARAM_ADD_IP && asoc->asconf_addr_del_pending) {
+ addr = asoc->asconf_addr_del_pending;
+ del_af = sctp_get_af_specific(addr->v4.sin_family);
+ del_addr_param_len = del_af->to_addr_param(addr,
+ &del_addr_param);
+ del_param.param_hdr.type = SCTP_PARAM_DEL_IP;
+ del_param.param_hdr.length = htons(del_paramlen +
+ del_addr_param_len);
+ del_param.crr_id = i;
+ asoc->asconf_del_pending_cid = i;
+
+ sctp_addto_chunk(retval, del_paramlen, &del_param);
+ sctp_addto_chunk(retval, del_addr_param_len, &del_addr_param);
+ /* For SET_PRIMARY */
+ addr_buf = addrs;
+ addr = (union sctp_addr *)addr_buf;
+ spr_af = sctp_get_af_specific(addr->v4.sin_family);
+ spr_addr_param_len = spr_af->to_addr_param(addr,
+ &spr_addr_param);
+ spr_param.param_hdr.type = SCTP_PARAM_SET_PRIMARY;
+ spr_param.param_hdr.length = htons(spr_paramlen +
+ spr_addr_param_len);
+ spr_param.crr_id = (i+1);
+ sctp_addto_chunk(retval, spr_paramlen, &spr_param);
+ sctp_addto_chunk(retval, spr_addr_param_len, &spr_addr_param);
+ }
return retval;
}
@@ -2990,7 +3123,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
* an Error Cause TLV set to the new error code 'Request to
* Delete Source IP Address'
*/
- if (sctp_cmp_addr_exact(sctp_source(asconf), &addr))
+ if (sctp_cmp_addr_exact(&asconf->source, &addr))
return SCTP_ERROR_DEL_SRC_IP;
/* Section 4.2.2
@@ -3171,7 +3304,6 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
struct sctp_bind_addr *bp = &asoc->base.bind_addr;
union sctp_addr_param *addr_param;
struct sctp_transport *transport;
- struct sctp_sockaddr_entry *saddr;
addr_param = (union sctp_addr_param *)
((void *)asconf_param + sizeof(sctp_addip_param_t));
@@ -3186,9 +3318,16 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
* held, so the list can not change.
*/
local_bh_disable();
- list_for_each_entry(saddr, &bp->address_list, list) {
- if (sctp_cmp_addr_exact(&saddr->a, &addr))
- saddr->state = SCTP_ADDR_SRC;
+ /* Until this ASCONF is acked on all associations, we cannot
+ * consider this address as ADDR_SRC
+ */
+ asoc->src_out_of_asoc_ok = 0;
+ sctp_add_addr_to_laddr(&addr.sa, asoc);
+ list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+ transports) {
+ dst_release(transport->dst);
+ sctp_transport_route(transport, NULL,
+ sctp_sk(asoc->base.sk));
}
local_bh_enable();
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
@@ -3203,6 +3342,25 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
case SCTP_PARAM_DEL_IP:
local_bh_disable();
sctp_del_bind_addr(bp, &addr);
+ if (asoc->asconf_addr_del_pending != NULL) {
+ if ((addr.sa.sa_family == AF_INET) &&
+ (asoc->asconf_addr_del_pending->sa.sa_family ==
+ AF_INET)) {
+ if (asoc->asconf_addr_del_pending->v4.sin_addr.s_addr == addr.v4.sin_addr.s_addr) {
+ kfree(asoc->asconf_addr_del_pending);
+ asoc->asconf_del_pending_cid = 0;
+ asoc->asconf_addr_del_pending = NULL;
+ }
+ } else if ((addr.sa.sa_family == AF_INET6) &&
+ (asoc->asconf_addr_del_pending->sa.sa_family ==
+ AF_INET6)) {
+ if (ipv6_addr_equal(&asoc->asconf_addr_del_pending->v6.sin6_addr, &addr.v6.sin6_addr)) {
+ kfree(asoc->asconf_addr_del_pending);
+ asoc->asconf_del_pending_cid = 0;
+ asoc->asconf_addr_del_pending = NULL;
+ }
+ }
+ }
local_bh_enable();
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
transports) {
@@ -3293,6 +3451,8 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
int no_err = 1;
int retval = 0;
__be16 err_code = SCTP_ERROR_NO_ERROR;
+ sctp_addip_param_t *first_asconf_param = NULL;
+ int first_asconf_paramlen;
/* Skip the chunkhdr and addiphdr from the last asconf sent and store
* a pointer to address parameter.
@@ -3307,6 +3467,8 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
length = ntohs(addr_param->v4.param_hdr.length);
asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
asconf_len -= length;
+ first_asconf_param = asconf_param;
+ first_asconf_paramlen = ntohs(first_asconf_param->param_hdr.length);
/* ADDIP 4.1
* A8) If there is no response(s) to specific TLV parameter(s), and no
@@ -3361,6 +3523,35 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
asconf_len -= length;
}
+ /* When the source address obviously changes to newly added one, we
+ reset the cwnd to re-probe the path condition
+ */
+ if (no_err && first_asconf_param->param_hdr.type == SCTP_PARAM_ADD_IP) {
+ if (first_asconf_paramlen == SCTP_ASCONF_V4_PARAM_LEN) {
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr.s_addr, first_asconf_param + 1,
+ sizeof(struct in_addr));
+ sctp_path_check_and_react(asoc,
+ (struct sockaddr *)&sin);
+
+ } else if (first_asconf_paramlen == SCTP_ASCONF_V6_PARAM_LEN) {
+ struct sockaddr_in6 sin6;
+
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_family = AF_INET6;
+ memcpy(&sin6.sin6_addr, first_asconf_param + 1,
+ sizeof(struct in6_addr));
+ sctp_path_check_and_react(asoc,
+ (struct sockaddr *)&sin6);
+ } else {
+ SCTP_DEBUG_PRINTK("funny asconf_paramlen? (%d)\n",
+ first_asconf_paramlen);
+ }
+ }
+
/* Free the cached last sent asconf chunk. */
list_del_init(&asconf->transmitted_list);
sctp_chunk_free(asconf);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 3951a10..9bc5e98 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -527,6 +527,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
struct list_head *p;
int i;
int retval = 0;
+ struct sctp_transport *trans = NULL;
if (!sctp_addip_enable)
return retval;
@@ -583,13 +584,10 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
goto out;
}
- retval = sctp_send_asconf(asoc, chunk);
- if (retval)
- goto out;
-
/* Add the new addresses to the bind address list with
* use_as_src set to 0.
*/
+ SCTP_DEBUG_PRINTK("snd_asconf_addip: next, add_bind_addr with ADDR_NEW flag\n");
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
@@ -599,6 +597,28 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
SCTP_ADDR_NEW, GFP_ATOMIC);
addr_buf += af->sockaddr_len;
}
+ list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+ transports) {
+ if (asoc->asconf_addr_del_pending != NULL)
+ /* This ADDIP ASCONF piggybacks DELIP for the
+ * last address, so need to select src addr
+ * from the out_of_asoc addrs
+ */
+ asoc->src_out_of_asoc_ok = 1;
+ /* Clear the source and route cache in the path */
+ memset(&trans->saddr, 0, sizeof(union sctp_addr));
+ dst_release(trans->dst);
+ trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
+ 2*asoc->pathmtu, 4380));
+ trans->ssthresh = asoc->peer.i.a_rwnd;
+ trans->rto = asoc->rto_initial;
+ trans->rtt = 0;
+ trans->srtt = 0;
+ trans->rttvar = 0;
+ sctp_transport_route(trans, NULL,
+ sctp_sk(asoc->base.sk));
+ }
+ retval = sctp_send_asconf(asoc, chunk);
}
out:
@@ -711,7 +731,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
struct sctp_sockaddr_entry *saddr;
int i;
int retval = 0;
+ int stored = 0;
+ chunk = NULL;
if (!sctp_addip_enable)
return retval;
@@ -762,8 +784,42 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
bp = &asoc->base.bind_addr;
laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
addrcnt, sp);
- if (!laddr)
- continue;
+ if ((laddr == NULL) && (addrcnt == 1)) {
+ union sctp_addr *sa_addr = NULL;
+
+ if (asoc->asconf_addr_del_pending == NULL) {
+ asoc->asconf_addr_del_pending =
+ kmalloc(sizeof(union sctp_addr),
+ GFP_ATOMIC);
+ memset(asoc->asconf_addr_del_pending, 0,
+ sizeof(union sctp_addr));
+ if (addrs->sa_family == AF_INET) {
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)addrs;
+ asoc->asconf_addr_del_pending->v4.sin_family = AF_INET;
+ memcpy(&asoc->asconf_addr_del_pending->v4.sin_addr, &sin->sin_addr, sizeof(struct in_addr));
+ } else if (addrs->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)addrs;
+ asoc->asconf_addr_del_pending->v6.sin6_family = AF_INET6;
+ memcpy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
+ }
+ sa_addr = (union sctp_addr *)addrs;
+ SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ",
+ " at %p\n", asoc, sa_addr,
+ asoc->asconf_addr_del_pending);
+ stored = 1;
+ goto skip_mkasconf;
+ } else {
+ SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: asoc %p, deleting last address ",
+ " is already stored at %p\n", asoc,
+ asoc->asconf_addr_del_pending,
+ asoc->asconf_addr_del_pending);
+ continue;
+ }
+ }
/* We do not need RCU protection throughout this loop
* because this is done under a socket lock from the
@@ -776,6 +832,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
goto out;
}
+skip_mkasconf:
/* Reset use_as_src flag for the addresses in the bind address
* list that are to be deleted.
*/
@@ -797,16 +854,205 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
transports) {
dst_release(transport->dst);
+ /* Clear source address cache */
+ memset(&transport->saddr, 0, sizeof(union sctp_addr));
sctp_transport_route(transport, NULL,
sctp_sk(asoc->base.sk));
}
+ if (stored) {
+ /* We don't need to transmit ASCONF */
+ continue;
+ }
retval = sctp_send_asconf(asoc, chunk);
}
out:
return retval;
}
+/* Add a new address to the list contains available addresses only in the
+ * association. If the new address is also available on the other associations
+ * on the endpoint, it is marked as SCTP_ADDR_SRC in the bind address list on
+ * the endpoint. This situation is possible when some of associations receive
+ * ASCONF-ACK for ADD_IP at the endpoint
+ */
+void
+sctp_add_addr_to_laddr(struct sockaddr *sa, struct sctp_association *asoc)
+{
+ struct sctp_endpoint *ep = asoc->ep;
+ struct sctp_association *tmp = NULL;
+ struct sctp_bind_addr *bp;
+ struct sctp_sockaddr_entry *addr;
+ struct sockaddr_in *sin = NULL;
+ struct sockaddr_in6 *sin6 = NULL;
+ int local;
+ int found;
+
+ union sctp_addr *tmpaddr = NULL;
+ tmpaddr = (union sctp_addr *)sa;
+ SCTP_DEBUG_PRINTK_IPADDR("add_addr_to_laddr: asoc: %p ", " ep: %p",
+ asoc, tmpaddr, ep);
+ if (sa->sa_family == AF_INET)
+ sin = (struct sockaddr_in *)sa;
+ else if (sa->sa_family == AF_INET6)
+ sin6 = (struct sockaddr_in6 *)sa;
+
+ /* Check if this address is locally available in the other asocs */
+ local = 0;
+ list_for_each_entry(tmp, &ep->asocs, asocs) {
+ if (tmp == asoc)
+ continue;
+ found = 0;
+ list_for_each_entry(addr, &tmp->asoc_laddr_list, list) {
+ tmpaddr = &addr->a;
+ if (sa->sa_family != addr->a.sa.sa_family)
+ continue;
+ if (sa->sa_family == AF_INET) {
+ if (sin->sin_addr.s_addr ==
+ addr->a.v4.sin_addr.s_addr)
+ found = 1;
+ } else if (sa->sa_family == AF_INET6) {
+ if (ipv6_addr_equal(&sin6->sin6_addr,
+ &addr->a.v6.sin6_addr))
+ found = 1;
+
+ }
+ }
+ if (!found) {
+ SCTP_DEBUG_PRINTK("add_addr_to_laddr: not found in asoc %p\n", tmp);
+ local = 1;
+ break;
+ }
+ }
+ addr = NULL;
+
+ if (local) {
+ /* this address is not available in some of the other
+ * associations. So add as locally-available in this
+ * asocciation
+ */
+ addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
+ if (addr == NULL) {
+ SCTP_DEBUG_PRINTK("add_addr_to_laddr: failed to allocate memory for this address\n");
+ return;
+ }
+ memset(addr, 0, sizeof(struct sctp_sockaddr_entry));
+ if (sa->sa_family == AF_INET) {
+ addr->a.sa.sa_family = AF_INET;
+ addr->a.v4.sin_port = sin->sin_port;
+ addr->a.v4.sin_addr.s_addr = sin->sin_addr.s_addr;
+ } else if (sa->sa_family == AF_INET6) {
+ addr->a.sa.sa_family = AF_INET6;
+ addr->a.v6.sin6_port = sin6->sin6_port;
+ memcpy(&addr->a.v6.sin6_addr, &sin6->sin6_addr,
+ sizeof(struct in6_addr));
+ }
+ list_add_tail(&addr->list, &asoc->asoc_laddr_list);
+ SCTP_DEBUG_PRINTK("add_addr_to_laddr: now we added this address to the local list on asoc %p\n", asoc);
+ } else {
+ /* this address is also available in all other asocs. So set
+ * it as ADDR_SRC in the bind-addr list in the endpoint, then
+ * remove from the asoc_laddr_list on the associations.
+ */
+ SCTP_DEBUG_PRINTK("add_addr_to_laddr: this address is available in all other asocs\n");
+ bp = &asoc->base.bind_addr;
+
+ /* change state of the new address in the bind list */
+ list_for_each_entry(addr, &bp->address_list, list) {
+ if (addr->state != SCTP_ADDR_NEW)
+ continue;
+ if (addr->a.sa.sa_family != sa->sa_family)
+ continue;
+ if (addr->a.sa.sa_family == AF_INET) {
+ if (sin->sin_port != addr->a.v4.sin_port)
+ continue;
+ if (sin->sin_addr.s_addr !=
+ addr->a.v4.sin_addr.s_addr)
+ continue;
+ } else if (addr->a.sa.sa_family == AF_INET6) {
+ if (sin6->sin6_port != addr->a.v6.sin6_port)
+ continue;
+ if (!ipv6_addr_equal(&sin6->sin6_addr,
+ &addr->a.v6.sin6_addr))
+ continue;
+ }
+ SCTP_DEBUG_PRINTK("add_addr_to_laddr: found the entry for this address with ADDR_NEW flag, set to ADDR_SRC\n");
+ addr->state = SCTP_ADDR_SRC;
+ }
+
+ /* remove the entry of this address from the asoc-local list */
+ list_for_each_entry(tmp, &ep->asocs, asocs) {
+ if (tmp == asoc)
+ continue;
+ addr = NULL;
+ list_for_each_entry(addr, &tmp->asoc_laddr_list, list) {
+ if (sa->sa_family != addr->a.sa.sa_family)
+ continue;
+ if (sa->sa_family == AF_INET) {
+ if (sin->sin_addr.s_addr !=
+ addr->a.v4.sin_addr.s_addr)
+ continue;
+ } else if (sa->sa_family == AF_INET6) {
+ if (!ipv6_addr_equal(&sin6->sin6_addr,
+ &addr->a.v6.sin6_addr))
+ continue;
+ }
+ break;
+ }
+ if (addr == NULL) {
+ SCTP_DEBUG_PRINTK("add_addr_to_laddr: Huh, asoc %p doesn't have the entry for this address?\n", asoc);
+ continue;
+ }
+ list_del(&addr->list);
+ kfree(addr);
+ }
+ }
+}
+
+/* set addr events to assocs in the endpoint. ep and addr_wq must be locked */
+int
+sctp_asconf_mgmt(struct sctp_endpoint *ep, struct sock *sk)
+{
+ struct sctp_addr_wait *addrw = NULL;
+ union sctp_addr *addr = NULL;
+ int cmd;
+ int error = 0;
+
+ if (ep == NULL || sk == NULL)
+ return -EINVAL;
+ if (list_empty(&sctp_addr_waitq)) {
+ SCTP_DEBUG_PRINTK("asconf_mgmt: nothing in the wq\n");
+ return -EINVAL;
+ }
+ addrw = list_first_entry(&sctp_addr_waitq, struct sctp_addr_wait, list);
+ if (addrw->cmd != SCTP_NEWADDR && addrw->cmd != SCTP_DELADDR)
+ return -EINVAL;
+ addr = &addrw->a;
+ cmd = addrw->cmd;
+
+ if (addr->sa.sa_family == AF_INET)
+ addr->v4.sin_port = htons(ep->base.bind_addr.port);
+ else if (addr->sa.sa_family == AF_INET6)
+ addr->v6.sin6_port = htons(ep->base.bind_addr.port);
+
+ SCTP_DEBUG_PRINTK("sctp_asconf_mgmt sk:%p ep:%p\n", sk, ep);
+ if (cmd == SCTP_NEWADDR) {
+ error = sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1);
+ if (error) {
+ SCTP_DEBUG_PRINTK("asconf_mgmt: send_asconf_add_ip returns %d\n", error);
+ return error;
+ }
+ } else if (cmd == SCTP_DELADDR) {
+ error = sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1);
+ if (error) {
+ SCTP_DEBUG_PRINTK("asconf_mgmt: send_asconf_del_ip returns %d\n", error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
/* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
*
* API 8.1
@@ -3341,6 +3587,44 @@ static int sctp_setsockopt_del_key(struct sock *sk,
}
+/*
+ * 8.1.23 SCTP_AUTO_ASCONF
+ *
+ * This option will enable or disable the use of the automatic generation of
+ * ASCONF chunks to add and delete addresses to an existing association. Note
+ * that this option has two caveats namely: a) it only affects sockets that
+ * are bound to all addresses available to the SCTP stack, and b) the system
+ * administrator may have an overriding control that turns the ASCONF feature
+ * off no matter what setting the socket option may have.
+ * This option expects an integer boolean flag, where a non-zero value turns on
+ * the option, and a zero value turns off the option.
+ * Note. In this implementation, socket operation overrides default parameter
+ * being set by sysctl as well as FreeBSD implementation
+ */
+static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
+ unsigned int optlen)
+{
+ int val;
+ struct sctp_ep_common *epb;
+
+ if (optlen < sizeof(int))
+ return -EINVAL;
+ if (get_user(val, (int __user *)optval))
+ return -EFAULT;
+ if (!sctp_is_ep_boundall(sk) && val)
+ return -EINVAL;
+ list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
+ if (epb->sk == sk) {
+ if (val == 0)
+ list_del(&epb->auto_asconf_list);
+ return 0;
+ }
+ }
+ if (val)
+ list_add_tail(&sctp_sk(sk)->ep->base.auto_asconf_list,
+ &sctp_auto_asconf_eplist);
+ return 0;
+}
/* API 6.2 setsockopt(), getsockopt()
*
@@ -3488,6 +3772,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_AUTH_DELETE_KEY:
retval = sctp_setsockopt_del_key(sk, optval, optlen);
break;
+ case SCTP_AUTO_ASCONF:
+ retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
+ break;
default:
retval = -ENOPROTOOPT;
break;
@@ -3770,6 +4057,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
local_bh_disable();
percpu_counter_inc(&sctp_sockets_allocated);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+ if (sctp_auto_asconf_enable)
+ list_add_tail(&ep->base.auto_asconf_list,
+ &sctp_auto_asconf_eplist);
+ SCTP_DEBUG_PRINTK("sctp_init_sk sk:%p ep:%p\n", sk, ep);
local_bh_enable();
return 0;
@@ -3779,11 +4070,18 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
{
struct sctp_endpoint *ep;
+ struct sctp_ep_common *epb;
SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk);
/* Release our hold on the endpoint. */
ep = sctp_sk(sk)->ep;
+ list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
+ if (epb->sk == sk) {
+ list_del(&epb->auto_asconf_list);
+ break;
+ }
+ }
sctp_endpoint_free(ep);
local_bh_disable();
percpu_counter_dec(&sctp_sockets_allocated);
@@ -5283,6 +5581,31 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
return 0;
}
+/*
+ * 8.1.23 SCTP_AUTO_ASCONF
+ * See the corresponding setsockopt entry as description
+ */
+static int sctp_getsockopt_auto_asconf(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ int val = 0;
+ struct sctp_ep_common *epb;
+
+ if (len < sizeof(int))
+ return -EINVAL;
+
+ len = sizeof(int);
+ list_for_each_entry(epb, &sctp_auto_asconf_eplist, auto_asconf_list) {
+ if (epb->sk == sk)
+ val = 1;
+ }
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &val, len))
+ return -EFAULT;
+ return 0;
+}
+
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
@@ -5415,6 +5738,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_GET_ASSOC_NUMBER:
retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
break;
+ case SCTP_AUTO_ASCONF:
+ retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
+ break;
default:
retval = -ENOPROTOOPT;
break;
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 50cb57f..df39789 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -183,6 +183,13 @@ static ctl_table sctp_table[] = {
.proc_handler = proc_dointvec,
},
{
+ .procname = "auto_asconf_enable",
+ .data = &sctp_auto_asconf_enable,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
.procname = "prsctp_enable",
.data = &sctp_prsctp_enable,
.maxlen = sizeof(int),
^ permalink raw reply related
* [PATCH 1/4] xfrm: Move the test on replay window size into the replay check functions
From: Steffen Klassert @ 2011-03-29 5:45 UTC (permalink / raw)
To: David Miller, Herbert Xu; +Cc: netdev
As it is, the replay check is just performed if the replay window of the
legacy implementation is nonzero. So we move the test on a nonzero replay
window inside the replay check functions to be sure we are testing for the
right implementation.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_input.c | 2 +-
net/xfrm/xfrm_replay.c | 17 +++++++++++++++--
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 872065c..e063638 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -173,7 +173,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
goto drop_unlock;
}
- if (x->props.replay_window && x->repl->check(x, skb, seq)) {
+ if (x->repl->check(x, skb, seq)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
goto drop_unlock;
}
diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c
index 2f5be5b..f218385 100644
--- a/net/xfrm/xfrm_replay.c
+++ b/net/xfrm/xfrm_replay.c
@@ -118,6 +118,9 @@ static int xfrm_replay_check(struct xfrm_state *x,
u32 diff;
u32 seq = ntohl(net_seq);
+ if (!x->props.replay_window)
+ return 0;
+
if (unlikely(seq == 0))
goto err;
@@ -193,9 +196,14 @@ static int xfrm_replay_check_bmp(struct xfrm_state *x,
{
unsigned int bitnr, nr;
struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
+ u32 pos;
u32 seq = ntohl(net_seq);
u32 diff = replay_esn->seq - seq;
- u32 pos = (replay_esn->seq - 1) % replay_esn->replay_window;
+
+ if (!replay_esn->replay_window)
+ return 0;
+
+ pos = (replay_esn->seq - 1) % replay_esn->replay_window;
if (unlikely(seq == 0))
goto err;
@@ -373,12 +381,17 @@ static int xfrm_replay_check_esn(struct xfrm_state *x,
unsigned int bitnr, nr;
u32 diff;
struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
+ u32 pos;
u32 seq = ntohl(net_seq);
- u32 pos = (replay_esn->seq - 1) % replay_esn->replay_window;
u32 wsize = replay_esn->replay_window;
u32 top = replay_esn->seq;
u32 bottom = top - wsize + 1;
+ if (!wsize)
+ return 0;
+
+ pos = (replay_esn->seq - 1) % replay_esn->replay_window;
+
if (unlikely(seq == 0 && replay_esn->seq_hi == 0 &&
(replay_esn->seq < replay_esn->replay_window - 1)))
goto err;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 2/4] xfrm: Assign esn pointers when cloning a state
From: Steffen Klassert @ 2011-03-29 5:46 UTC (permalink / raw)
To: David Miller, Herbert Xu; +Cc: netdev
In-Reply-To: <20110329054552.GI1290@secunet.com>
When we clone a xfrm state we have to assign the replay_esn
and the preplay_esn pointers to the state if we use the
new replay detection method. To this end, we add a
xfrm_replay_clone() function that allocates memory for
the replay detection and takes over the necessary values
from the original state.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
include/net/xfrm.h | 22 ++++++++++++++++++++++
net/xfrm/xfrm_state.c | 6 ++++++
2 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index cffa5dc..6ae4bc5 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1601,6 +1601,28 @@ static inline int xfrm_replay_state_esn_len(struct xfrm_replay_state_esn *replay
}
#ifdef CONFIG_XFRM_MIGRATE
+static inline int xfrm_replay_clone(struct xfrm_state *x,
+ struct xfrm_state *orig)
+{
+ x->replay_esn = kzalloc(xfrm_replay_state_esn_len(orig->replay_esn),
+ GFP_KERNEL);
+ if (!x->replay_esn)
+ return -ENOMEM;
+
+ x->replay_esn->bmp_len = orig->replay_esn->bmp_len;
+ x->replay_esn->replay_window = orig->replay_esn->replay_window;
+
+ x->preplay_esn = kmemdup(x->replay_esn,
+ xfrm_replay_state_esn_len(x->replay_esn),
+ GFP_KERNEL);
+ if (!x->preplay_esn) {
+ kfree(x->replay_esn);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
{
return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index f83a3d1..dd78536 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1181,6 +1181,12 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
goto error;
}
+ if (orig->replay_esn) {
+ err = xfrm_replay_clone(x, orig);
+ if (err)
+ goto error;
+ }
+
memcpy(&x->mark, &orig->mark, sizeof(x->mark));
err = xfrm_init_state(x);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 3/4] xfrm: Check for esn buffer len in xfrm_new_ae
From: Steffen Klassert @ 2011-03-29 5:47 UTC (permalink / raw)
To: David Miller, Herbert Xu; +Cc: netdev
In-Reply-To: <20110329054552.GI1290@secunet.com>
In xfrm_new_ae() we may overwrite the allocated esn replay state
buffer with a wrong size. So check that the new size matches the
original allocated size and return an error if this is not the case.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_user.c | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index fc152d2..ccc4c0c 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -360,6 +360,23 @@ static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
return 0;
}
+static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_esn,
+ struct nlattr *rp)
+{
+ struct xfrm_replay_state_esn *up;
+
+ if (!replay_esn || !rp)
+ return 0;
+
+ up = nla_data(rp);
+
+ if (xfrm_replay_state_esn_len(replay_esn) !=
+ xfrm_replay_state_esn_len(up))
+ return -EINVAL;
+
+ return 0;
+}
+
static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn,
struct xfrm_replay_state_esn **preplay_esn,
struct nlattr *rta)
@@ -1766,6 +1783,10 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
if (x->km.state != XFRM_STATE_VALID)
goto out;
+ err = xfrm_replay_verify_len(x->replay_esn, rp);
+ if (err)
+ goto out;
+
spin_lock_bh(&x->lock);
xfrm_update_ae_params(x, attrs);
spin_unlock_bh(&x->lock);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 4/4] xfrm: Restrict extended sequence numbers to esp
From: Steffen Klassert @ 2011-03-29 5:48 UTC (permalink / raw)
To: David Miller, Herbert Xu; +Cc: netdev
In-Reply-To: <20110329054552.GI1290@secunet.com>
The IPsec extended sequence numbers are fully implemented just for
esp. So restrict the usage to esp until other protocols have
support too.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_user.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index ccc4c0c..3d15d3e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -127,6 +127,9 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
if (!rt)
return 0;
+ if (p->id.proto != IPPROTO_ESP)
+ return -EINVAL;
+
if (p->replay_window != 0)
return -EINVAL;
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH 1/4] xfrm: Move the test on replay window size into the replay check functions
From: Herbert Xu @ 2011-03-29 6:20 UTC (permalink / raw)
To: Steffen Klassert; +Cc: David Miller, netdev
In-Reply-To: <20110329054552.GI1290@secunet.com>
On Tue, Mar 29, 2011 at 07:45:52AM +0200, Steffen Klassert wrote:
> As it is, the replay check is just performed if the replay window of the
> legacy implementation is nonzero. So we move the test on a nonzero replay
> window inside the replay check functions to be sure we are testing for the
> right implementation.
>
> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
for all 4 patches.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH 1/4] xfrm: Move the test on replay window size into the replay check functions
From: David Miller @ 2011-03-29 6:48 UTC (permalink / raw)
To: herbert; +Cc: steffen.klassert, netdev
In-Reply-To: <20110329062006.GA23079@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 29 Mar 2011 14:20:06 +0800
> On Tue, Mar 29, 2011 at 07:45:52AM +0200, Steffen Klassert wrote:
>> As it is, the replay check is just performed if the replay window of the
>> legacy implementation is nonzero. So we move the test on a nonzero replay
>> window inside the replay check functions to be sure we are testing for the
>> right implementation.
>>
>> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
>
> Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
>
> for all 4 patches.
All applied, thanks Steffen.
^ permalink raw reply
* [GIT] Networking
From: David Miller @ 2011-03-29 7:49 UTC (permalink / raw)
To: torvalds; +Cc: akpm, netdev, linux-kernel
1) Fix oops in RAW ipv4 when route doesn't exist.
2) Heap corruptions, missing length checks, in IRDA and ROSE. From
Dan Rosenberg and Ben Hutchings.
3) Fix FIB error return code checking regression, fix from Julian Anastasov.
4) Fix refression in ethtool ->set_flags() error returns for some
network drivers, from Stanislaw Gruszka.
5) When we do async crypto, we don't take a reference while the transaction
is "in flight" and thus can crash if the object is release meanwhile.
Fix from Steffen Klassert.
6) Bug fixes to the new IPSEC extended replay window support, also
from Steffen Klassert.
7) Bridge forgets to send out notifier when device address changes, from
Stephen Hemminger.
8) Conver jme driver away from legacy PCI power management, from Rafael J.
Wysocki.
9) GRO is ineffective on large page size configs because we don't put
enough scatter gather elements into the SKB, from Anton Blanchard.
10) cxgb3 erroneously only applies irq coalescing settings to one queue,
fix also from Anton Blanchard.
11) CAN fixes from Jan Altenberg, Marc Kleine-Budde, and Oliver Hartkopp.
12) mlx4_en driver loses promiscuous setting, fix from Herbert Xu.
Please pull, thanks a lot!
The following changes since commit 89078d572eb9ce8d4c04264b8b0ba86de0d74c8f:
md: Fix integrity registration error when no devices are capable (2011-03-28 17:53:29 -0700)
are available in the git repository at:
master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6.git master
Amerigo Wang (1):
net: remove useless comments in net/core/dev.c
Anton Blanchard (2):
net: Always allocate at least 16 skb frags regardless of page size
cxgb3: Apply interrupt coalescing settings to all queues
Balaji G (1):
drivers net: Fix declaration ordering in inline functions.
Ben Hutchings (1):
rose: Add length checks to CALL_REQUEST parsing
Cesar Eduardo Barros (1):
net: use CHECKSUM_NONE instead of magic number
Dan Rosenberg (3):
irda: prevent heap corruption on invalid nickname
irda: validate peer name and attribute lengths
ROSE: prevent heap corruption with bad facilities
David S. Miller (1):
ipv4: Don't ip_rt_put() an error pointer in RAW sockets.
Herbert Xu (1):
mlx4_en: Fix loss of promiscuity
Jan Altenberg (1):
can: c_can: Fix tx_bytes accounting
Jan Luebbe (1):
ipv4: Fix IP timestamp option (IPOPT_TS_PRESPEC) handling in ip_options_echo()
Javier Martinez Canillas (2):
tg3: use <linux/io.h> and <linux/uaccess.h> instead <asm/io.h> and <asm/uaccess.h>
tg3: Fix inline keyword usage
Julian Anastasov (1):
ipv4: do not ignore route errors
Marc Kleine-Budde (2):
can: c_can: disable one shot mode until driver is fixed
can: c_can_platform: fix irq check in probe
Mike Frysinger (1):
netdev: bfin_mac: document TE setting in RMII modes
Oliver Hartkopp (1):
can: make struct proto const
Rafael J. Wysocki (1):
Net / jme: Do not use legacy PCI power management
Stanislaw Gruszka (2):
myri10ge: small rx_done refactoring
net: fix ethtool->set_flags not intended -EINVAL return value
Steffen Klassert (6):
xfrm: Force a dst refcount before entering the xfrm type handlers
dst: Clone child entry in skb_dst_pop
xfrm: Move the test on replay window size into the replay check functions
xfrm: Assign esn pointers when cloning a state
xfrm: Check for esn buffer len in xfrm_new_ae
xfrm: Restrict extended sequence numbers to esp
stephen hemminger (1):
bridge: notify applications if address of bridge device changes
drivers/net/bfin_mac.c | 13 ++++-
drivers/net/bnx2.c | 2 +-
drivers/net/can/c_can/c_can.c | 16 ++----
drivers/net/can/c_can/c_can_platform.c | 9 ++-
drivers/net/cxgb3/cxgb3_main.c | 14 +++-
drivers/net/jme.c | 30 +++++----
drivers/net/ksz884x.c | 2 +-
drivers/net/mlx4/en_netdev.c | 3 +
drivers/net/myri10ge/myri10ge.c | 37 +++++++----
drivers/net/netxen/netxen_nic_ethtool.c | 2 +-
drivers/net/qlcnic/qlcnic_ethtool.c | 2 +-
drivers/net/s2io.c | 2 +-
drivers/net/tg3.c | 6 +-
drivers/net/vmxnet3/vmxnet3_ethtool.c | 4 +-
drivers/net/vxge/vxge-ethtool.c | 4 +-
include/linux/can/core.h | 9 ++-
include/linux/ethtool.h | 1 +
include/linux/skbuff.h | 8 ++-
include/net/dst.h | 2 +-
include/net/rose.h | 8 ++-
include/net/xfrm.h | 22 +++++++
net/bridge/br_if.c | 6 ++-
net/bridge/br_private.h | 2 +-
net/bridge/br_stp_if.c | 9 ++-
net/can/af_can.c | 9 +--
net/can/bcm.c | 4 +-
net/can/raw.c | 4 +-
net/core/dev.c | 55 +----------------
net/core/ethtool.c | 17 +++++-
net/ipv4/fib_trie.c | 4 +-
net/ipv4/ip_options.c | 6 +-
net/ipv4/raw.c | 1 +
net/ipv6/ip6mr.c | 2 +-
net/irda/iriap.c | 6 ++
net/irda/irnet/irnet_ppp.c | 3 +
net/rose/af_rose.c | 8 +-
net/rose/rose_loopback.c | 13 ++++-
net/rose/rose_route.c | 20 ++++--
net/rose/rose_subr.c | 101 +++++++++++++++++++++----------
net/xfrm/xfrm_input.c | 4 +-
net/xfrm/xfrm_output.c | 4 +-
net/xfrm/xfrm_replay.c | 17 +++++-
net/xfrm/xfrm_state.c | 6 ++
net/xfrm/xfrm_user.c | 24 +++++++
44 files changed, 329 insertions(+), 192 deletions(-)
^ permalink raw reply
* [PATCH] net: gre: provide multicast mappings for ipv4 and ipv6
From: Timo Teräs @ 2011-03-29 8:40 UTC (permalink / raw)
To: netdev; +Cc: Doug Kehn, Timo Teräs
In-Reply-To: <4D8F6313.60408@iki.fi>
My commit 6d55cb91a0020ac0 (gre: fix hard header destination
address checking) broke multicast.
The reason is that ip_gre used to get ipgre_header() calls with
zero destination if we have NOARP or multicast destination. Instead
the actual target was decided at ipgre_tunnel_xmit() time based on
per-protocol dissection.
Instead of allowing the "abuse" of ->header() calls with invalid
destination, this creates multicast mappings for ip_gre. This also
fixes "ip neigh show nud noarp" to display the proper multicast
mappings used by the gre device.
Reported-by: Doug Kehn <rdkehn@yahoo.com>
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
---
Compile tested only. Doug tested IPv4 side with the earlier patch.
The IPv6 side needs a review. I'm not sure if mapped IPv4 multicast
addresses are intrepreted as multicast addresses by ndisc code or
if we could map real IPv6 multicast addresses to IPv4 multicast
addresses.
include/net/if_inet6.h | 16 ++++++++++++++++
include/net/ip.h | 8 ++++++++
net/ipv4/arp.c | 3 +++
net/ipv6/ndisc.c | 2 ++
4 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 04977ee..fccc218 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -286,5 +286,21 @@ static inline void ipv6_ib_mc_map(const struct in6_addr *addr,
buf[9] = broadcast[9];
memcpy(buf + 10, addr->s6_addr + 6, 10);
}
+
+static inline int ipv6_ipgre_mc_map(const struct in6_addr *addr,
+ const unsigned char *broadcast, char *buf)
+{
+ if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) {
+ memcpy(buf, broadcast, 4);
+ } else {
+ /* v4mapped? */
+ if ((addr->s6_addr32[0] | addr->s6_addr32[1] |
+ (addr->s6_addr32[2] ^ htonl(0x0000ffff))) != 0)
+ return -EINVAL;
+ memcpy(buf, &addr->s6_addr32[3], 4);
+ }
+ return 0;
+}
+
#endif
#endif
diff --git a/include/net/ip.h b/include/net/ip.h
index a4f6311..7c41658 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -339,6 +339,14 @@ static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, ch
buf[16] = addr & 0x0f;
}
+static inline void ip_ipgre_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf)
+{
+ if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0)
+ memcpy(buf, broadcast, 4);
+ else
+ memcpy(buf, &naddr, sizeof(naddr));
+}
+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <linux/ipv6.h>
#endif
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 090d273..1b74d3b 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -215,6 +215,9 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
case ARPHRD_INFINIBAND:
ip_ib_mc_map(addr, dev->broadcast, haddr);
return 0;
+ case ARPHRD_IPGRE:
+ ip_ipgre_mc_map(addr, dev->broadcast, haddr);
+ return 0;
default:
if (dir) {
memcpy(haddr, dev->broadcast, dev->addr_len);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 0e49c9d..92f952d 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -341,6 +341,8 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
case ARPHRD_INFINIBAND:
ipv6_ib_mc_map(addr, dev->broadcast, buf);
return 0;
+ case ARPHRD_IPGRE:
+ return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
default:
if (dir) {
memcpy(buf, dev->broadcast, dev->addr_len);
--
1.7.1
^ permalink raw reply related
* [PATCH] NFS4: some cleanup in kernel thread creation
From: Stanislav Kinsbursky @ 2011-03-29 9:06 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, bfields, davem
kthread_run() macro allows to pass kthread name with parameters in printf
style. So, additinal array for kthread name is redundant and was removed.
Patch for 2.6.38
Found in 2.6.32
Signed-off-by: Stanislav Kinsbursky <skinsbursky@openvz.org>
---
fs/nfs/callback.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index e3d2942..9e5220f 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -250,7 +250,6 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
struct svc_rqst *rqstp;
int (*callback_svc)(void *vrqstp);
struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
- char svc_name[12];
int ret = 0;
int minorversion_setup;
@@ -280,10 +279,10 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
svc_sock_update_bufs(serv);
- sprintf(svc_name, "nfsv4.%u-svc", minorversion);
cb_info->serv = serv;
cb_info->rqst = rqstp;
- cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name);
+ cb_info->task = kthread_run(callback_svc, cb_info->rqst,
+ "nfsv4.%u-svc", minorversion);
if (IS_ERR(cb_info->task)) {
ret = PTR_ERR(cb_info->task);
svc_exit_thread(cb_info->rqst);
^ permalink raw reply related
* Re: [PATCH] net: gre: provide multicast mappings for ipv4 and ipv6
From: Eric Dumazet @ 2011-03-29 9:11 UTC (permalink / raw)
To: Timo Teräs; +Cc: netdev, Doug Kehn
In-Reply-To: <1301388053-6083-1-git-send-email-timo.teras@iki.fi>
Le mardi 29 mars 2011 à 11:40 +0300, Timo Teräs a écrit :
> My commit 6d55cb91a0020ac0 (gre: fix hard header destination
> address checking) broke multicast.
>
> The reason is that ip_gre used to get ipgre_header() calls with
> zero destination if we have NOARP or multicast destination. Instead
> the actual target was decided at ipgre_tunnel_xmit() time based on
> per-protocol dissection.
>
> Instead of allowing the "abuse" of ->header() calls with invalid
> destination, this creates multicast mappings for ip_gre. This also
> fixes "ip neigh show nud noarp" to display the proper multicast
> mappings used by the gre device.
>
> Reported-by: Doug Kehn <rdkehn@yahoo.com>
> Signed-off-by: Timo Teräs <timo.teras@iki.fi>
> ---
> Compile tested only. Doug tested IPv4 side with the earlier patch.
> +static inline int ipv6_ipgre_mc_map(const struct in6_addr *addr,
> + const unsigned char *broadcast, char *buf)
> +{
> + if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) {
> + memcpy(buf, broadcast, 4);
> + } else {
> + /* v4mapped? */
> + if ((addr->s6_addr32[0] | addr->s6_addr32[1] |
> + (addr->s6_addr32[2] ^ htonl(0x0000ffff))) != 0)
> + return -EINVAL;
if (ipv6_addr_v4mapped(addr))
> + memcpy(buf, &addr->s6_addr32[3], 4);
> + }
> + return 0;
> +}
^ permalink raw reply
* Re: [PATCH] net: gre: provide multicast mappings for ipv4 and ipv6
From: Timo Teräs @ 2011-03-29 10:00 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, Doug Kehn
In-Reply-To: <1301389905.3161.3.camel@edumazet-laptop>
On 03/29/2011 12:11 PM, Eric Dumazet wrote:
> Le mardi 29 mars 2011 à 11:40 +0300, Timo Teräs a écrit :
>> My commit 6d55cb91a0020ac0 (gre: fix hard header destination
>> address checking) broke multicast.
>>
>> The reason is that ip_gre used to get ipgre_header() calls with
>> zero destination if we have NOARP or multicast destination. Instead
>> the actual target was decided at ipgre_tunnel_xmit() time based on
>> per-protocol dissection.
>>
>> Instead of allowing the "abuse" of ->header() calls with invalid
>> destination, this creates multicast mappings for ip_gre. This also
>> fixes "ip neigh show nud noarp" to display the proper multicast
>> mappings used by the gre device.
>>
>> Reported-by: Doug Kehn <rdkehn@yahoo.com>
>> Signed-off-by: Timo Teräs <timo.teras@iki.fi>
>> ---
>> Compile tested only. Doug tested IPv4 side with the earlier patch.
>
>
>> +static inline int ipv6_ipgre_mc_map(const struct in6_addr *addr,
>> + const unsigned char *broadcast, char *buf)
>> +{
>> + if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) {
>> + memcpy(buf, broadcast, 4);
>> + } else {
>> + /* v4mapped? */
>> + if ((addr->s6_addr32[0] | addr->s6_addr32[1] |
>> + (addr->s6_addr32[2] ^ htonl(0x0000ffff))) != 0)
>> + return -EINVAL;
>
> if (ipv6_addr_v4mapped(addr))
>
>
>> + memcpy(buf, &addr->s6_addr32[3], 4);
>> + }
>> + return 0;
>> +}
I wanted to put the function same header as all other similar ones:
net/if_inet6.h. However, ipv6_addr_v4mapped() is defined in net/ipv6.h
which includes net/if_inet6.h. So I can't really use that function there.
^ permalink raw reply
* Re: [PATCH 2/2 v2] tg3: Don't use IRQF_SAMPLE_RANDOM
From: Javier Martinez Canillas @ 2011-03-29 11:26 UTC (permalink / raw)
To: David Miller; +Cc: bhutchings, eric.dumazet, error27, netdev, kernel-janitors
In-Reply-To: <20110328.165311.226778266.davem@davemloft.net>
On Tue, Mar 29, 2011 at 1:53 AM, David Miller <davem@davemloft.net> wrote:
> From: Ben Hutchings <bhutchings@solarflare.com>
> Date: Mon, 28 Mar 2011 18:20:22 +0100
>
>> On Mon, 2011-03-28 at 17:46 +0200, Javier Martinez Canillas wrote:
>>> Yes this definitely is not janitor material :)
>>>
>>> I just sent the patch because I saw IRQF_SAMPLE_RANDOM in
>>> Documentation/feature-removal-schedule.txt. I can resend a patch
>>> removing the macro in the remaining network cards if the decision is
>>> to remove IRQF_SAMPLE_RANDOM.
>>
>> It's not my call, but I would support it.
>
> FWIW, I support it too.
>
Ok, I just sent a patch removing the IRQF_SAMPLE_RANDOM flag in all
the network drivers in the case everyone agrees.
Best regards,
-----------------------------------------
Javier Martínez Canillas
(+34) 682 39 81 69
PhD Student in High Performance Computing
Computer Architecture and Operating System Department (CAOS)
Universitat Autònoma de Barcelona
Barcelona, Spain
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox