* [PATCH 3/4] sis190: mdio operation failure is not correctly detected
From: Francois Romieu @ 2007-12-10 22:31 UTC (permalink / raw)
To: jeff; +Cc: Andrew Morton, netdev, K.M. Liu
In-Reply-To: <20071210222732.GA8675@electric-eye.fr.zoreil.com>
i ranges from 0 to 100 in the 'for' loop a few lines above.
Reported by davem.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: K.M. Liu <kmliu@sis.com.tw>
---
drivers/net/sis190.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index f6a921c..973b369 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -372,7 +372,7 @@ static void __mdio_cmd(void __iomem *ioaddr, u32 ctl)
msleep(1);
}
- if (i > 999)
+ if (i > 99)
printk(KERN_ERR PFX "PHY command failed !\n");
}
--
1.5.3.3
^ permalink raw reply related
* [PATCH 1/4] sis190: add cmos ram access code for the SiS19x/968 chipset pair
From: Francois Romieu @ 2007-12-10 22:29 UTC (permalink / raw)
To: jeff
Cc: Andrew Morton, netdev, K.M. Liu, J. Gleacher,
Alexandre Penasso Teixeira, Arliton Rocha, Juan Jose Pablos,
Wipat Srutiprom
In-Reply-To: <20071210222732.GA8675@electric-eye.fr.zoreil.com>
More work is needed to handle correctly the PHY of the new devices
when connected to a 10Mb link but this change already helps some
users as is.
Fix for:
http://bugzilla.kernel.org/show_bug.cgi?id=9467
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: K.M. Liu <kmliu@sis.com.tw>
Cc: J. Gleacher <jgleacher@yahoo.com>
Cc: Alexandre Penasso Teixeira <alexandre@keepsoftware.com>
Cc: Arliton Rocha <arliton@gmail.com>
Cc: Juan Jose Pablos <juanjo@apertus.es>
Cc: Wipat Srutiprom <wipat.s@psu.ac.th>
---
drivers/net/sis190.c | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 7200883..51bbb60 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1549,28 +1549,31 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
}
/**
- * sis190_get_mac_addr_from_apc - Get MAC address for SiS965 model
+ * sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model
* @pdev: PCI device
* @dev: network device to get address for
*
- * SiS965 model, use APC CMOS RAM to store MAC address.
+ * SiS96x model, use APC CMOS RAM to store MAC address.
* APC CMOS RAM is accessed through ISA bridge.
* MAC address is read into @net_dev->dev_addr.
*/
static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
struct net_device *dev)
{
+ static const u16 __devinitdata ids[] = { 0x0965, 0x0966, 0x0968 };
struct sis190_private *tp = netdev_priv(dev);
struct pci_dev *isa_bridge;
u8 reg, tmp8;
- int i;
+ unsigned int i;
net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n",
pci_name(pdev));
- isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL);
- if (!isa_bridge)
- isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0966, NULL);
+ for (i = 0; i < ARRAY_SIZE(ids); i++) {
+ isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, ids[i], NULL);
+ if (isa_bridge)
+ break;
+ }
if (!isa_bridge) {
net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n",
--
1.5.3.3
^ permalink raw reply related
* [PATCH 4/4] sis190: scheduling while atomic error
From: Francois Romieu @ 2007-12-10 22:31 UTC (permalink / raw)
To: jeff; +Cc: Andrew Morton, netdev, K.M. Liu
In-Reply-To: <20071210222732.GA8675@electric-eye.fr.zoreil.com>
sis190_tx_timeout
-> sis190_hw_start
-> sis190_soft_reset
-> msleep *splat*
PCI transactions are correctly flushed here.
The msleep() is probably useless.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: K.M. Liu <kmliu@sis.com.tw>
---
drivers/net/sis190.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 973b369..c0db182 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -847,10 +847,8 @@ static void sis190_soft_reset(void __iomem *ioaddr)
{
SIS_W32(IntrControl, 0x8000);
SIS_PCI_COMMIT();
- msleep(1);
SIS_W32(IntrControl, 0x0);
sis190_asic_down(ioaddr);
- msleep(1);
}
static void sis190_hw_start(struct net_device *dev)
--
1.5.3.3
^ permalink raw reply related
* [IPv4] ESP: Discard dummy packets introduced in rfc4303
From: Thomas Graf @ 2007-12-10 22:17 UTC (permalink / raw)
To: davem, herbert; +Cc: netdev
RFC4303 introduces dummy packets with a nexthdr value of 59
to implement traffic confidentiality. Such packets need to
be dropped silently and the payload may not be attempted to
be parsed as it consists of random chunk.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Index: net-2.6.25/net/ipv4/esp4.c
===================================================================
--- net-2.6.25.orig/net/ipv4/esp4.c 2007-12-10 15:57:23.000000000 +0100
+++ net-2.6.25/net/ipv4/esp4.c 2007-12-10 16:06:10.000000000 +0100
@@ -9,6 +9,7 @@
#include <linux/pfkeyv2.h>
#include <linux/random.h>
#include <linux/spinlock.h>
+#include <linux/in6.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/udp.h>
@@ -233,6 +234,10 @@
/* ... check padding bits here. Silly. :-) */
+ /* RFC4303: Drop dummy packets without any error */
+ if (nexthdr[1] == IPPROTO_NONE)
+ goto out;
+
iph = ip_hdr(skb);
ihl = iph->ihl * 4;
^ permalink raw reply
* [IPv6] ESP: Discard dummy packets introduced in rfc4303
From: Thomas Graf @ 2007-12-10 22:18 UTC (permalink / raw)
To: davem, herbert; +Cc: netdev
RFC4303 introduces dummy packets with a nexthdr value of 59
to implement traffic confidentiality. Such packets need to
be dropped silently and the payload may not be attempted to
be parsed as it consists of random chunk.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Index: net-2.6.25/net/ipv6/esp6.c
===================================================================
--- net-2.6.25.orig/net/ipv6/esp6.c 2007-12-10 16:06:02.000000000 +0100
+++ net-2.6.25/net/ipv6/esp6.c 2007-12-10 16:08:02.000000000 +0100
@@ -238,6 +238,12 @@
}
/* ... check padding bits here. Silly. :-) */
+ /* RFC4303: Drop dummy packets without any error */
+ if (nexthdr[1] == IPPROTO_NONE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
pskb_trim(skb, skb->len - alen - padlen - 2);
ret = nexthdr[1];
}
^ permalink raw reply
* Re: [PATCH] [TCP]: Bind fackets_out state to highest_sack more tightly
From: David Miller @ 2007-12-10 23:55 UTC (permalink / raw)
To: ilpo.jarvinen; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0712101437080.3437@kivilampi-30.cs.helsinki.fi>
From: "Ilpo_Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Mon, 10 Dec 2007 14:39:46 +0200 (EET)
> On Mon, 10 Dec 2007, David Miller wrote:
>
> > From: "Ilpo_Järvinen" <ilpo.jarvinen@helsinki.fi>
> > Date: Mon, 10 Dec 2007 14:27:24 +0200 (EET)
> >
> > > Added checks will catch most of the errors if the current
> > > complex fack_count counting logic is flawed somewhere.
> > >
> > > Fackets_out should always be advancable if highest_sack is too
> > > because the fackets_out is nowadays accurate (and obviously it
> > > must be smaller than packets_out).
> > >
> > > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
> >
> > Applied to net-2.6.25, thanks!
>
> Please get the fack_count fix as well from the mm1 thread before my
> mailbox gets filled with stacktraces :-) :
> http://marc.info/?l=linux-netdev&m=119728952018975&w=2
Done, thanks!
^ permalink raw reply
* Re: [PATCH][Take3] PCI legacy I/O port free driver - Making Intel e1000 driver legacy I/O port free
From: Kok, Auke @ 2007-12-11 0:03 UTC (permalink / raw)
To: Tomohiro Kusumi, NetDev
Cc: Ronciak, John, Jesse Brandeburg, Kirsher, Jeffrey T
In-Reply-To: <474CCEAD.1060702@jp.fujitsu.com>
Tomohiro Kusumi wrote:
> Dear Auke and e1000 maintainers
>
> Hi, this is the patch which makes the e1000 driver legacy I/O port free.
>
> I've received some advice from Auke quite long time ago, and submitted
> a patch (http://lkml.org/lkml/2007/8/10/11) which I think meets what Auke
> had told me. Since the patch has not received any reaction from the e1000
> community, let me submit it once again (plus, the previous one had a bug
> regarding module parameter).
this opens up an interesting discussion -
e1000 is going to be the driver for 8254x hardware only from 2.6.25 and on. e1000e
will be the driver that powers 8257x hardware (and ich8/9 and es2lan NICs) and
those are all the pci-e hardware devices.
This means that the current e1000 driver will not power the pci-e hardware anymore
and thus those io-port free devices are removed from e1000.
considering the fact that only 82542, 82543 and 82547 devices are (from 2.6.25) on
the only devices that can be ioport free in this new e1000 driver, I think that it
almost makes no sense to code this functionality up for that.
so, I'm wondering if we should not drop this effort alltogether, since it's just a
lot of code and none of the pci-e hardware should use ioport anymore.
Can you screen e1000e in jeff garzik's netdev-2.6#upstream tree and see if that is
correctly not using ioport? I think that would be worth the time.
Cheers,
Auke
>
> If the module parameter enable_legacy_ioport_free is set to 0, it does
> not differ from the existing e1000 driver, otherwise legacy I/O port free
> function is enabled. I may have done something wrong, so any comments
> would be helpful.
>
> Tomohiro Kusumi
> Signed-off-by: Tomohiro Kusumi <kusumi.tomohiro@jp.fujitsu.com>
>
> ---
> diff -Nur linux-2.6.23.org/drivers/net/e1000/e1000.h linux-2.6.23/drivers/net/e1000/e1000.h
> --- linux-2.6.23.org/drivers/net/e1000/e1000.h 2007-10-16 11:30:37.000000000 +0900
> +++ linux-2.6.23/drivers/net/e1000/e1000.h 2007-10-16 11:32:55.000000000 +0900
> @@ -342,6 +342,9 @@
> boolean_t quad_port_a;
> unsigned long flags;
> uint32_t eeprom_wol;
> +
> + int use_ioport;
> + int bars;
> };
>
> enum e1000_state_t {
> diff -Nur linux-2.6.23.org/drivers/net/e1000/e1000_main.c linux-2.6.23/drivers/net/e1000/e1000_main.c
> --- linux-2.6.23.org/drivers/net/e1000/e1000_main.c 2007-10-16 11:30:38.000000000 +0900
> +++ linux-2.6.23/drivers/net/e1000/e1000_main.c 2007-10-16 14:48:16.390575464 +0900
> @@ -226,6 +226,11 @@
> static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
> static void e1000_io_resume(struct pci_dev *pdev);
>
> +static unsigned int enable_legacy_ioport_free = 0;
> +module_param(enable_legacy_ioport_free, uint, 0644);
> +MODULE_PARM_DESC(enable_legacy_ioport_free, "Enable legacy I/O port free (default:0)");
> +static int e1000_test_legacy_ioport(struct pci_dev *pdev);
> +
> static struct pci_error_handlers e1000_err_handler = {
> .error_detected = e1000_io_error_detected,
> .slot_reset = e1000_io_slot_reset,
> @@ -872,8 +877,24 @@
> int i, err, pci_using_dac;
> uint16_t eeprom_data = 0;
> uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
> - if ((err = pci_enable_device(pdev)))
> + int bars = 0;
> + int use_ioport = 0;
> +
> + if (enable_legacy_ioport_free) {
> + if ((use_ioport = e1000_test_legacy_ioport(pdev)) < 0) {
> + E1000_ERR("e1000_test_legacy_ioport failed, aborting\n");
> + return -1;
> + }
> + if (use_ioport)
> + bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
> + else
> + bars = pci_select_bars(pdev, IORESOURCE_MEM);
> + if ((err = pci_enable_device_bars(pdev, bars)) != 0)
> + return err;
> + }
> + else if ((err = pci_enable_device(pdev)) != 0) {
> return err;
> + }
>
> if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
> !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
> @@ -887,7 +908,11 @@
> pci_using_dac = 0;
> }
>
> - if ((err = pci_request_regions(pdev, e1000_driver_name)))
> + if (enable_legacy_ioport_free)
> + err = pci_request_selected_regions(pdev, bars, e1000_driver_name);
> + else
> + err = pci_request_regions(pdev, e1000_driver_name);
> + if (err)
> goto err_pci_reg;
>
> pci_set_master(pdev);
> @@ -906,6 +931,10 @@
> adapter->pdev = pdev;
> adapter->hw.back = adapter;
> adapter->msg_enable = (1 << debug) - 1;
> + if (enable_legacy_ioport_free) {
> + adapter->use_ioport = use_ioport;
> + adapter->bars = bars;
> + }
>
> mmio_start = pci_resource_start(pdev, BAR_0);
> mmio_len = pci_resource_len(pdev, BAR_0);
> @@ -915,12 +944,14 @@
> if (!adapter->hw.hw_addr)
> goto err_ioremap;
>
> - for (i = BAR_1; i <= BAR_5; i++) {
> - if (pci_resource_len(pdev, i) == 0)
> - continue;
> - if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
> - adapter->hw.io_base = pci_resource_start(pdev, i);
> - break;
> + if (!enable_legacy_ioport_free || adapter->use_ioport) {
> + for (i = BAR_1; i <= BAR_5; i++) {
> + if (pci_resource_len(pdev, i) == 0)
> + continue;
> + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
> + adapter->hw.io_base = pci_resource_start(pdev, i);
> + break;
> + }
> }
> }
>
> @@ -1188,7 +1219,10 @@
> err_ioremap:
> free_netdev(netdev);
> err_alloc_etherdev:
> - pci_release_regions(pdev);
> + if (enable_legacy_ioport_free)
> + pci_release_selected_regions(pdev, bars);
> + else
> + pci_release_regions(pdev);
> err_pci_reg:
> err_dma:
> pci_disable_device(pdev);
> @@ -1240,7 +1274,10 @@
> iounmap(adapter->hw.hw_addr);
> if (adapter->hw.flash_address)
> iounmap(adapter->hw.flash_address);
> - pci_release_regions(pdev);
> + if (enable_legacy_ioport_free)
> + pci_release_selected_regions(pdev, adapter->bars);
> + else
> + pci_release_regions(pdev);
>
> free_netdev(netdev);
>
> @@ -5180,7 +5217,11 @@
>
> pci_set_power_state(pdev, PCI_D0);
> pci_restore_state(pdev);
> - if ((err = pci_enable_device(pdev))) {
> + if (enable_legacy_ioport_free)
> + err = pci_enable_device_bars(pdev, adapter->bars);
> + else
> + err = pci_enable_device(pdev);
> + if (err) {
> printk(KERN_ERR "e1000: Cannot enable PCI device from suspend\n");
> return err;
> }
> @@ -5325,4 +5366,42 @@
>
> }
>
> +/*
> + * e1000_test_legacy_ioport - see if the device uses legacy I/O port
> + * @pdev: Pointer to PCI device
> + *
> + * This function tests if the PCI device uses I/O port.
> + * If yes the function returns 1, if no the function returns 0.
> + * The function returns -1 if there is an error.
> + */
> +static int e1000_test_legacy_ioport(struct pci_dev *pdev)
> +{
> + int ret;
> + struct e1000_hw hw;
> + memset(&hw, 0, sizeof(hw));
> +
> + hw.mac_type = e1000_undefined;
> + hw.device_id = pdev->device;
> + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.revision_id);
> +
> + if (e1000_set_mac_type(&hw) < 0)
> + return -1;
> +
> + switch (hw.mac_type) {
> + case e1000_82540:
> + case e1000_82541:
> + case e1000_82541_rev_2:
> + case e1000_82544:
> + case e1000_82545:
> + case e1000_82546:
> + ret = 1;
> + break;
> + default:
> + ret = 0;
> + break;
> + }
> +
> + return ret;
> +}
> +
> /* e1000_main.c */
^ permalink raw reply
* Re: [PATCH 2/3] arch/ : Platform changes for UCC TDM driver for MPC8323ERDB.Also includes related QE changes.
From: Stephen Rothwell @ 2007-12-11 0:18 UTC (permalink / raw)
To: Poonam_Aggrwal-b10812
Cc: rubini, linux-kernel, netdev, kumar.gala, linuxppc-dev,
michael.barkowski, rich.cutler, ashish.kalra
In-Reply-To: <Pine.LNX.4.64.0712101734490.29623@linux121>
[-- Attachment #1: Type: text/plain, Size: 2543 bytes --]
On Mon, 10 Dec 2007 17:39:22 +0530 (IST) Poonam_Aggrwal-b10812 <b10812@freescale.com> wrote:
>
> +++ b/arch/powerpc/sysdev/qe_lib/qe.c
> @@ -149,22 +149,116 @@ EXPORT_SYMBOL(qe_issue_cmd);
> */
> static unsigned int brg_clk = 0;
>
> -unsigned int get_brg_clk(void)
> +u32 get_brg_clk(enum qe_clock brgclk, enum qe_clock *brg_source)
> {
> - struct device_node *qe;
> - if (brg_clk)
> - return brg_clk;
> + struct device_node *qe, *brg, *clocks;
> + enum qe_clock brg_src;
> + u32 brg_input_freq = 0;
> + u32 brg_num;
> + const unsigned int *prop;
>
> - qe = of_find_node_by_type(NULL, "qe");
> - if (qe) {
> + *brg_source = 0;
> +
> + brg_num = brgclk - QE_BRG1;
> + brg = of_find_compatible_node(NULL, NULL, "fsl,cpm-brg");
> + if (brg) {
> unsigned int size;
> - const u32 *prop = of_get_property(qe, "brg-frequency", &size);
> - brg_clk = *prop;
> - of_node_put(qe);
> - };
> + prop = of_get_property(brg,
> + "fsl,brg-sources", &size);
> +
> + brg_src = *(prop + brg_num);
You should probably sanity check that prop is not NULL and points to
something large enough.
You don't use brg after here, so the "of_node_put(brg)" could go here to
save putting it in multiple places later. Also, currently there are
paths through the following code that do not do the of_node_put(brg).
> + if (brg_src == 0) {
> + *brg_source = 0;
> + if (brg_clk > 0) {
> + of_node_put(brg);
> + return brg_clk;
> + }
> + qe = of_find_node_by_type(NULL, "qe");
> + if (qe) {
> + unsigned int size;
> + prop = of_get_property
> + (qe, "brg-frequency", &size);
> + of_node_put(qe);
> + of_node_put(brg);
> + return *prop;
NULL check here (yes, I know that the old code didn't check).
> + }
> + } else {
> + *brg_source = brg_src + QE_CLK1 - 1;
> + clocks = of_find_compatible_node(NULL, NULL,
> + "fsl,cpm-clocks");
> + prop = of_get_property(clocks,
> + "#clock-cells", &size);
> + /*
> + * clock-cells = 1 only supported right now.
> + */
> + if (*prop != 1)
Again check for NULL (and possibly size).
> + return 0;
> + prop = of_get_property(clocks,
> + "clock-frequency", &size);
> +
> + brg_input_freq = *(prop+(brg_src - 1));
And again.
> + of_node_put(clocks);
> + of_node_put(brg);
> + return brg_input_freq;
> + }
> + }
> return brg_clk;
> }
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [patch 0/5] ipv6: make af_inet6 subsystems to return an error at init
From: David Miller @ 2007-12-11 0:45 UTC (permalink / raw)
To: dlezcano; +Cc: yoshfuji, pekkas, netdev
In-Reply-To: <475D5C22.1090103@fr.ibm.com>
From: Daniel Lezcano <dlezcano@fr.ibm.com>
Date: Mon, 10 Dec 2007 16:32:50 +0100
> I just noticed that I forgot to put ipv6 under bracket.
> Sorry for that :(
>
> Should I resend the patchset ?
This is not necessary.
^ permalink raw reply
* Re: [IPv4] ESP: Discard dummy packets introduced in rfc4303
From: David Miller @ 2007-12-11 0:53 UTC (permalink / raw)
To: tgraf; +Cc: davem, herbert, netdev
In-Reply-To: <20071210221703.GG11220@postel.suug.ch>
From: Thomas Graf <tgraf@suug.ch>
Date: Mon, 10 Dec 2007 23:17:03 +0100
> RFC4303 introduces dummy packets with a nexthdr value of 59
> to implement traffic confidentiality. Such packets need to
> be dropped silently and the payload may not be attempted to
> be parsed as it consists of random chunk.
>
> Signed-off-by: Thomas Graf <tgraf@suug.ch>
Applied to net-2.6, since this is more of a bug fix than
anything else.
^ permalink raw reply
* Re: [IPv6] ESP: Discard dummy packets introduced in rfc4303
From: David Miller @ 2007-12-11 0:54 UTC (permalink / raw)
To: tgraf; +Cc: herbert, netdev
In-Reply-To: <20071210221807.GH11220@postel.suug.ch>
From: Thomas Graf <tgraf@suug.ch>
Date: Mon, 10 Dec 2007 23:18:07 +0100
> RFC4303 introduces dummy packets with a nexthdr value of 59
> to implement traffic confidentiality. Such packets need to
> be dropped silently and the payload may not be attempted to
> be parsed as it consists of random chunk.
>
> Signed-off-by: Thomas Graf <tgraf@suug.ch>
Also applied to net-2.6, thanks Thomas.
^ permalink raw reply
* Re: [PATCH 1/3][BNX2]: Add PHY_DIS_EARLY_DAC workaround.
From: David Miller @ 2007-12-11 1:19 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1197235008.20251.9.camel@dell>
From: "Michael Chan" <mchan@broadcom.com>
Date: Sun, 09 Dec 2007 13:16:48 -0800
> [BNX2]: Add PHY_DIS_EARLY_DAC workaround.
>
> 5709 Ax and Bx chips all need this workaround.
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH 2/3][BNX2]: Fix RX packet rot.
From: David Miller @ 2007-12-11 1:19 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1197235034.20251.10.camel@dell>
From: "Michael Chan" <mchan@broadcom.com>
Date: Sun, 09 Dec 2007 13:17:14 -0800
> [BNX2]: Fix RX packet rot.
>
> Packets can be left in the RX ring if the NAPI budget is reached.
> This is caused by storing the latest rx index at the beginning of
> bnx2_rx_int(). We may not process all the work up to this index
> if the budget is reached and so some packets in the RX ring may rot
> when we later check for more work using this stored rx index.
>
> The fix is to not store this latest hw index and only store the
> processed rx index. We use a new function bnx2_get_hw_rx_cons()
> to fetch the latest hw rx index.
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH 3/3][BNX2]: Update version to 1.6.9.
From: David Miller @ 2007-12-11 1:19 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1197235082.20251.11.camel@dell>
From: "Michael Chan" <mchan@broadcom.com>
Date: Sun, 09 Dec 2007 13:18:02 -0800
> [BNX2]: Update version to 1.6.9.
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH 4/4] udp: memory accounting in IPv4
From: Hideo AOKI @ 2007-12-11 1:28 UTC (permalink / raw)
To: Herbert Xu, David Miller
Cc: netdev, Eric Dumazet, Satoshi Oshima, Bill Fink, Andi Kleen,
Evgeniy Polyakov, Stephen Hemminger, yoshfuji, Yumiko Sugita,
haoki
In-Reply-To: <20071210092252.GA1598@gondor.apana.org.au>
Herbert Xu wrote:
> On Wed, Dec 05, 2007 at 11:28:34PM -0500, Hideo AOKI wrote:
>> 1. Using sk_forward_alloc and adding socket lock
>>
>> UDP already uses a socket lock to send message. However, it doesn't
>> use the lock to receive message. I wonder if we can also use the
>> lock when sk_forward_alloc is updated in receive processing.
>> I understand performance issue might occur, but ...
>
> Having discussed this with Dave we've agreed that this is the
> best way to go.
>
> Thanks,
Hello,
Thank you so much for reviewing.
I chose this solution and developed new patch set.
I'm testing the patch set right now.
I'll submit it to netdev as soon as I finish the test.
Best regards,
Hideo
--
Hitachi Computer Products (America) Inc.
^ permalink raw reply
* [IPSEC]: Add xfrm_input_state helper
From: Herbert Xu @ 2007-12-11 3:45 UTC (permalink / raw)
To: David S. Miller, netdev
Hi Dave:
This is the last patch we need before converting ESP over to
crypto_aead.
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
[IPSEC]: Add xfrm_input_state helper
This patch adds the xfrm_input_state helper function which returns the
current xfrm state being processed on the input path given an sk_buff.
This is currently only used by xfrm_input but will be used by ESP upon
asynchronous resumption.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index fb154a6..c49fe0f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1302,4 +1302,9 @@ static inline void xfrm_states_delete(struct xfrm_state **states, int n)
}
#endif
+static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)
+{
+ return skb->sp->xvec[skb->sp->len - 1];
+}
+
#endif /* _NET_XFRM_H */
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 8b2b1b5..8624cbd 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -109,7 +109,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
/* A negative encap_type indicates async resumption. */
if (encap_type < 0) {
async = 1;
- x = skb->sp->xvec[skb->sp->len - 1];
+ x = xfrm_input_state(skb);
seq = XFRM_SKB_CB(skb)->seq;
goto resume;
}
^ permalink raw reply related
* Re: [PATCH 2.6.25] netns: struct net content re-work
From: Eric W. Biederman @ 2007-12-11 3:52 UTC (permalink / raw)
To: Denis V. Lunev; +Cc: davem, containers, netdev, herbert
In-Reply-To: <20071210163645.GA24030@iris.sw.ru>
The idea of separate structures make sense, and seems needed and useful.
"Denis V. Lunev" <den@openvz.org> writes:
> diff --git a/include/net/netns/unix.h b/include/net/netns/unix.h
> new file mode 100644
> index 0000000..27b4e7f
> --- /dev/null
> +++ b/include/net/netns/unix.h
^^^^^^
Given that we are making this per protocol adding a separate directory
to hold them seems to be the wrong grouping. Ideally we want everything
for the protocol all together in the same location so it is easy
to find. Possibly with a user/kernel split.
So perhaps unix_net.h
> @@ -0,0 +1,13 @@
> +/*
> + * Unix network namespace
> + */
> +#ifndef __NETNS_UNIX_H__
> +#define __NETNS_UNIX_H__
> +
> +struct ctl_table_header;
> +struct netns_unix {
> + int sysctl_unix_max_dgram_qlen;
> + struct ctl_table_header *unix_ctl;
> +};
How about struct unix_net? I think that tracks a little better
with how we have done struct in_device, ip6_dev and their friends.
Eric
^ permalink raw reply
* [PATCH] NET : dst_ifdown() cleanup
From: Eric Dumazet @ 2007-12-11 3:59 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
[-- Attachment #1: Type: text/plain, Size: 256 bytes --]
This cleanup shrinks size of net/core/dst.o on i386 from 1299 to 1289 bytes.
(This is because dev_hold()/dev_put() are doing atomic_inc()/atomic_dec() and
force compiler to re-evaluate memory contents.)
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
[-- Attachment #2: dst_ifdown.patch --]
[-- Type: text/plain, Size: 411 bytes --]
diff --git a/net/core/dst.c b/net/core/dst.c
index 5c6cfc4..7eceeba 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -284,8 +284,8 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
dev_put(dev);
if (dst->neighbour && dst->neighbour->dev == dev) {
dst->neighbour->dev = dst->dev;
+ dev_hold(dst->dev);
dev_put(dev);
- dev_hold(dst->neighbour->dev);
}
}
}
^ permalink raw reply related
* Re: [PATCH 2.6.25] netns: struct net content re-work
From: Eric W. Biederman @ 2007-12-11 4:04 UTC (permalink / raw)
To: Kirill Korotaev
Cc: Daniel Lezcano, containers, Denis V. Lunev, herbert, davem,
netdev
In-Reply-To: <475D7C56.9020402@sw.ru>
Kirill Korotaev <dev@sw.ru> writes:
> Daniel Lezcano wrote:
>> Denis V. Lunev wrote:
>>
>>>Recently David Miller and Herbert Xu pointed out that struct net becomes
>>>overbloated and un-maintainable. There are two solutions:
>>>- provide a pointer to a network subsystem definition from struct net.
>>> This costs an additional dereferrence
>>>- place sub-system definition into the structure itself. This will speedup
>>> run-time access at the cost of recompilation time
>>>
>>>The second approach looks better for us.
>>
>>
>> Yes, we do not need/want a pointer in this structure and add more
>> dereference in the network code.
If it does go that way we just carefully pass around a properly
typed structure in that subsystem to reduce the cost. Still
it would be nice not to need to add the extra pointer.
>>>index b62e31f..f60e1ce 100644
>>>--- a/include/net/net_namespace.h
>>>+++ b/include/net/net_namespace.h
>>>@@ -8,6 +8,8 @@
>>> #include <linux/workqueue.h>
>>> #include <linux/list.h>
>>>
>>>+#include <net/netns/unix.h>
>>>+
>>> struct proc_dir_entry;
>>> struct net_device;
>>> struct sock;
>>>@@ -46,8 +48,7 @@ struct net {
>>> struct hlist_head packet_sklist;
>>>
>>> /* unix sockets */
>>>- int sysctl_unix_max_dgram_qlen;
>>>- struct ctl_table_header *unix_ctl;
>>>+ struct netns_unix unx;
>>
>>
>> Can you change this from unx to unix ?
>
> no, it won't compile. Guess why :)
Hmm. It looks like it is a #define somewhere gcc?
Eric
^ permalink raw reply
* Re: [PATCH 2.6.25] netns: struct net content re-work
From: David Miller @ 2007-12-11 4:12 UTC (permalink / raw)
To: ebiederm; +Cc: dev, dlezcano, containers, den, herbert, netdev
In-Reply-To: <m1lk8127yg.fsf@ebiederm.dsl.xmission.com>
From: ebiederm@xmission.com (Eric W. Biederman)
Date: Mon, 10 Dec 2007 21:04:07 -0700
> Kirill Korotaev <dev@sw.ru> writes:
>
> > Daniel Lezcano wrote:
> >> Denis V. Lunev wrote:
> >> Can you change this from unx to unix ?
> >
> > no, it won't compile. Guess why :)
>
> Hmm. It looks like it is a #define somewhere gcc?
It is a platform CPP pre-define for UNIX platforms.
^ permalink raw reply
* [RFC 0/3] Add AEAD support to ESP
From: Herbert Xu @ 2007-12-11 4:23 UTC (permalink / raw)
To: David S. Miller, netdev
Hi Dave:
This series of patches add AEAD support to ESP.
Please don't merge it just yet because they depend on what's
in the current cryptodev-2.6 tree. Once that tree has settled
down I'll ask you to pull it and then these patches can go on
top of that.
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <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
* [PATCH 2/3] [IPSEC]: Allow async algorithms
From: Herbert Xu @ 2007-12-11 4:23 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20071211042312.GA10911@gondor.apana.org.au>
[IPSEC]: Allow async algorithms
Now that ESP uses authenc we can turn on the support for async algorithms
in IPsec.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/xfrm/xfrm_algo.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index 1686f64..ae34a12 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -358,21 +358,21 @@ static const struct xfrm_algo_list xfrm_aalg_list = {
.algs = aalg_list,
.entries = ARRAY_SIZE(aalg_list),
.type = CRYPTO_ALG_TYPE_HASH,
- .mask = CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC,
+ .mask = CRYPTO_ALG_TYPE_HASH_MASK,
};
static const struct xfrm_algo_list xfrm_ealg_list = {
.algs = ealg_list,
.entries = ARRAY_SIZE(ealg_list),
.type = CRYPTO_ALG_TYPE_BLKCIPHER,
- .mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC,
+ .mask = CRYPTO_ALG_TYPE_BLKCIPHER_MASK,
};
static const struct xfrm_algo_list xfrm_calg_list = {
.algs = calg_list,
.entries = ARRAY_SIZE(calg_list),
.type = CRYPTO_ALG_TYPE_COMPRESS,
- .mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC,
+ .mask = CRYPTO_ALG_TYPE_MASK,
};
static struct xfrm_algo_desc *xfrm_find_algo(
^ permalink raw reply related
* [PATCH 1/3] [IPSEC]: Use crypto_aead and authenc in ESP
From: Herbert Xu @ 2007-12-11 4:23 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20071211042312.GA10911@gondor.apana.org.au>
[IPSEC]: Use crypto_aead and authenc in ESP
This patch converts ESP to use the crypto_aead interface and in particular
the authenc algorithm. This lays the foundations for future support of
combined mode algorithms.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/esp.h | 54 +-----
net/ipv4/esp4.c | 465 ++++++++++++++++++++++++++++++++----------------------
net/ipv6/esp6.c | 422 +++++++++++++++++++++++++++++--------------------
3 files changed, 536 insertions(+), 405 deletions(-)
diff --git a/include/net/esp.h b/include/net/esp.h
index c05f529..d9834f7 100644
--- a/include/net/esp.h
+++ b/include/net/esp.h
@@ -1,58 +1,22 @@
#ifndef _NET_ESP_H
#define _NET_ESP_H
-#include <linux/crypto.h>
-#include <net/xfrm.h>
-#include <linux/scatterlist.h>
+#include <linux/skbuff.h>
#define ESP_NUM_FAST_SG 4
-struct esp_data
-{
- struct scatterlist sgbuf[ESP_NUM_FAST_SG];
-
- /* Confidentiality */
- struct {
- int padlen; /* 0..255 */
- /* ivlen is offset from enc_data, where encrypted data start.
- * It is logically different of crypto_tfm_alg_ivsize(tfm).
- * We assume that it is either zero (no ivec), or
- * >= crypto_tfm_alg_ivsize(tfm). */
- int ivlen;
- int ivinitted;
- u8 *ivec; /* ivec buffer */
- struct crypto_blkcipher *tfm; /* crypto handle */
- } conf;
-
- /* Integrity. It is active when icv_full_len != 0 */
- struct {
- u8 *work_icv;
- int icv_full_len;
- int icv_trunc_len;
- struct crypto_hash *tfm;
- } auth;
+struct crypto_aead;
+
+struct esp_data {
+ /* 0..255 */
+ int padlen;
+
+ /* Confidentiality & Integrity */
+ struct crypto_aead *aead;
};
extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len);
-static inline int esp_mac_digest(struct esp_data *esp, struct sk_buff *skb,
- int offset, int len)
-{
- struct hash_desc desc;
- int err;
-
- desc.tfm = esp->auth.tfm;
- desc.flags = 0;
-
- err = crypto_hash_init(&desc);
- if (unlikely(err))
- return err;
- err = skb_icv_walk(skb, &desc, offset, len, crypto_hash_update);
- if (unlikely(err))
- return err;
- return crypto_hash_final(&desc, esp->auth.work_icv);
-}
-
struct ip_esp_hdr;
static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb)
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index de4592c..c1f5936 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -1,3 +1,5 @@
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
#include <linux/err.h>
#include <linux/module.h>
#include <net/ip.h>
@@ -7,20 +9,91 @@
#include <linux/crypto.h>
#include <linux/kernel.h>
#include <linux/pfkeyv2.h>
-#include <linux/random.h>
+#include <linux/rtnetlink.h>
#include <linux/spinlock.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/udp.h>
+struct esp_skb_cb {
+ struct xfrm_skb_cb xfrm;
+ void *tmp;
+};
+
+#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
+
+/*
+ * Allocate an AEAD request structure with extra space for SG and IV.
+ *
+ * For alignment considerations the IV is placed at the front, followed
+ * by the request and finally the SG list.
+ *
+ * TODO: Use spare space in skb for this where possible.
+ */
+static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
+{
+ unsigned int len;
+
+ len = crypto_aead_ivsize(aead);
+ if (len) {
+ len += crypto_aead_alignmask(aead) &
+ ~(crypto_tfm_ctx_alignment() - 1);
+ len = ALIGN(len, crypto_tfm_ctx_alignment());
+ }
+
+ len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
+ len = ALIGN(len, __alignof__(struct scatterlist));
+
+ len += sizeof(struct scatterlist *) * nfrags;
+
+ return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp)
+{
+ return crypto_aead_ivsize(aead) ?
+ PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp;
+}
+
+static inline struct aead_givcrypt_request *esp_tmp_req(
+ struct crypto_aead *aead, u8 *iv)
+{
+ struct aead_givcrypt_request *req;
+
+ req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
+ crypto_tfm_ctx_alignment());
+ aead_givcrypt_set_tfm(req, aead);
+ return req;
+}
+
+static inline struct scatterlist *esp_tmp_sg(struct crypto_aead *aead,
+ struct aead_givcrypt_request *req)
+{
+ return (void *)ALIGN((unsigned long)(req + 1) +
+ crypto_aead_reqsize(aead),
+ __alignof__(struct scatterlist));
+}
+
+static void esp_output_done(struct crypto_async_request *base, int err)
+{
+ struct sk_buff *skb = base->data;
+
+ kfree(ESP_SKB_CB(skb)->tmp);
+ xfrm_output_resume(skb, err);
+}
+
static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
struct ip_esp_hdr *esph;
- struct crypto_blkcipher *tfm;
- struct blkcipher_desc desc;
+ struct crypto_aead *aead;
+ struct aead_givcrypt_request *req;
+ struct scatterlist *sg;
+ struct scatterlist *asg;
struct esp_data *esp;
struct sk_buff *trailer;
+ void *tmp;
+ u8 *iv;
u8 *tail;
int blksize;
int clen;
@@ -35,18 +108,26 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
clen = skb->len;
esp = x->data;
- alen = esp->auth.icv_trunc_len;
- tfm = esp->conf.tfm;
- desc.tfm = tfm;
- desc.flags = 0;
- blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+ aead = esp->aead;
+ alen = crypto_aead_authsize(aead);
+
+ blksize = ALIGN(crypto_aead_blocksize(aead), 4);
clen = ALIGN(clen + 2, blksize);
- if (esp->conf.padlen)
- clen = ALIGN(clen, esp->conf.padlen);
+ if (esp->padlen)
+ clen = ALIGN(clen, esp->padlen);
if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0)
goto error;
+ tmp = esp_alloc_tmp(aead, nfrags + 1);
+ if (!tmp)
+ goto error;
+
+ iv = esp_tmp_iv(aead, tmp);
+ req = esp_tmp_req(aead, iv);
+ asg = esp_tmp_sg(aead, req);
+ sg = asg + 1;
+
/* Fill padding... */
tail = skb_tail_pointer(trailer);
do {
@@ -55,28 +136,34 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
tail[i] = i + 1;
} while (0);
tail[clen - skb->len - 2] = (clen - skb->len) - 2;
- pskb_put(skb, trailer, clen - skb->len);
+ tail[clen - skb->len - 1] = *skb_mac_header(skb);
+ pskb_put(skb, trailer, clen - skb->len + alen);
skb_push(skb, -skb_network_offset(skb));
esph = ip_esp_hdr(skb);
- *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb);
*skb_mac_header(skb) = IPPROTO_ESP;
- spin_lock_bh(&x->lock);
-
/* this is non-NULL only with UDP Encapsulation */
if (x->encap) {
struct xfrm_encap_tmpl *encap = x->encap;
struct udphdr *uh;
__be32 *udpdata32;
+ unsigned int sport, dport;
+ int encap_type;
+
+ spin_lock_bh(&x->lock);
+ sport = encap->encap_sport;
+ dport = encap->encap_dport;
+ encap_type = encap->encap_type;
+ spin_unlock_bh(&x->lock);
uh = (struct udphdr *)esph;
- uh->source = encap->encap_sport;
- uh->dest = encap->encap_dport;
- uh->len = htons(skb->len + alen - skb_transport_offset(skb));
+ uh->source = sport;
+ uh->dest = dport;
+ uh->len = htons(skb->len - skb_transport_offset(skb));
uh->check = 0;
- switch (encap->encap_type) {
+ switch (encap_type) {
default:
case UDP_ENCAP_ESPINUDP:
esph = (struct ip_esp_hdr *)(uh + 1);
@@ -94,141 +181,50 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
esph->spi = x->id.spi;
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq);
- if (esp->conf.ivlen) {
- if (unlikely(!esp->conf.ivinitted)) {
- get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
- esp->conf.ivinitted = 1;
- }
- crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
- }
-
- do {
- struct scatterlist *sg = &esp->sgbuf[0];
-
- if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
- sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
- if (!sg)
- goto unlock;
- }
- sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg,
- esph->enc_data +
- esp->conf.ivlen -
- skb->data, clen);
- err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
- if (unlikely(sg != &esp->sgbuf[0]))
- kfree(sg);
- } while (0);
-
- if (unlikely(err))
- goto unlock;
-
- if (esp->conf.ivlen) {
- memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
- crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
- }
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg,
+ esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
+ clen + alen);
+ sg_init_one(asg, esph, sizeof(*esph));
- if (esp->auth.icv_full_len) {
- err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
- sizeof(*esph) + esp->conf.ivlen + clen);
- memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
- }
+ aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
+ aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
+ aead_givcrypt_set_assoc(req, asg, sizeof(*esph));
+ aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq);
-unlock:
- spin_unlock_bh(&x->lock);
+ ESP_SKB_CB(skb)->tmp = tmp;
+ err = crypto_aead_givencrypt(req);
+ if (err != -EINPROGRESS)
+ kfree(tmp);
error:
return err;
}
-/*
- * Note: detecting truncated vs. non-truncated authentication data is very
- * expensive, so we only support truncated data, which is the recommended
- * and common case.
- */
-static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+static int esp_input_done2(struct sk_buff *skb, int err)
{
- struct iphdr *iph;
- struct ip_esp_hdr *esph;
+ struct xfrm_state *x = xfrm_input_state(skb);
struct esp_data *esp = x->data;
- struct crypto_blkcipher *tfm = esp->conf.tfm;
- struct blkcipher_desc desc = { .tfm = tfm };
- struct sk_buff *trailer;
- int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
- int alen = esp->auth.icv_trunc_len;
- int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen;
- int nfrags;
+ struct crypto_aead *aead = esp->aead;
+ struct iphdr *iph;
+ int alen = crypto_aead_authsize(aead);
+ int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
+ int elen = skb->len - hlen;
int ihl;
- u8 nexthdr[2];
- struct scatterlist *sg;
int padlen;
- int err = -EINVAL;
-
- if (!pskb_may_pull(skb, sizeof(*esph)))
- goto out;
-
- if (elen <= 0 || (elen & (blksize-1)))
- goto out;
-
- if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
- goto out;
- nfrags = err;
-
- skb->ip_summed = CHECKSUM_NONE;
-
- spin_lock(&x->lock);
-
- /* If integrity check is required, do this. */
- if (esp->auth.icv_full_len) {
- u8 sum[alen];
-
- err = esp_mac_digest(esp, skb, 0, skb->len - alen);
- if (err)
- goto unlock;
-
- if (skb_copy_bits(skb, skb->len - alen, sum, alen))
- BUG();
-
- if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
- err = -EBADMSG;
- goto unlock;
- }
- }
-
- esph = (struct ip_esp_hdr *)skb->data;
-
- /* Get ivec. This can be wrong, check against another impls. */
- if (esp->conf.ivlen)
- crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
-
- sg = &esp->sgbuf[0];
-
- if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
- err = -ENOMEM;
- sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
- if (!sg)
- goto unlock;
- }
- sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg,
- sizeof(*esph) + esp->conf.ivlen,
- elen);
- err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
- if (unlikely(sg != &esp->sgbuf[0]))
- kfree(sg);
+ u8 nexthdr[2];
-unlock:
- spin_unlock(&x->lock);
+ kfree(ESP_SKB_CB(skb)->tmp);
if (unlikely(err))
goto out;
- if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
+ if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
BUG();
err = -EINVAL;
padlen = nexthdr[0];
- if (padlen+2 >= elen)
+ if (padlen + 2 + alen >= elen)
goto out;
/* ... check padding bits here. Silly. :-) */
@@ -274,7 +270,7 @@ unlock:
}
pskb_trim(skb, skb->len - alen - padlen - 2);
- __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
+ __skb_pull(skb, hlen);
skb_set_transport_header(skb, -ihl);
return nexthdr[1];
@@ -283,14 +279,89 @@ out:
return err;
}
+static void esp_input_done(struct crypto_async_request *base, int err)
+{
+ struct sk_buff *skb = base->data;
+
+ xfrm_input_resume(skb, esp_input_done2(skb, err));
+}
+
+/*
+ * Note: detecting truncated vs. non-truncated authentication data is very
+ * expensive, so we only support truncated data, which is the recommended
+ * and common case.
+ */
+static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ip_esp_hdr *esph;
+ struct esp_data *esp = x->data;
+ struct crypto_aead *aead = esp->aead;
+ struct aead_givcrypt_request *greq;
+ struct aead_request *req;
+ struct sk_buff *trailer;
+ int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
+ int nfrags;
+ void *tmp;
+ u8 *iv;
+ struct scatterlist *sg;
+ struct scatterlist *asg;
+ int err = -EINVAL;
+
+ if (!pskb_may_pull(skb, sizeof(*esph)))
+ goto out;
+
+ if (elen <= 0)
+ goto out;
+
+ if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ goto out;
+ nfrags = err;
+
+ err = -ENOMEM;
+ tmp = esp_alloc_tmp(aead, nfrags + 1);
+ if (!tmp)
+ goto out;
+
+ ESP_SKB_CB(skb)->tmp = tmp;
+ iv = esp_tmp_iv(aead, tmp);
+ greq = esp_tmp_req(aead, iv);
+ req = &greq->areq;
+ asg = esp_tmp_sg(aead, greq);
+ sg = asg + 1;
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ esph = (struct ip_esp_hdr *)skb->data;
+
+ /* Get ivec. This can be wrong, check against another impls. */
+ iv = esph->enc_data;
+
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
+ sg_init_one(asg, esph, sizeof(*esph));
+
+ aead_request_set_callback(req, 0, esp_input_done, skb);
+ aead_request_set_crypt(req, sg, sg, elen, iv);
+ aead_request_set_assoc(req, asg, sizeof(*esph));
+
+ err = crypto_aead_decrypt(req);
+ if (err == -EINPROGRESS)
+ goto out;
+
+ err = esp_input_done2(skb, err);
+
+out:
+ return err;
+}
+
static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
{
struct esp_data *esp = x->data;
- u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
- u32 align = max_t(u32, blksize, esp->conf.padlen);
+ u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
+ u32 align = max_t(u32, blksize, esp->padlen);
u32 rem;
- mtu -= x->props.header_len + esp->auth.icv_trunc_len;
+ mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
rem = mtu & (align - 1);
mtu &= ~(align - 1);
@@ -337,80 +408,98 @@ static void esp_destroy(struct xfrm_state *x)
if (!esp)
return;
- crypto_free_blkcipher(esp->conf.tfm);
- esp->conf.tfm = NULL;
- kfree(esp->conf.ivec);
- esp->conf.ivec = NULL;
- crypto_free_hash(esp->auth.tfm);
- esp->auth.tfm = NULL;
- kfree(esp->auth.work_icv);
- esp->auth.work_icv = NULL;
+ crypto_free_aead(esp->aead);
kfree(esp);
}
static int esp_init_state(struct xfrm_state *x)
{
struct esp_data *esp = NULL;
- struct crypto_blkcipher *tfm;
+ struct crypto_aead *aead;
+ struct crypto_authenc_key_param *param;
+ struct rtattr *rta;
+ char *key;
+ char *p;
+ char authenc_name[CRYPTO_MAX_ALG_NAME];
u32 align;
+ unsigned int keylen;
+ int err;
if (x->ealg == NULL)
- goto error;
+ return -EINVAL;
+
+ if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
+ x->aalg ? x->aalg->alg_name : "digest_null",
+ x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
esp = kzalloc(sizeof(*esp), GFP_KERNEL);
if (esp == NULL)
return -ENOMEM;
+ x->data = esp;
+
+ aead = crypto_alloc_aead(authenc_name, 0, 0);
+ err = PTR_ERR(aead);
+ if (IS_ERR(aead))
+ goto error;
+
+ esp->aead = aead;
+
+ keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
+ (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
+ err = -ENOMEM;
+ key = kmalloc(keylen, GFP_KERNEL);
+ if (!key)
+ goto error;
+
+ p = key;
+ rta = (void *)p;
+ rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
+ rta->rta_len = RTA_LENGTH(sizeof(*param));
+ param = RTA_DATA(rta);
+ p += RTA_SPACE(sizeof(*param));
+
if (x->aalg) {
struct xfrm_algo_desc *aalg_desc;
- struct crypto_hash *hash;
-
- hash = crypto_alloc_hash(x->aalg->alg_name, 0,
- CRYPTO_ALG_ASYNC);
- if (IS_ERR(hash))
- goto error;
- esp->auth.tfm = hash;
- if (crypto_hash_setkey(hash, x->aalg->alg_key,
- (x->aalg->alg_key_len + 7) / 8))
- goto error;
+ memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
+ p += (x->aalg->alg_key_len + 7) / 8;
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
+ err = -EINVAL;
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
- crypto_hash_digestsize(hash)) {
+ crypto_aead_authsize(aead)) {
NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
x->aalg->alg_name,
- crypto_hash_digestsize(hash),
+ crypto_aead_authsize(aead),
aalg_desc->uinfo.auth.icv_fullbits/8);
- goto error;
+ goto free_key;
}
- esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
- esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
-
- esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);
- if (!esp->auth.work_icv)
- goto error;
+ err = crypto_aead_setauthsize(
+ aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
+ if (err)
+ goto free_key;
}
- tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- goto error;
- esp->conf.tfm = tfm;
- esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
- esp->conf.padlen = 0;
- if (esp->conf.ivlen) {
- esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
- if (unlikely(esp->conf.ivec == NULL))
- goto error;
- esp->conf.ivinitted = 0;
- }
- if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key,
- (x->ealg->alg_key_len + 7) / 8))
+ esp->padlen = 0;
+
+ param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
+ memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
+
+ err = crypto_aead_setkey(aead, key, keylen);
+
+free_key:
+ kfree(key);
+
+ if (err)
goto error;
- x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
+
+ x->props.header_len = sizeof(struct ip_esp_hdr) +
+ crypto_aead_ivsize(aead);
if (x->props.mode == XFRM_MODE_TUNNEL)
x->props.header_len += sizeof(struct iphdr);
else if (x->props.mode == XFRM_MODE_BEET)
@@ -429,18 +518,16 @@ static int esp_init_state(struct xfrm_state *x)
break;
}
}
- x->data = esp;
- align = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
- if (esp->conf.padlen)
- align = max_t(u32, align, esp->conf.padlen);
- x->props.trailer_len = align + 1 + esp->auth.icv_trunc_len;
+
+ align = ALIGN(crypto_aead_blocksize(aead), 4);
+ if (esp->padlen)
+ align = max_t(u32, align, esp->padlen);
+ x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead);
return 0;
error:
- x->data = esp;
esp_destroy(x);
- x->data = NULL;
- return -EINVAL;
+ return err;
}
static struct xfrm_type esp_type =
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index bb0e562..d8c1619 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -24,13 +24,14 @@
* This file is derived from net/ipv4/esp.c
*/
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
#include <linux/err.h>
#include <linux/module.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/esp.h>
#include <linux/scatterlist.h>
-#include <linux/crypto.h>
#include <linux/kernel.h>
#include <linux/pfkeyv2.h>
#include <linux/random.h>
@@ -40,17 +41,88 @@
#include <net/protocol.h>
#include <linux/icmpv6.h>
+struct esp_skb_cb {
+ struct xfrm_skb_cb xfrm;
+ void *tmp;
+};
+
+#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
+
+/*
+ * Allocate an AEAD request structure with extra space for SG and IV.
+ *
+ * For alignment considerations the IV is placed at the front, followed
+ * by the request and finally the SG list.
+ *
+ * TODO: Use spare space in skb for this where possible.
+ */
+static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
+{
+ unsigned int len;
+
+ len = crypto_aead_ivsize(aead);
+ if (len) {
+ len += crypto_aead_alignmask(aead) &
+ ~(crypto_tfm_ctx_alignment() - 1);
+ len = ALIGN(len, crypto_tfm_ctx_alignment());
+ }
+
+ len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
+ len = ALIGN(len, __alignof__(struct scatterlist));
+
+ len += sizeof(struct scatterlist *) * nfrags;
+
+ return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp)
+{
+ return crypto_aead_ivsize(aead) ?
+ PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp;
+}
+
+static inline struct aead_givcrypt_request *esp_tmp_req(
+ struct crypto_aead *aead, u8 *iv)
+{
+ struct aead_givcrypt_request *req;
+
+ req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
+ crypto_tfm_ctx_alignment());
+ aead_givcrypt_set_tfm(req, aead);
+ return req;
+}
+
+static inline struct scatterlist *esp_tmp_sg(struct crypto_aead *aead,
+ struct aead_givcrypt_request *req)
+{
+ return (void *)ALIGN((unsigned long)(req + 1) +
+ crypto_aead_reqsize(aead),
+ __alignof__(struct scatterlist));
+}
+
+static void esp_output_done(struct crypto_async_request *base, int err)
+{
+ struct sk_buff *skb = base->data;
+
+ kfree(ESP_SKB_CB(skb)->tmp);
+ xfrm_output_resume(skb, err);
+}
+
static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
struct ip_esp_hdr *esph;
- struct crypto_blkcipher *tfm;
- struct blkcipher_desc desc;
+ struct crypto_aead *aead;
+ struct aead_givcrypt_request *req;
+ struct scatterlist *sg;
+ struct scatterlist *asg;
struct sk_buff *trailer;
+ void *tmp;
int blksize;
int clen;
int alen;
int nfrags;
+ u8 *iv;
u8 *tail;
struct esp_data *esp = x->data;
@@ -60,19 +132,27 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
/* Round to block size */
clen = skb->len;
- alen = esp->auth.icv_trunc_len;
- tfm = esp->conf.tfm;
- desc.tfm = tfm;
- desc.flags = 0;
- blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+ aead = esp->aead;
+ alen = crypto_aead_authsize(aead);
+
+ blksize = ALIGN(crypto_aead_blocksize(aead), 4);
clen = ALIGN(clen + 2, blksize);
- if (esp->conf.padlen)
- clen = ALIGN(clen, esp->conf.padlen);
+ if (esp->padlen)
+ clen = ALIGN(clen, esp->padlen);
if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) {
goto error;
}
+ tmp = esp_alloc_tmp(aead, nfrags + 1);
+ if (!tmp)
+ goto error;
+
+ iv = esp_tmp_iv(aead, tmp);
+ req = esp_tmp_req(aead, iv);
+ asg = esp_tmp_sg(aead, req);
+ sg = asg + 1;
+
/* Fill padding... */
tail = skb_tail_pointer(trailer);
do {
@@ -81,86 +161,105 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
tail[i] = i + 1;
} while (0);
tail[clen-skb->len - 2] = (clen - skb->len) - 2;
- pskb_put(skb, trailer, clen - skb->len);
+ tail[clen - skb->len - 1] = *skb_mac_header(skb);
+ pskb_put(skb, trailer, clen - skb->len + alen);
skb_push(skb, -skb_network_offset(skb));
esph = ip_esp_hdr(skb);
- *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb);
*skb_mac_header(skb) = IPPROTO_ESP;
esph->spi = x->id.spi;
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq);
- spin_lock_bh(&x->lock);
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg,
+ esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
+ clen + alen);
+ sg_init_one(asg, esph, sizeof(*esph));
- if (esp->conf.ivlen) {
- if (unlikely(!esp->conf.ivinitted)) {
- get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
- esp->conf.ivinitted = 1;
- }
- crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
- }
+ aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
+ aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
+ aead_givcrypt_set_assoc(req, asg, sizeof(*esph));
+ aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq);
- do {
- struct scatterlist *sg = &esp->sgbuf[0];
+ ESP_SKB_CB(skb)->tmp = tmp;
+ err = crypto_aead_givencrypt(req);
+ if (err != -EINPROGRESS)
+ kfree(tmp);
- if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
- sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
- if (!sg)
- goto unlock;
- }
- sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg,
- esph->enc_data +
- esp->conf.ivlen -
- skb->data, clen);
- err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
- if (unlikely(sg != &esp->sgbuf[0]))
- kfree(sg);
- } while (0);
+error:
+ return err;
+}
+
+static int esp_input_done2(struct sk_buff *skb, int err)
+{
+ struct xfrm_state *x = xfrm_input_state(skb);
+ struct esp_data *esp = x->data;
+ struct crypto_aead *aead = esp->aead;
+ int alen = crypto_aead_authsize(aead);
+ int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
+ int elen = skb->len - hlen;
+ int hdr_len = skb_network_header_len(skb);
+ int padlen;
+ u8 nexthdr[2];
+
+ kfree(ESP_SKB_CB(skb)->tmp);
if (unlikely(err))
- goto unlock;
+ goto out;
- if (esp->conf.ivlen) {
- memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
- crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
- }
+ if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
+ BUG();
- if (esp->auth.icv_full_len) {
- err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
- sizeof(*esph) + esp->conf.ivlen + clen);
- memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
+ err = -EINVAL;
+ padlen = nexthdr[0];
+ if (padlen + 2 + alen >= elen) {
+ LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage "
+ "padlen=%d, elen=%d\n", padlen + 2, elen);
+ goto out;
}
-unlock:
- spin_unlock_bh(&x->lock);
+ /* ... check padding bits here. Silly. :-) */
-error:
+ pskb_trim(skb, skb->len - alen - padlen - 2);
+ __skb_pull(skb, hlen);
+ skb_set_transport_header(skb, -hdr_len);
+
+ return nexthdr[1];
+
+out:
return err;
}
+static void esp_input_done(struct crypto_async_request *base, int err)
+{
+ struct sk_buff *skb = base->data;
+
+ xfrm_input_resume(skb, esp_input_done2(skb, err));
+}
+
static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
{
- struct ipv6hdr *iph;
struct ip_esp_hdr *esph;
struct esp_data *esp = x->data;
- struct crypto_blkcipher *tfm = esp->conf.tfm;
- struct blkcipher_desc desc = { .tfm = tfm };
+ struct crypto_aead *aead = esp->aead;
+ struct aead_givcrypt_request *greq;
+ struct aead_request *req;
struct sk_buff *trailer;
- int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
- int alen = esp->auth.icv_trunc_len;
- int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen;
- int hdr_len = skb_network_header_len(skb);
+ int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
int nfrags;
int ret = 0;
+ void *tmp;
+ u8 *iv;
+ struct scatterlist *sg;
+ struct scatterlist *asg;
if (!pskb_may_pull(skb, sizeof(*esph))) {
ret = -EINVAL;
goto out;
}
- if (elen <= 0 || (elen & (blksize-1))) {
+ if (elen <= 0) {
ret = -EINVAL;
goto out;
}
@@ -170,80 +269,39 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
goto out;
}
- skb->ip_summed = CHECKSUM_NONE;
-
- spin_lock(&x->lock);
-
- /* If integrity check is required, do this. */
- if (esp->auth.icv_full_len) {
- u8 sum[alen];
-
- ret = esp_mac_digest(esp, skb, 0, skb->len - alen);
- if (ret)
- goto unlock;
+ ret = -ENOMEM;
+ tmp = esp_alloc_tmp(aead, nfrags + 1);
+ if (!tmp)
+ goto out;
- if (skb_copy_bits(skb, skb->len - alen, sum, alen))
- BUG();
+ ESP_SKB_CB(skb)->tmp = tmp;
+ iv = esp_tmp_iv(aead, tmp);
+ greq = esp_tmp_req(aead, iv);
+ req = &greq->areq;
+ asg = esp_tmp_sg(aead, greq);
+ sg = asg + 1;
- if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
- ret = -EBADMSG;
- goto unlock;
- }
- }
+ skb->ip_summed = CHECKSUM_NONE;
esph = (struct ip_esp_hdr *)skb->data;
- iph = ipv6_hdr(skb);
/* Get ivec. This can be wrong, check against another impls. */
- if (esp->conf.ivlen)
- crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
-
- {
- struct scatterlist *sg = &esp->sgbuf[0];
-
- if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
- sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
- if (!sg) {
- ret = -ENOMEM;
- goto unlock;
- }
- }
- sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg,
- sizeof(*esph) + esp->conf.ivlen,
- elen);
- ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
- if (unlikely(sg != &esp->sgbuf[0]))
- kfree(sg);
- }
-
-unlock:
- spin_unlock(&x->lock);
-
- if (unlikely(ret))
- goto out;
+ iv = esph->enc_data;
- {
- u8 nexthdr[2];
- u8 padlen;
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
+ sg_init_one(asg, esph, sizeof(*esph));
- if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
- BUG();
+ aead_request_set_callback(req, 0, esp_input_done, skb);
+ aead_request_set_crypt(req, sg, sg, elen, iv);
+ aead_request_set_assoc(req, asg, sizeof(*esph));
- padlen = nexthdr[0];
- if (padlen+2 >= elen) {
- LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen);
- ret = -EINVAL;
- goto out;
- }
- /* ... check padding bits here. Silly. :-) */
+ ret = crypto_aead_decrypt(req);
+ if (ret == -EINPROGRESS)
+ goto out;
- pskb_trim(skb, skb->len - alen - padlen - 2);
- ret = nexthdr[1];
- }
+ ret = esp_input_done2(skb, ret);
- __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
- skb_set_transport_header(skb, -hdr_len);
out:
return ret;
}
@@ -251,11 +309,11 @@ out:
static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
{
struct esp_data *esp = x->data;
- u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
- u32 align = max_t(u32, blksize, esp->conf.padlen);
+ u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
+ u32 align = max_t(u32, blksize, esp->padlen);
u32 rem;
- mtu -= x->props.header_len + esp->auth.icv_trunc_len;
+ mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
rem = mtu & (align - 1);
mtu &= ~(align - 1);
@@ -294,81 +352,101 @@ static void esp6_destroy(struct xfrm_state *x)
if (!esp)
return;
- crypto_free_blkcipher(esp->conf.tfm);
- esp->conf.tfm = NULL;
- kfree(esp->conf.ivec);
- esp->conf.ivec = NULL;
- crypto_free_hash(esp->auth.tfm);
- esp->auth.tfm = NULL;
- kfree(esp->auth.work_icv);
- esp->auth.work_icv = NULL;
+ crypto_free_aead(esp->aead);
kfree(esp);
}
static int esp6_init_state(struct xfrm_state *x)
{
struct esp_data *esp = NULL;
- struct crypto_blkcipher *tfm;
+ struct crypto_aead *aead;
+ struct crypto_authenc_key_param *param;
+ struct rtattr *rta;
+ char *key;
+ char *p;
+ char authenc_name[CRYPTO_MAX_ALG_NAME];
+ u32 align;
+ unsigned int keylen;
+ int err;
if (x->ealg == NULL)
- goto error;
+ return -EINVAL;
if (x->encap)
- goto error;
+ return -EINVAL;
+
+ if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
+ x->aalg ? x->aalg->alg_name : "digest_null",
+ x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
esp = kzalloc(sizeof(*esp), GFP_KERNEL);
if (esp == NULL)
return -ENOMEM;
+ x->data = esp;
+
+ aead = crypto_alloc_aead(authenc_name, 0, 0);
+ err = PTR_ERR(aead);
+ if (IS_ERR(aead))
+ goto error;
+
+ esp->aead = aead;
+
+ keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
+ (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
+ err = -ENOMEM;
+ key = kmalloc(keylen, GFP_KERNEL);
+ if (!key)
+ goto error;
+
+ p = key;
+ rta = (void *)p;
+ rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
+ rta->rta_len = RTA_LENGTH(sizeof(*param));
+ param = RTA_DATA(rta);
+ p += RTA_SPACE(sizeof(*param));
+
if (x->aalg) {
struct xfrm_algo_desc *aalg_desc;
- struct crypto_hash *hash;
-
- hash = crypto_alloc_hash(x->aalg->alg_name, 0,
- CRYPTO_ALG_ASYNC);
- if (IS_ERR(hash))
- goto error;
- esp->auth.tfm = hash;
- if (crypto_hash_setkey(hash, x->aalg->alg_key,
- (x->aalg->alg_key_len + 7) / 8))
- goto error;
+ memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
+ p += (x->aalg->alg_key_len + 7) / 8;
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
+ err = -EINVAL;
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
- crypto_hash_digestsize(hash)) {
+ crypto_aead_authsize(aead)) {
NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
x->aalg->alg_name,
- crypto_hash_digestsize(hash),
+ crypto_aead_authsize(aead),
aalg_desc->uinfo.auth.icv_fullbits/8);
- goto error;
+ goto free_key;
}
- esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
- esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
-
- esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);
- if (!esp->auth.work_icv)
- goto error;
+ err = crypto_aead_setauthsize(
+ aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
+ if (err)
+ goto free_key;
}
- tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- goto error;
- esp->conf.tfm = tfm;
- esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
- esp->conf.padlen = 0;
- if (esp->conf.ivlen) {
- esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
- if (unlikely(esp->conf.ivec == NULL))
- goto error;
- esp->conf.ivinitted = 0;
- }
- if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key,
- (x->ealg->alg_key_len + 7) / 8))
+
+ esp->padlen = 0;
+
+ param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
+ memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
+
+ err = crypto_aead_setkey(aead, key, keylen);
+
+free_key:
+ kfree(key);
+
+ if (err)
goto error;
- x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
+
+ x->props.header_len = sizeof(struct ip_esp_hdr) +
+ crypto_aead_ivsize(aead);
switch (x->props.mode) {
case XFRM_MODE_BEET:
case XFRM_MODE_TRANSPORT:
@@ -379,14 +457,16 @@ static int esp6_init_state(struct xfrm_state *x)
default:
goto error;
}
- x->data = esp;
+
+ align = ALIGN(crypto_aead_blocksize(aead), 4);
+ if (esp->padlen)
+ align = max_t(u32, align, esp->padlen);
+ x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead);
return 0;
error:
- x->data = esp;
esp6_destroy(x);
- x->data = NULL;
- return -EINVAL;
+ return err;
}
static struct xfrm_type esp6_type =
^ permalink raw reply related
* [PATCH 3/3] [IPSEC]: Add support for combined mode algorithms
From: Herbert Xu @ 2007-12-11 4:23 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20071211042312.GA10911@gondor.apana.org.au>
[IPSEC]: Add support for combined mode algorithms
This patch adds support for combined mode algorithms with GCM being the
first algorithm supported.
Combined mode algorithms can be added through the xfrm_user interface
using the new algorithm payload type XFRMA_ALG_AEAD. Each algorithms
is identified by its name and the ICV length.
For the purposes of matching algorithms in xfrm_tmpl structures, combined
mode algorithms are occupy the same name space as encryption algorithms.
This is in line with how they are negotiated using IKE.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/linux/pfkeyv2.h | 3 +
include/linux/xfrm.h | 8 ++++
include/net/xfrm.h | 16 ++++++++
net/ipv4/esp4.c | 71 ++++++++++++++++++++++++++++++-------
net/ipv6/esp6.c | 77 ++++++++++++++++++++++++++++++++---------
net/xfrm/xfrm_algo.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++
net/xfrm/xfrm_user.c | 69 +++++++++++++++++++++++++++++++++++-
7 files changed, 303 insertions(+), 31 deletions(-)
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index d9db5f6..fb4649e 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -298,6 +298,9 @@ struct sadb_x_sec_ctx {
#define SADB_X_EALG_BLOWFISHCBC 7
#define SADB_EALG_NULL 11
#define SADB_X_EALG_AESCBC 12
+#define SADB_X_EALG_AES_GCM_ICV8 18
+#define SADB_X_EALG_AES_GCM_ICV12 19
+#define SADB_X_EALG_AES_GCM_ICV16 20
#define SADB_X_EALG_CAMELLIACBC 22
#define SADB_EALG_MAX 253 /* last EALG */
/* private allocations should use 249-255 (RFC2407) */
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index b58adc5..df2e62a 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -96,6 +96,13 @@ struct xfrm_algo {
char alg_key[0];
};
+struct xfrm_algo_aead {
+ char alg_name[64];
+ int alg_key_len; /* in bits */
+ int alg_icv_len; /* in bits */
+ char alg_key[0];
+};
+
struct xfrm_stats {
__u32 replay_window;
__u32 replay;
@@ -269,6 +276,7 @@ enum xfrm_attr_type_t {
XFRMA_LASTUSED,
XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */
XFRMA_MIGRATE,
+ XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */
__XFRMA_MAX
#define XFRMA_MAX (__XFRMA_MAX - 1)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index c49fe0f..92ee8e5 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -145,6 +145,7 @@ struct xfrm_state
struct xfrm_algo *aalg;
struct xfrm_algo *ealg;
struct xfrm_algo *calg;
+ struct xfrm_algo_aead *aead;
/* Data for encapsulator */
struct xfrm_encap_tmpl *encap;
@@ -1021,6 +1022,10 @@ static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
/*
* xfrm algorithm information
*/
+struct xfrm_algo_aead_info {
+ u16 icv_truncbits;
+};
+
struct xfrm_algo_auth_info {
u16 icv_truncbits;
u16 icv_fullbits;
@@ -1035,11 +1040,20 @@ struct xfrm_algo_comp_info {
u16 threshold;
};
+enum {
+ XFRM_ALGO_AEAD,
+ XFRM_ALGO_AUTH,
+ XFRM_ALGO_ENCR,
+ XFRM_ALGO_COMP,
+};
+
struct xfrm_algo_desc {
char *name;
char *compat;
u8 available:1;
+ u16 type;
union {
+ struct xfrm_algo_aead_info aead;
struct xfrm_algo_auth_info auth;
struct xfrm_algo_encr_info encr;
struct xfrm_algo_comp_info comp;
@@ -1241,6 +1255,8 @@ extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id);
extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
+extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len,
+ int probe);
struct hash_desc;
struct scatterlist;
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index c1f5936..45fa230 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -412,32 +412,53 @@ static void esp_destroy(struct xfrm_state *x)
kfree(esp);
}
-static int esp_init_state(struct xfrm_state *x)
+static int esp_init_aead(struct xfrm_state *x)
{
- struct esp_data *esp = NULL;
+ struct esp_data *esp = x->data;
+ struct crypto_aead *aead;
+ int err;
+
+ aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
+ err = PTR_ERR(aead);
+ if (IS_ERR(aead))
+ goto error;
+
+ esp->aead = aead;
+
+ err = crypto_aead_setkey(aead, x->aead->alg_key,
+ (x->aead->alg_key_len + 7) / 8);
+ if (err)
+ goto error;
+
+ err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
+ if (err)
+ goto error;
+
+error:
+ return err;
+}
+
+static int esp_init_authenc(struct xfrm_state *x)
+{
+ struct esp_data *esp = x->data;
struct crypto_aead *aead;
struct crypto_authenc_key_param *param;
struct rtattr *rta;
char *key;
char *p;
char authenc_name[CRYPTO_MAX_ALG_NAME];
- u32 align;
unsigned int keylen;
int err;
+ err = -EINVAL;
if (x->ealg == NULL)
- return -EINVAL;
+ goto error;
+ err = -ENAMETOOLONG;
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
- return -ENAMETOOLONG;
-
- esp = kzalloc(sizeof(*esp), GFP_KERNEL);
- if (esp == NULL)
- return -ENOMEM;
-
- x->data = esp;
+ goto error;
aead = crypto_alloc_aead(authenc_name, 0, 0);
err = PTR_ERR(aead);
@@ -485,8 +506,6 @@ static int esp_init_state(struct xfrm_state *x)
goto free_key;
}
- esp->padlen = 0;
-
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
@@ -495,9 +514,35 @@ static int esp_init_state(struct xfrm_state *x)
free_key:
kfree(key);
+error:
+ return err;
+}
+
+static int esp_init_state(struct xfrm_state *x)
+{
+ struct esp_data *esp;
+ struct crypto_aead *aead;
+ u32 align;
+ int err;
+
+ esp = kzalloc(sizeof(*esp), GFP_KERNEL);
+ if (esp == NULL)
+ return -ENOMEM;
+
+ x->data = esp;
+
+ if (x->aead)
+ err = esp_init_aead(x);
+ else
+ err = esp_init_authenc(x);
+
if (err)
goto error;
+ aead = esp->aead;
+
+ esp->padlen = 0;
+
x->props.header_len = sizeof(struct ip_esp_hdr) +
crypto_aead_ivsize(aead);
if (x->props.mode == XFRM_MODE_TUNNEL)
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index d8c1619..84fe594 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -356,35 +356,53 @@ static void esp6_destroy(struct xfrm_state *x)
kfree(esp);
}
-static int esp6_init_state(struct xfrm_state *x)
+static int esp_init_aead(struct xfrm_state *x)
+{
+ struct esp_data *esp = x->data;
+ struct crypto_aead *aead;
+ int err;
+
+ aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
+ err = PTR_ERR(aead);
+ if (IS_ERR(aead))
+ goto error;
+
+ esp->aead = aead;
+
+ err = crypto_aead_setkey(aead, x->aead->alg_key,
+ (x->aead->alg_key_len + 7) / 8);
+ if (err)
+ goto error;
+
+ err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
+ if (err)
+ goto error;
+
+error:
+ return err;
+}
+
+static int esp_init_authenc(struct xfrm_state *x)
{
- struct esp_data *esp = NULL;
+ struct esp_data *esp = x->data;
struct crypto_aead *aead;
struct crypto_authenc_key_param *param;
struct rtattr *rta;
char *key;
char *p;
char authenc_name[CRYPTO_MAX_ALG_NAME];
- u32 align;
unsigned int keylen;
int err;
+ err = -EINVAL;
if (x->ealg == NULL)
- return -EINVAL;
-
- if (x->encap)
- return -EINVAL;
+ goto error;
+ err = -ENAMETOOLONG;
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
- return -ENAMETOOLONG;
-
- esp = kzalloc(sizeof(*esp), GFP_KERNEL);
- if (esp == NULL)
- return -ENOMEM;
-
- x->data = esp;
+ goto error;
aead = crypto_alloc_aead(authenc_name, 0, 0);
err = PTR_ERR(aead);
@@ -432,8 +450,6 @@ static int esp6_init_state(struct xfrm_state *x)
goto free_key;
}
- esp->padlen = 0;
-
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
@@ -442,9 +458,38 @@ static int esp6_init_state(struct xfrm_state *x)
free_key:
kfree(key);
+error:
+ return err;
+}
+
+static int esp6_init_state(struct xfrm_state *x)
+{
+ struct esp_data *esp;
+ struct crypto_aead *aead;
+ u32 align;
+ int err;
+
+ if (x->encap)
+ return -EINVAL;
+
+ esp = kzalloc(sizeof(*esp), GFP_KERNEL);
+ if (esp == NULL)
+ return -ENOMEM;
+
+ x->data = esp;
+
+ if (x->aead)
+ err = esp_init_aead(x);
+ else
+ err = esp_init_authenc(x);
+
if (err)
goto error;
+ aead = esp->aead;
+
+ esp->padlen = 0;
+
x->props.header_len = sizeof(struct ip_esp_hdr) +
crypto_aead_ivsize(aead);
switch (x->props.mode) {
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index ae34a12..259e61e 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -28,6 +28,57 @@
* that instantiated crypto transforms have correct parameters for IPsec
* purposes.
*/
+static struct xfrm_algo_desc aead_list[] = {
+{
+ .name = "gcm(aes)",
+
+ .uinfo = {
+ .aead = {
+ .icv_truncbits = 64,
+ }
+ },
+
+ .desc = {
+ .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8,
+ .sadb_alg_ivlen = 8,
+ .sadb_alg_minbits = 128,
+ .sadb_alg_maxbits = 256
+ }
+},
+{
+ .name = "gcm(aes)",
+
+ .uinfo = {
+ .aead = {
+ .icv_truncbits = 96,
+ }
+ },
+
+ .desc = {
+ .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12,
+ .sadb_alg_ivlen = 8,
+ .sadb_alg_minbits = 128,
+ .sadb_alg_maxbits = 256
+ }
+},
+{
+ .name = "gcm(aes)",
+
+ .uinfo = {
+ .aead = {
+ .icv_truncbits = 128,
+ }
+ },
+
+ .desc = {
+ .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16,
+ .sadb_alg_ivlen = 8,
+ .sadb_alg_minbits = 128,
+ .sadb_alg_maxbits = 256
+ }
+},
+};
+
static struct xfrm_algo_desc aalg_list[] = {
{
.name = "hmac(digest_null)",
@@ -332,6 +383,11 @@ static struct xfrm_algo_desc calg_list[] = {
},
};
+static inline int aead_entries(void)
+{
+ return ARRAY_SIZE(aead_list);
+}
+
static inline int aalg_entries(void)
{
return ARRAY_SIZE(aalg_list);
@@ -354,6 +410,13 @@ struct xfrm_algo_list {
u32 mask;
};
+static const struct xfrm_algo_list xfrm_aead_list = {
+ .algs = aead_list,
+ .entries = ARRAY_SIZE(aead_list),
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .mask = CRYPTO_ALG_TYPE_MASK,
+};
+
static const struct xfrm_algo_list xfrm_aalg_list = {
.algs = aalg_list,
.entries = ARRAY_SIZE(aalg_list),
@@ -461,6 +524,33 @@ struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)
}
EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
+struct xfrm_aead_name {
+ const char *name;
+ int icvbits;
+};
+
+static int xfrm_aead_name_match(const struct xfrm_algo_desc *entry,
+ const void *data)
+{
+ const struct xfrm_aead_name *aead = data;
+ const char *name = aead->name;
+
+ return aead->icvbits == entry->uinfo.aead.icv_truncbits && name &&
+ !strcmp(name, entry->name);
+}
+
+struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len, int probe)
+{
+ struct xfrm_aead_name data = {
+ .name = name,
+ .icvbits = icv_len * 8,
+ };
+
+ return xfrm_find_algo(&xfrm_aead_list, xfrm_aead_name_match, &data,
+ probe);
+}
+EXPORT_SYMBOL_GPL(xfrm_aead_get_byname);
+
struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
{
if (idx >= aalg_entries())
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 2403788..6ad1f11 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -36,6 +36,11 @@ static inline int alg_len(struct xfrm_algo *alg)
return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
}
+static inline int aead_len(struct xfrm_algo_aead *alg)
+{
+ return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
{
struct nlattr *rt = attrs[type];
@@ -61,6 +66,8 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
return -EINVAL;
break;
+ case XFRMA_ALG_AEAD:
+ /* Zero length keys will be picked up by init_state. */
case XFRMA_ALG_COMP:
/* Zero length keys are legal. */
break;
@@ -73,6 +80,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
return 0;
}
+static int verify_aead(struct nlattr **attrs)
+{
+ struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
+ struct xfrm_algo_aead *algp;
+
+ if (!rt)
+ return 0;
+
+ algp = nla_data(rt);
+ if (nla_len(rt) < aead_len(algp))
+ return -EINVAL;
+
+ algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
+ return 0;
+}
+
static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
xfrm_address_t **addrp)
{
@@ -124,20 +147,28 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
switch (p->id.proto) {
case IPPROTO_AH:
if (!attrs[XFRMA_ALG_AUTH] ||
+ attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ALG_COMP])
goto out;
break;
case IPPROTO_ESP:
+ if (attrs[XFRMA_ALG_COMP])
+ goto out;
if ((!attrs[XFRMA_ALG_AUTH] &&
- !attrs[XFRMA_ALG_CRYPT]) ||
- attrs[XFRMA_ALG_COMP])
+ !attrs[XFRMA_ALG_CRYPT] &&
+ !attrs[XFRMA_ALG_AEAD]))
goto out;
+ if ((attrs[XFRMA_ALG_AUTH] ||
+ attrs[XFRMA_ALG_CRYPT]) &&
+ attrs[XFRMA_ALG_AEAD])
+ goto out;
break;
case IPPROTO_COMP:
if (!attrs[XFRMA_ALG_COMP] ||
+ attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_AUTH] ||
attrs[XFRMA_ALG_CRYPT])
goto out;
@@ -148,6 +179,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
case IPPROTO_ROUTING:
if (attrs[XFRMA_ALG_COMP] ||
attrs[XFRMA_ALG_AUTH] ||
+ attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ENCAP] ||
attrs[XFRMA_SEC_CTX] ||
@@ -160,6 +192,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
goto out;
}
+ if ((err = verify_aead(attrs)))
+ goto out;
if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
goto out;
if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
@@ -213,6 +247,31 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
return 0;
}
+static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
+ struct nlattr *rta)
+{
+ struct xfrm_algo_aead *p, *ualg;
+ struct xfrm_algo_desc *algo;
+
+ if (!rta)
+ return 0;
+
+ ualg = nla_data(rta);
+
+ algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
+ if (!algo)
+ return -ENOSYS;
+ *props = algo->desc.sadb_alg_id;
+
+ p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ strcpy(p->alg_name, algo->name);
+ *algpp = p;
+ return 0;
+}
+
static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
{
int len = 0;
@@ -291,6 +350,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
copy_from_user_state(x, p);
+ if ((err = attach_aead(&x->aead, &x->props.ealgo,
+ attrs[XFRMA_ALG_AEAD])))
+ goto error;
if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
xfrm_aalg_get_byname,
attrs[XFRMA_ALG_AUTH])))
@@ -515,6 +577,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
if (x->lastused)
NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
+ if (x->aead)
+ NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
if (x->aalg)
NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg);
if (x->ealg)
@@ -1813,6 +1877,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
#undef XMSGSIZE
static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
+ [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) },
[XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) },
[XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) },
[XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) },
^ permalink raw reply related
* [PATCH] NETLINK : kzalloc() conversion
From: Eric Dumazet @ 2007-12-11 5:40 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
[-- Attachment #1: Type: text/plain, Size: 157 bytes --]
nl_pid_hash_alloc() is renamed to nl_pid_hash_zalloc().
It is now returning zeroed memory to its callers.
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
[-- Attachment #2: netlink.patch --]
[-- Type: text/plain, Size: 1574 bytes --]
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 2e02b19..dbd7cad 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -237,13 +237,14 @@ found:
return sk;
}
-static inline struct hlist_head *nl_pid_hash_alloc(size_t size)
+static inline struct hlist_head *nl_pid_hash_zalloc(size_t size)
{
if (size <= PAGE_SIZE)
- return kmalloc(size, GFP_ATOMIC);
+ return kzalloc(size, GFP_ATOMIC);
else
return (struct hlist_head *)
- __get_free_pages(GFP_ATOMIC, get_order(size));
+ __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
+ get_order(size));
}
static inline void nl_pid_hash_free(struct hlist_head *table, size_t size)
@@ -272,11 +273,10 @@ static int nl_pid_hash_rehash(struct nl_pid_hash *hash, int grow)
size *= 2;
}
- table = nl_pid_hash_alloc(size);
+ table = nl_pid_hash_zalloc(size);
if (!table)
return 0;
- memset(table, 0, size);
otable = hash->table;
hash->table = table;
hash->mask = mask;
@@ -1919,7 +1919,7 @@ static int __init netlink_proto_init(void)
for (i = 0; i < MAX_LINKS; i++) {
struct nl_pid_hash *hash = &nl_table[i].hash;
- hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table));
+ hash->table = nl_pid_hash_zalloc(1 * sizeof(*hash->table));
if (!hash->table) {
while (i-- > 0)
nl_pid_hash_free(nl_table[i].hash.table,
@@ -1927,7 +1927,6 @@ static int __init netlink_proto_init(void)
kfree(nl_table);
goto panic;
}
- memset(hash->table, 0, 1 * sizeof(*hash->table));
hash->max_shift = order;
hash->shift = 0;
hash->mask = 0;
^ permalink raw reply related
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