This patch adds the Kernel support for the caam-keygen user-space
application. It has two IOCTL calls for key and blob generation and
import a black key from a blob.
This support is included in CRYPTO_DEV_FSL_CAAM_TK_API (tagged key
support).
Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com>
Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
CAAM's Black Key mechanism is intended for protection
of user keys against bus snooping. This automatically
encapsulates and decapsulates cryptographic keys ''on-the-fly''
in an encrypted data structure called a Black Key.
Before a value is copied from a Key Register to memory,
CAAM will automatically encrypt the key as a Black Key
(encrypted key) using the current value in the JDKEKR or
TDKEKR as the encryption key.
CAAM's built-in Blob Protocol provides a method for protecting
user-defined data across system power cycles. CAAM protects data
in a data structure called a Blob, which provides both confidentiality
and integrity protection. The data to be protected is encrypted so that
it can be safely placed into non-volatile storage before the SoC is
powered down.
This patch includes the support to generate a black key from random or
from a plaintext. Also one can encapsulate it into a blob or decapsulate
a black key from a blob.
The key and blob generation descriptors are exported into a separate file,
such that they could be shared with other interfaces (qi, qi2).
This feature has support only for black keys, encapsulated in
black blobs in General Memory.
In caamkeyblob_test.c file is a test that validates the above
operations: create a black key from plaintext or from random,
encapsulate and decapsulate a blob and compare the obtained black key.
This test is configured as a kernel module.
Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com>
Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
Tagged keys are keys that contain metadata indicating what
they are and how to handle them using the new added tag_object API.
A tag object represents the metadata (or simply a header/configuration)
and the actual data (e.g. black key) obtained from hardware.
The support, for tagged keys, to skcipher algorithms, is done by
adding new transformations, with tk prefix to distinguish
between plaintext and tagged keys.
The tk_ transformations can be used directly by their name:
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "skcipher", /* this selects the symmetric cipher */
.salg_name = "tk(cbc(aes))" /* this is the cipher name */
};
or for dm-crypt, e.g. using dmsetup:
dmsetup -v create encrypted --table "0 $(blockdev --getsz /dev/mmcblk2p10)
crypt capi:tk(cbc(aes))-plain :32:logon:seckey 0 /dev/mmcblk2p10 0 1
sector_size:512".
tk_ transformations will know how to handle tagged keys, by loading the
proper settings for KEY command.
The API expects that the object (the actual data) from a tag object
to be a buffer (defined by address and size).
Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com>
Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
Configuring both caam/jr and snvs/secvio drivers as modules:
CONFIG_CRYPTO_DEV_FSL_CAAM_JR=m
CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=m
fails with:
drivers/crypto/caam/secvio.o: In function `snvs_secvio_driver_init':
drivers/crypto/caam/secvio.c:339: multiple definition of `init_module'
drivers/crypto/caam/jr.o:drivers/crypto/caam/jr.c:854: first defined here
drivers/crypto/caam/secvio.o: In function `snvs_secvio_install_handler':
drivers/crypto/caam/secvio.c:137: multiple definition of `cleanup_module'
drivers/crypto/caam/jr.o:drivers/crypto/caam/jr.c:71: first defined here
scripts/Makefile.build:439: recipe for target 'drivers/crypto/caam/caam_jr.o' failed
make[3]: *** [drivers/crypto/caam/caam_jr.o] Error 1
This is due to trying to link two platform drivers in the same
"composite" object.
Since in fact snvs/secvio driver does not depend on caam/jr
(and should not depend on the other caam drivers in general [*]),
and to keep the fix small [**], avoid linking snvs/secvio with caam/jr.
[*] Currently the only dependency is related to I/O accessors (regs.h)
and endianness detection (ctrl.c).
From this perspective, it's important for caam controller driver
(ctrl.c) to probe before snvs/secvio driver.
[**] The proper solution would be splitting snvs/secvio from caam
(drivers, DT bindings etc.), since snvs is just a "companion module"
of caam.
Fixes: f50dd756a0 ("MLKU-38-3 crypto: caam - add SNVS / SECVIO support")
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Reviewed-by: Iuliana Prodan <iuliana.prodan@nxp.com>
Commit 77debf316c44 ("LFV-26 crypto: caam - fix Secure Memory driver init")
addressed SM driver initialization and also update SM test.
However, the fix for SM test is insufficient.
There are cases when SM test runs before SM driver, causing a crash
due to uninitialized "priv" pointer being dereferenced.
The fix consists in the following:
1. Since SM test is a "bare" device driver (doesn't sit on any bus),
there is no deferred probing support.
Thus we have no choice (*) but to abort SM tests with a notification.
(*) We don't want to force SM driver running first by means of
init levels etc. Just KISS.
2. SM test driver forced to being built only as a module
Since SM test driver's only goal is to run SM tests, it doesn't make
any sense to be built-in.
Building the driver as a module allows for running the tests
several times if needed (multiple modprobe & rmmod cycles).
Note: from the perspective of wanting to test repetitively, it would
make sense to force module unloading by returning an error code
in the module_init function.
However, this might affect test scripts (due to error code and/or
message output by unsuccessful module loading), so we postpone
this change for now.
Fixes: d02fe599d7d5 ("MLKU-25-3 crypto: caam - add Secure Memory support")
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Acked-by: Leonard Crestez <leonard.crestez@nxp.com>
This patch add the support for job ring UIO so
that userspace drivers can have access to the
caam job rings
Signed-off-by: Sandeep Malik <Sandeep.Malik@nxp.com>
Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
A tagged key is a key which has been tagged with metadata
using tag_object.h API.
We add the support for these keys to caamalg.
For each algo of caamalg which supports tagged keys , it is done by:
- Creating a modified version of the algo
- Registering the modified version
- When the modified transform is used, it gets
the load parameter of the key.
Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
(cherry picked from commit 88dee97d985890dbf37cafa7934c476d0ecfd0b3)
(Vipul: Fixed merge conflicts)
Conflicts:
drivers/crypto/caam/caamalg.c
Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
(cherry picked from commit 5adebac40a7a8065c074f4a69f4ad760c67233f5)
-port from ablkcipher to current skcipher implementation
-since in linux-imx true key_inline was always true: a. simplify
the descriptors and b. use key_cmd_opt to differentiate b/w tk and non-tk
cases
-change commit headline prefix
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Add functions to tag an object with metadata(configuration).
It is possible to:
- create metadata:
- init_tag_object_header
- init_blackey_conf
- set_tag_object_conf
- retrieve metadata:
- get_tag_object_conf
- get_blackey_conf
The API expects an object to be a space a memory
with an address and a size.
The implementation of the tag is currently exposed
but users shouldn't access it directly, they should
use the functions provided.
Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
(cherry picked from commit ebbb132da8e7f9de7f3d375eff8d87f684feb1eb)
Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
(cherry picked from commit 8b6f6b4474be33ee271dfe2cce79f9f6335733aa)
-make tag functionality depend on JR
-change commit headline prefix
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
This is a squash of the following i.MX BSP commits
(rel_imx_4.19.35_1.1.0_rc2)
1. 8f6a17b41917 ("ENGR00289885 [iMX6Q] Add Secure Memory and SECVIO support.")
2. 8433c811e97a ("MLK-9710-18 snvs - make SECVIO module device tree correct")
3. 35bbc34e996b ("MLK-9769-23 Replace SECVIO of_irq_to_resource() with irq_of_parse_and_map()")
4. 3ac6edcd92d4 ("MLK-11360-01 crypto: caam_snvs: add snvs clock management")
5. 9d9ca7a03e3b ("MLK-11922 i.mx6: Linux 3.14.28 CAAM & SNVS enabled by default. JTAG, DS-5 attachment causes exceptions")
6. fcdaabf1bba2 ("MLK-17412-01: Fix secvio driver to have same driver name as DTS")
Signed-off-by: Dan Douglass <dan.douglass@nxp.com>
Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
Signed-off-by: Steve Cornelius <steve.cornelius@nxp.com>
Signed-off-by: Fugang Duan <andy.duan@nxp.com>
Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
that have been reworked:
1.
-make SM depend on JR
-enable SM, SECVIO only on i.MX SoCs
-fix resource leak - add off_node_put() where needed
Split commit in three:
- SNVS/SECVIO driver
- Secure Memory driver
- DT changes
3.
JR changes dropped - no longer needed, already upstream in
commit 549077d7d8 ("crypto: caam - check irq_of_parse_and_map for errors")
4.
Split the patch in two:
-DT bindings changes
-driver changes
5.
Fixed conflicts in imx7d.dtsi - added caam_sm and irq_sec_vio nodes.
Split commit in 3:
-SECVIO/SNVS driver changes
-SECVIO/SNVS DT changes
-Secure Memory DT changes
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Add support of printing the dpseci frame queue statistics using debugfs.
Signed-off-by: Vakul Garg <vakul.garg@nxp.com>
Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Currently we allow top level code, i.e. that which sits between the
low level (HW-specific) drivers and crypto API, to be built as several
drivers: caamalg, caamhash, caam_pkc, caamrng, caamalg_qi.
There is no advantage in this, more it interferes with adding support
for deferred probing (there are no corresponding devices and thus
no bus).
Convert these drivers and call init() / exit() manually at the right
time.
Move algorithms initialization at JR probe / remove time:
-the first probed JR registers the crypto algs
-the last removed JR unregisters the crypto algs
Note: caam_qi_init() is called before JR platform devices creation
(of_populate_bus()), such that QI interface is initialized when
the caam/qi algorithms are registered in the JR driver (by calling
caam_qi_algapi_init().
While here, fix the Kconfig entries under CRYPTO_DEV_FSL_CAAM_JR
to be aligned.
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
caam/qi2 driver will support ahash algorithms,
thus move ahash descriptors generation in a shared location.
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Add CAAM driver that works using the DPSECI backend, i.e. manages
DPSECI DPAA2 objects sitting on the Management Complex (MC) fsl-mc bus.
Data transfers (crypto requests) are sent/received to/from CAAM crypto
engine via Queue Interface (v2), this being similar to existing caam/qi.
OTOH, configuration/setup (obtaining virtual queue IDs, authorization
etc.) is done by sending commands to the MC f/w.
Note that the CAAM accelerator included in DPAA2 platforms still has
Job Rings. However, the driver being added does not handle access
via this backend. Kconfig & Makefile are updated such that DPAA2-CAAM
(a.k.a. "caam/qi2") driver does not depend on caam/jr or caam/qi
backends - which rely on platform bus support (ctrl.c).
Support for the following aead and authenc algorithms is also added
in this patch:
-aead:
gcm(aes)
rfc4106(gcm(aes))
rfc4543(gcm(aes))
-authenc:
authenc(hmac({md5,sha*}),cbc({aes,des,des3_ede}))
echainiv(authenc(hmac({md5,sha*}),cbc({aes,des,des3_ede})))
authenc(hmac({md5,sha*}),rfc3686(ctr(aes))
seqiv(authenc(hmac({md5,sha*}),rfc3686(ctr(aes)))
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Add support to submit ablkcipher and authenc algorithms
via the QI backend:
-ablkcipher:
cbc({aes,des,des3_ede})
ctr(aes), rfc3686(ctr(aes))
xts(aes)
-authenc:
authenc(hmac(md5),cbc({aes,des,des3_ede}))
authenc(hmac(sha*),cbc({aes,des,des3_ede}))
caam/qi being a new driver, let's wait some time to settle down without
interfering with existing caam/jr driver.
Accordingly, for now all caam/qi algorithms (caamalg_qi module) are
marked to be of lower priority than caam/jr ones (caamalg module).
Signed-off-by: Vakul Garg <vakul.garg@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
CAAM engine supports two interfaces for crypto job submission:
-job ring interface - already existing caam/jr driver
-Queue Interface (QI) - caam/qi driver added in current patch
QI is present in CAAM engines found on DPAA platforms.
QI gets its I/O (frame descriptors) from QMan (Queue Manager) queues.
This patch adds a platform device for accessing CAAM's queue interface.
The requests are submitted to CAAM using one frame queue per
cryptographic context. Each crypto context has one shared descriptor.
This shared descriptor is attached to frame queue associated with
corresponding driver context using context_a.
The driver hides the mechanics of FQ creation, initialisation from its
applications. Each cryptographic context needs to be associated with
driver context which houses the FQ to be used to transport the job to
CAAM. The driver provides API for:
(a) Context creation
(b) Job submission
(c) Context deletion
(d) Congestion indication - whether path to/from CAAM is congested
The driver supports affining its context to a particular CPU.
This means that any responses from CAAM for the context in question
would arrive at the given CPU. This helps in implementing one CPU
per packet round trip in IPsec application.
The driver processes CAAM responses under NAPI contexts.
NAPI contexts are instantiated only on cores with affined portals since
only cores having their own portal can receive responses from DQRR.
The responses from CAAM for all cryptographic contexts ride on a fixed
set of FQs. We use one response FQ per portal owning core. The response
FQ is configured in each core's and thus portal's dedicated channel.
This gives the flexibility to direct CAAM's responses for a crypto
context on a given core.
Signed-off-by: Vakul Garg <vakul.garg@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Refactor the generation of the authenc, ablkcipher shared descriptors
and exports the functionality, such that they could be shared
with the upcoming caam/qi (Queue Interface) driver.
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Add RSA support to caam driver.
Initial author is Yashpal Dutta <yashpal.dutta@freescale.com>.
Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
EXTRA_CFLAGS is still supported but its usage is deprecated.
Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
The SEC Job Rings are now available as individual devices.
This would enable sharing of job rings between kernel and
user space. Job Rings can now be dynamically bound/unbound
from kernel.
Changes are made in the following layers of CAAM Driver
1. Controller driver
- Does basic initialization of CAAM Block.
- Creates platform devices for Job Rings.
(Earlier the initialization of Job ring was done
by the controller driver)
2. JobRing Platform driver
- Manages the platform Job Ring devices created
by the controller driver
Signed-off-by: Ruchika Gupta <ruchika.gupta@freescale.com>
Reviewed-by: Garg Vakul-B16394 <vakul@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This patch adds an option to the Kconfig file for
SEC which enables the user to see the debug messages
that are printed inside the SEC driver.
Signed-off-by: Alex Porosanu <alexandru.porosanu@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
caam_read copies random bytes from two buffers into output.
caam rng can fill empty buffer 0xffff bytes at a time,
but the buffer sizes are rounded down to multiple of cacheline size.
Signed-off-by: Yuan Kang <Yuan.Kang@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
caam supports ahash hmac with sha algorithms and md5.
Signed-off-by: Yuan Kang <Yuan.Kang@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
create separate files for split key generation and scatterlist functions.
Signed-off-by: Yuan Kang <Yuan.Kang@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
The SEC4 supercedes the SEC2.x/3.x as Freescale's
Integrated Security Engine. Its programming model is
incompatible with all prior versions of the SEC (talitos).
The SEC4 is also known as the Cryptographic Accelerator
and Assurance Module (CAAM); this driver is named caam.
This initial submission does not include support for Data Path
mode operation - AEAD descriptors are submitted via the job
ring interface, while the Queue Interface (QI) is enabled
for use by others. Only AEAD algorithms are implemented
at this time, for use with IPsec.
Many thanks to the Freescale STC team for their contributions
to this driver.
Signed-off-by: Steve Cornelius <sec@pobox.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>