From mboxrd@z Thu Jan 1 00:00:00 1970 Subject: Re: Slab corruption mm3 + davem fixes From: "David S. Miller" In-Reply-To: <200305111221.26048.tomlins@cam.org> References: <20030511031940.97C24251B@oscar.casa.dyndns.org> <200305111221.26048.tomlins@cam.org> Content-Type: multipart/mixed; boundary="=-5BrkI45hpvPGN31OmYHz" Message-Id: <1052690490.4471.2.camel@rth.ninka.net> Mime-Version: 1.0 Date: 11 May 2003 15:01:31 -0700 Sender: owner-linux-mm@kvack.org Return-Path: To: Ed Tomlinson Cc: akpm@digeo.com, linux-mm@kvack.org, linux-kernel@vger.kernel.org, rusty@rustcorp.com.au, laforge@netfilter.org List-ID: --=-5BrkI45hpvPGN31OmYHz Content-Type: text/plain Content-Transfer-Encoding: 7bit On Sun, 2003-05-11 at 09:21, Ed Tomlinson wrote: > I am also seeing this on 69-bk (as of Sunday morning) ... > On May 10, 2003 11:19 pm, Ed Tomlinson wrote: > > I looked at my logs and found the following error in it. My kernel is > > 69-mm3 with two davem fixes on it. ... > > May 10 22:41:06 oscar kernel: Call Trace: > > May 10 22:41:06 oscar kernel: [__slab_error+30/32] __slab_error+0x1e/0x20 > > May 10 22:41:06 oscar kernel: [check_poison_obj+376/384] > > check_poison_obj+0x178/0x180 May 10 22:41:06 oscar kernel: > > [kmalloc+221/392] kmalloc+0xdd/0x188 May 10 22:41:06 oscar kernel: > > [alloc_skb+64/240] alloc_skb+0x40/0xf0 May 10 22:41:06 oscar kernel: Yeah, more bugs in the NAT netfilter changes. Debugging this one patch is becomming a full time job :-( This should fix it. Rusty, you're computing checksums and mangling src/dst using header pointers potentially pointing to free'd skbs. -- David S. Miller --=-5BrkI45hpvPGN31OmYHz Content-Disposition: attachment; filename=diff Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; name=diff; charset=UTF-8 # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher= . # This patch includes the following deltas: # ChangeSet 1.1199 -> 1.1411=20 # drivers/net/3c59x.c 1.19 -> 1.20 =20 # include/net/route.h 1.7 -> 1.15 =20 # net/ipv4/syncookies.c 1.7 -> 1.10 =20 # include/linux/sysctl.h 1.23 -> 1.24 =20 # net/ipv4/ip_forward.c 1.2 -> 1.9 =20 # net/ipv4/raw.c 1.7 -> 1.17 =20 # net/ipv6/tcp_ipv6.c 1.23 -> 1.32 =20 # net/ipv6/af_inet6.c 1.9 -> 1.11 =20 # arch/cris/config.in 1.13 -> 1.14 =20 # include/linux/skbuff.h 1.15 -> 1.18 =20 # include/net/dn_route.h 1.1 -> 1.2 =20 # net/ipv6/ndisc.c 1.20 -> 1.24 =20 # net/ipv6/exthdrs.c 1.4 -> 1.7 =20 # net/ipv4/ipconfig.c 1.18 -> 1.19 =20 # net/ipv6/ip6_output.c 1.11 -> 1.17 =20 # net/ipv4/netfilter/ipt_MASQUERADE.c 1.5 -> 1.6 =20 # net/ipv4/ip_input.c 1.5 -> 1.10 =20 # arch/sparc/config.in 1.14 -> 1.15 =20 # net/ipv6/ipv6_sockglue.c 1.8 -> 1.10 =20 # net/ipv4/Config.in 1.3 -> 1.8 =20 # net/ipv6/datagram.c 1.5 -> 1.6 =20 # arch/s390x/config.in 1.9 -> 1.10 =20 # Makefile 1.208 -> 1.209 =20 # include/linux/inetdevice.h 1.4 -> 1.5 =20 # include/net/tcp.h 1.22 -> 1.24 =20 # include/linux/ipsec.h 1.2 -> 1.4 =20 # net/ipv4/protocol.c 1.3 -> 1.4 =20 # net/ipv4/af_inet.c 1.10 -> 1.15 =20 # net/ipv4/netfilter/ip_nat_core.c 1.17 -> 1.18 =20 # net/ipv4/udp.c 1.9 -> 1.19 =20 # net/ipv6/protocol.c 1.2 -> 1.3 =20 # include/asm-ppc/kmap_types.h 1.8 -> 1.11 =20 # net/ipv4/fib_semantics.c 1.6 -> 1.7 =20 # net/core/skbuff.c 1.9 -> 1.12 =20 # arch/arm/config.in 1.21 -> 1.22 =20 # net/ipv6/ip6_input.c 1.2 -> 1.9 =20 # net/ipv6/route.c 1.14 -> 1.22 =20 # net/ipv4/tcp_input.c 1.23 -> 1.24 =20 # net/ipv4/tcp_minisocks.c 1.13 -> 1.14 =20 # include/asm-sparc/kmap_types.h 1.6 -> 1.9 =20 # include/net/ip6_route.h 1.3 -> 1.5 =20 # arch/alpha/config.in 1.22 -> 1.23 =20 # net/Config.in 1.10 -> 1.12 =20 # include/linux/udp.h 1.1 -> 1.4 =20 # net/ipv4/devinet.c 1.8 -> 1.10 =20 # arch/ppc64/config.in 1.5 -> 1.6 =20 # net/ipv4/Makefile 1.3 -> 1.10 =20 # net/ipv4/netfilter/ip_fw_compat_masq.c 1.4 -> 1.5 =20 # arch/s390/config.in 1.9 -> 1.10 =20 # net/ipv6/ip6_fib.c 1.7 -> 1.8 =20 # include/net/ipv6.h 1.5 -> 1.6 =20 # net/ipv4/tcp.c 1.26 -> 1.28 =20 # net/ipv6/udp.c 1.9 -> 1.16 =20 # net/ipv4/netfilter/ipt_REJECT.c 1.11 -> 1.14 =20 # include/linux/ip.h 1.1 -> 1.4 =20 # net/sched/cls_route.c 1.4 -> 1.5 =20 # net/ipv4/ip_sockglue.c 1.6 -> 1.10 =20 # net/ipv6/icmp.c 1.14 -> 1.18 =20 # arch/sparc64/config.in 1.25 -> 1.26 =20 # include/linux/netlink.h 1.7 -> 1.9 =20 # net/ipv6/reassembly.c 1.6 -> 1.8 =20 # net/ipv4/arp.c 1.10 -> 1.12 =20 # arch/i386/config.in 1.41 -> 1.42 =20 # net/ipv4/tcp_ipv4.c 1.22 -> 1.31 =20 # include/net/flow.h 1.1 -> 1.3 =20 # include/net/ip_fib.h 1.2 -> 1.4 =20 # include/net/raw.h 1.2 -> 1.3 =20 # net/ipv4/icmp.c 1.16 -> 1.21 =20 # net/ipv6/raw.c 1.10 -> 1.13 =20 # include/net/ip6_fw.h 1.1 -> (deleted) =20 # include/linux/netdevice.h 1.24 -> 1.26 =20 # net/netsyms.c 1.35 -> 1.55 =20 # include/net/protocol.h 1.4 -> 1.9 =20 # net/Makefile 1.6 -> 1.9 =20 # include/net/rawv6.h 1.2 -> 1.3 =20 # net/atm/clip.c 1.4 -> 1.5 =20 # net/ipv4/netfilter/ip_conntrack_standalone.c 1.10 -> 1.11 =20 # net/core/netfilter.c 1.7 -> 1.8 =20 # net/ipv6/ip6_fw.c 1.2 -> (deleted) =20 # net/ipv4/fib_frontend.c 1.7 -> 1.8 =20 # net/ipv4/ipmr.c 1.8 -> 1.14 =20 # net/ipv4/fib_hash.c 1.2 -> 1.3 =20 # net/ipv6/Config.in 1.3 -> 1.5 =20 # include/linux/in.h 1.1 -> 1.4 =20 # include/net/transp_v6.h 1.1 -> 1.2 =20 # net/netlink/af_netlink.c 1.10 -> 1.11 =20 # net/core/dev.c 1.35 -> 1.36 =20 # net/ipv4/ipip.c 1.13 -> 1.23 =20 # arch/sh/config.in 1.8 -> 1.9 =20 # arch/ia64/config.in 1.17 -> 1.18 =20 # net/core/rtnetlink.c 1.5 -> 1.6 =20 # net/ipv4/netfilter/ipt_TCPMSS.c 1.5 -> 1.7 =20 # arch/mips/config-shared.in 1.2 -> 1.3 =20 # arch/ppc/config.in 1.31 -> 1.32 =20 # net/ipv4/fib_rules.c 1.3 -> 1.4 =20 # MAINTAINERS 1.101 -> 1.102 =20 # net/core/dst.c 1.3 -> 1.6 =20 # include/linux/in6.h 1.4 -> 1.5 =20 # lib/Config.in 1.1 -> 1.2 =20 # net/ipv4/tcp_output.c 1.15 -> 1.17 =20 # include/net/ip.h 1.2 -> 1.6 =20 # arch/x86_64/config.in 1.4 -> 1.5 =20 # include/linux/ipv6.h 1.1 -> 1.3 =20 # include/asm-i386/kmap_types.h 1.6 -> 1.9 =20 # include/net/sock.h 1.15 -> 1.20 =20 # arch/m68k/config.in 1.17 -> 1.18 =20 # net/ipv4/sysctl_net_ipv4.c 1.8 -> 1.9 =20 # include/net/ip6_fib.h 1.2 -> 1.3 =20 # net/ipv4/ip_gre.c 1.8 -> 1.16 =20 # net/ipv6/Makefile 1.2 -> 1.8 =20 # net/ipv4/ip_nat_dumb.c 1.2 -> 1.4 =20 # include/linux/rtnetlink.h 1.6 -> 1.7 =20 # Documentation/Configure.help 1.179 -> 1.195 =20 # net/ipv6/sit.c 1.12 -> 1.17 =20 # include/net/dst.h 1.1 -> 1.12 =20 # net/decnet/dn_route.c 1.6 -> 1.9 =20 # include/net/ipip.h 1.2 -> 1.3 =20 # include/asm-x86_64/kmap_types.h 1.3 -> 1.6 =20 # net/decnet/dn_nsp_out.c 1.2 -> 1.3 =20 # net/ipv4/igmp.c 1.7 -> 1.12 =20 # net/ipv4/ip_output.c 1.12 -> 1.23 =20 # net/ipv4/route.c 1.24 -> 1.34 =20 # arch/parisc/config.in 1.5 -> 1.6 =20 # net/ipv4/netfilter/ipt_MIRROR.c 1.3 -> 1.4 =20 # (new) -> 1.3 net/ipv4/xfrm4_input.c # (new) -> 1.1 net/xfrm/xfrm_output.c # (new) -> 1.28 net/key/af_key.c # (new) -> 1.5 include/linux/pfkeyv2.h # (new) -> 1.3 net/ipv6/xfrm6_policy.c # (new) -> 1.1 net/xfrm/Config.in # (new) -> 1.2 net/ipv4/xfrm4_state.c # (new) -> 1.16 crypto/internal.h # (new) -> 1.17 net/xfrm/xfrm_user.c # (new) -> 1.14 net/ipv6/esp6.c # (new) -> 1.1 include/asm-sparc64/kmap_types.h # (new) -> 1.3 crypto/blowfish.c # (new) -> 1.3 net/xfrm/Makefile # (new) -> 1.7 crypto/compress.c # (new) -> 1.1 Documentation/crypto/descore-read= me.txt # (new) -> 1.26 crypto/api.c =20 # (new) -> 1.12 Documentation/crypto/api-intro.tx= t # (new) -> 1.27 include/linux/crypto.h # (new) -> 1.8 crypto/md5.c =20 # (new) -> 1.6 net/ipv4/ipcomp.c # (new) -> 1.8 net/xfrm/xfrm_algo.c # (new) -> 1.2 crypto/crypto_null.c # (new) -> 1.2 include/net/esp.h # (new) -> 1.14 crypto/Makefile # (new) -> 1.3 crypto/hmac.c =20 # (new) -> 1.2 crypto/serpent.c # (new) -> 1.7 include/linux/xfrm.h # (new) -> 1.13 crypto/tcrypt.h # (new) -> 1.14 net/ipv6/ah6.c=20 # (new) -> 1.3 net/ipv4/xfrm4_policy.c # (new) -> 1.2 net/ipv6/xfrm6_state.c # (new) -> 1.1 net/ipv6/ipv6_syms.c # (new) -> 1.3 crypto/proc.c =20 # (new) -> 1.9 crypto/sha1.c =20 # (new) -> 1.14 crypto/cipher.c # (new) -> 1.14 crypto/Config.in # (new) -> 1.2 crypto/sha256.c # (new) -> 1.21 crypto/tcrypt.c # (new) -> 1.33 include/net/xfrm.h # (new) -> 1.7 net/ipv6/xfrm6_input.c # (new) -> 1.6 crypto/md4.c =20 # (new) -> 1.1 net/key/Makefile # (new) -> 1.15 crypto/digest.c # (new) -> 1.23 net/xfrm/xfrm_policy.c # (new) -> 1.5 net/ipv4/xfrm4_tunnel.c # (new) -> 1.6 crypto/autoload.c # (new) -> 1.3 crypto/deflate.c # (new) -> 1.30 net/ipv4/esp.c=20 # (new) -> 1.23 net/ipv4/ah.c =20 # (new) -> 1.3 crypto/aes.c =20 # (new) -> 1.10 net/xfrm/xfrm_input.c # (new) -> 1.2 crypto/twofish.c # (new) -> 1.2 include/net/ah.h # (new) -> 1.23 net/xfrm/xfrm_state.c # (new) -> 1.1 crypto/sha512.c # (new) -> 1.11 crypto/des.c =20 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1200 # [CRYPTO]: Add initial crypto api subsystem. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1201 # [CRYPTO]: Cleanups based upon feedback from Rusty and jgarzik # - s/__u/u/ # - s/char/u8/ # - Fixed bug in cipher.c, page remapped was off by one block # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1202 # [CRYPTO]: Cleanups based upon feedback from Rusty and jgarzik # - s/__u/u/ # - s/char/u8/ # - Fixed bug in cipher.c, page remapped was off by one block # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1203 # [CRYPTO]: Use try_inc_mod_count and semaphore for alg list. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1204 # [CRYPTO]: Use kmod to try to autoload modules. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1205 # [CRYPTO]: Bug fixes and cleanups. # - try_inc_mod_count() already does what crypto_alg_get() was trying to do= . # (feedback from Andrew Morton.) # - Moved the BUG_ON() in crypto_unregister_alg() further up, no need to=20 # bother iterating over the list. # - Always use kmap_atomic (feedback from Andrew Morton). Implemented two # atomic kmaps, KM_USER for user context and KM_SOFTIRQ for softirq # context. # - Fixup KM_CRYPTO_ placement so Dave does not go crazy. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1206 # [CRYPTO]: More bug fixes and cleanups. # - added back USAGI copyright for HMAC (lost earlier during some # refactoring). # - bugfix: make sure tfm pointer is set to NULL during post allocation # failure path in crypto_alloc_tfm() # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1207 # [CRYPTO]: Add MD4. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1208 # [CRYPTO]: Algorithm lookup API change plus bug fixes. # - API change: implemented simplest version of algorithm lookup # by name (feedback from Rusty Russell and Herbert Valerio Riedel). # - Now need to add the following line to to /etc/modules.conf for # dynamic module loading: # alias des3_ede des # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1209 # [CRYPTO]: Run tcrypt through lindent, plus doc update. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1210 # [CRYPTO]: Assert that interfaces are called on correct cipher type. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1211 # [CRYPTO]: Cleanups and more consistency checks. # - Removed local_bh_disable() from kmap wrapper, not needed now with # two atomic kmaps. # - Nuked atomic flag, use in_softirq() instead. # - Converted crypto_kmap() and crypto_yield() to check in_softirq(). # - Check CRYPTO_MAX_CIPHER_BLOCK_SIZE during alg init. # - Try to initialize as much at compile time as possible # (feedback from Christoph Hellwig). # - Clean up list handling a bit (feedback from Christoph Hellwig). # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1212 # [CRYPTO]: Update to IV get/set interface. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1213 # [CRYPTO]: kunmap does not return a value. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1214 # [CRYPTO]: Build/warning fixups. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1215 # [CRYPTO]: Add some documentation. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1216 # [CRYPTO]: Clean up header file usage. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1217 # [CRYPTO]: Fix some credits. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1218 # [CRYPTO]: Cleanups based upon suggestions by Jeff Garzik. # - Changed unsigned to unsigned int in algos. # - Consistent use of u32 for flags throughout api. # - Use of unsigned int rather than int for counting things which must # be positive, also replaced size_ts to keep code simpler and lessen # bloat on some archs. # - got rid of some unneeded returns. # - const correctness. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1219 # [CRYPTO]: Uninline some functions to save some bloat. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1220 # [CRYPTO]: Cleanups based upon feedback from jgarzik. # - make crypto_cipher_flags() return u32 (this means it will return # the actual flags reliably, instead of being just a boolean op). # - simplify error path in crypto_init_flags(). # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1221 # [CRYPTO]: Add crypto_alg_available interface. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1222 # [CRYPTO]: Rework HMAC interface. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1223 # [CRYPTO]: Include kernel.h in crypto.h # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1224 # [CRYPTO]: Allocate work buffers instead of using kstack. # -------------------------------------------- # 03/05/07 torvalds@transmeta.com 1.1225 # The crypto auto-load should be enabled if crypto is enabled. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1226 # [CRYPTO]: Add SHA256 plus bug fixes. # - Bugfix in sha1 copyright # - Add support for SHA256, test vectors and HMAC test vectors # - Remove obsolete atomic messages. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1227 # [CRYPTO]: Add blowfish algorithm. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1228 # [CRYPTO]: Make sha256.c more palatable to GCCs optimizers. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1229 # [CRYPTO]: minor updates # - Fixed min keysize bug for Blowfish (it is 32, not 64). # - Documentation updates. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1230 # [CRYPTO] kstack cleanup (v0.28) # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1231 # [CRYPTO] Add maintainers entry. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1232 # [CRYPTO] Minor doc update. # -------------------------------------------- # 03/05/07 jgarzik@redhat.com 1.1233 # [CRYPTO]: Kill accidental double memset. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1234 # [CRYPTO]: Add null algorithms and minor cleanups. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1235 # [CRYPTO]: Kill stray CRYPTO_ALG_TYPE_COMP. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1236 # [CRYPTO]: Add twofish algorithm. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1237 # [CRYPTO]: Add serpent algorithm. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1238 # [CRYPTO]: Documentation update. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1239 # [CRYPTO]: Dont compile procfs stuff if procfs is not enabled. # -------------------------------------------- # 03/05/07 adam@yggdrasil.com 1.1240 # [CRYPTO]: Simplify crypto memory allocation. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1241 # [CRYPTO]: internal.h needs init.h # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1242 # [CRYPTO]: Add AES algorithm. # - Merged AES code from Adam J. Richter # - Add kconfig help and test vector code from # Martin Clausen # - Minor cleanups: removed EXPORT_NO_SYMBOLS (not needed for 2.5), # removed debugging code etc. # - Documentation updates. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1243 # [CRYPTO]: Use appropriate defaults if AH/ESP is enabled. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1244 # [CRYPTO]: More credits for AES. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1245 # [CRYPTO]: Add support for SHA-386 and SHA-512 # - Merged SHA-384 and SHA-512 code from Kyle McMartin # # - Added test vectors. # - Documentation and credits updates. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1246 # [CRYPTO] remove superfluous goto from des module init exception path # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1247 # [CRYPTO] Add AES and MD4 to tcrypto crypto_alg_available() test. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1248 # [CRYPTO]: in/out scatterlist support for ciphers. # - Merge scatterwalk patch from Adam J. Richter # API change: cipher methods now take in/out scatterlists and nbytes=20 # params. # - Merge gss_krb5_crypto update from Adam J. Richter # - Add KM_SOFTIRQn (instead of KM_CRYPTO_IN etc). # - Add asm/kmap_types.h to crypto/internal.h # - Update cipher.c credits. # - Update cipher.c documentation. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1249 # [CRYPTO]: Move km_types out of header. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1250 # [CRYPTO]: Add encrypt_iv() and decrypt_iv() methods. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1251 # [CRYPTO]: Eliminate crypto_tfm.crt_ctx, from Adam Richter. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1252 # [CRYPTO]: Documentation updates. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1253 # [CRYPTO-2.4]: Add dummy kmap_types.h header for sparc64. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1254 # [CRYPTO]: Include linux/errno.h as appropriate. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1255 # [CRYPTO-2.4]: module_name does not exist in 2.4.x # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1256 # [CRYPTO]: Make use of crypto_exit_ops() during crypto_free_tfm(). # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1257 # [CRYPTO]: Add Deflate algorithm to crypto API. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1258 # [CRYPTO]: deflate module: workaround zlib bug. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1259 # [CRYPTO-2.4]: const static --> static const. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1260 # [CRYPTO]: deflate.c needs slab.h # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1261 # [CRYPTO-2.4]: Fix condition typos in crypto/Config.in # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1262 # [IPV4/IPV6]: Cleanup inet{,6}_protocol. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1263 # [IPV4]: Use generic struct flowi as routing key. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1264 # [NET]: Ipv4 output path changes by Alexey. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1265 # [IPV4]: Provide full proto/ports in flowi route lookups. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1266 # [IPV4]: Kill ip_send, use dst_output instead. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1267 # [NET]: Kill reroute from DST ops, unused. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1268 # [IPV4]: Missing ip_rt_put in ip_route_newports. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1269 # include/linux/ip.h: Define AH/ESP header layout. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1270 # [NET]: Fix rtnetlink metric type, should be u32. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1271 # [NET]: Cleanup DST metrics and abstract MSS/PMTU further. # - Changed dst named metrics, to RTAX_MAX metrics array. # - Add inline shorthands to access them # - Add update_pmtu and get_mss to DST ops. # - Add path component to DST, it is DST itself by default. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1272 # [NET]: Add DST_NOXFRM and DST_NOPOLICY flags. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1273 # net/ipv4/route.c: Create compare_keys to compare flowi identities. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1274 # [IPV4]: Rework key route lookup interface slightly. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1275 # [IPSEC]: Add transform engine and AH implementation. # -------------------------------------------- # 03/05/07 viro@math.psu.edu 1.1276 # [NET]: Compile fixes. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1277 # [IPV4]: Define IPPROTO_SCTP. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1278 # [UDP]: Delete buggy assertion. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1279 # [NET]: Some missed cases of dst_pmtu conversion. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1280 # [NET]: IPSEC updates. # - Add ESP tranformer. # - Add AF_KEY socket layer. # - Rework xfrm structures for user interfaces # - Add CONFIG_IP_{AH,ESP}. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1281 # [IPSEC-2.4]: Fix inet_getid invocation for 2.4.x # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1282 # [IPSEC]: Fix xfrm policy locking. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1283 # [AF_KEY]: Convert to/from IPSEC_PROTO_ANY. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1284 # [IPSEC]: XFRM policy bug fixes. # - Fix dst metric memcpy length. # - Iterator for walking skb sec_path goes in wrong direction. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1285 # [IPSEC]: Bug fixes and updates. # - Implement IP_IPSEC_POLICY setsockopt # - Rework input policy checks to use it # - dst->child destruction is repaired # - Fix tunnel mode IP header building. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1286 # [IPSEC]: Export xfrm_policy_list. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1287 # [IPSEC]: Allocate work buffers instead of using kstack. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1288 # [IPSEC]: RAWv4 makes inverted policy check. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1289 # [IPSEC]: Semantic fixes with help from Maxim Giryaev. # - BSD apps want sin_zero cleared in sys_getname. # - Fix protocol setting in flow descriptor of RAW sockets # - Wildcard protocol is represented differently in policy # than for association. # - Missing update of key manager sequence in xfrm_state entries. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1290 # [IPSEC]: Few changes to keep racoon ISAKMP daemon happy. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1291 # [IPSEC] More work. # 1. Expiration of SAs. Some missing updates of counters. # Question: very strange, rfc defines use_time as time of the first use # of SA. But kame setkey refers to this as lastuse. # 2. Bug fixes for tunnel mode and forwarding. # 3. Fix bugs in per-socket policy: policy entries do not leak but are dest= royed, # when socket is closed, and are cloned on children of listening sockets= . # 4. Implemented use policy: i.e. use ipsec if a SA is available, # ignore if it is not. # 5. Added sysctl to disable in/out policy on some devices. # It is set on loopback by default. # 6. Remove resolved reference from template. It is not used, # but pollutes code. # 7. Added all the SASTATEs, now they make sense. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1292 # [IPSEC]: Fix lockup in xfrm4_dst_check. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1293 # [IPSEC]: More fixes and corrections. # - Make connect() policy selection actually happen # - return len instead of 0 on successful pfkey sendmsg # - make prefixlen checks in a way more compatible with isakmpd # - key manager wait queues are totally wrong # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1294 # [IPSEC]: Make netlink user interface header. # -------------------------------------------- # 03/05/07 viro@math.psu.edu 1.1295 # [ipt_TCPMSS]: Compile fix. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1296 # [UDP]: silly bug, local input policy did not work on udp sockets. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1297 # [IPSEC]: ah/esp, 0 was used as tunnels protocol. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1298 # [IPSEC]: authentication signature for MD5/SHA was not truncated to confor= m RFC. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1299 # [AF_KEY]: Fix alloc_skb args. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1300 # [IPSEC]: More pfkey2 semantic fixes. # - xfrm_state.c: never return mature SAs on getspi. # - af_key.c: do not forget to delete dummy super-larvals when they are res= olve\d # - af_key.c: wow! specially for this case I added gfp argument # to xfrm_alloc_policy() and forgot to use it really. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1301 # [IPSEC]: Netlink configuration interface. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1302 # [XFRM_USER]: Destroy netlink socket on shutdown. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1303 # [XFRM]: Add family member to state/policy structs. # -------------------------------------------- # 03/05/07 taral@taral.net 1.1304 # [IPSEC]: Fix double unlock in esp/ah. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1305 # [IPSEC]: Policy timeout and pfkey acquire fixes. # - Implement policy timeouts. # - Make PF_KEY return proper error from KM acquire. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1306 # [IPSEC]: Make xfrm_user key manager return proper errors. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1307 # [XFRM_USER]: Index xfrma array correctly. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1308 # [PATCH] IPv6: Fix BUG When Received Unknown Protocol. # -------------------------------------------- # 03/05/07 hch@lst.de 1.1309 # [AF_KEY]: Fix comment typo. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1310 # [NET]: Protect skbuff secpath code with CONFIG_INET. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1311 # [IPSEC]: Uninline _decode_session. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1312 # [IPV4 OUTPUT]: Uninline ip_finish_output and skb_fill_page_desc. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1313 # [IPSEC]: Clean up key manager algorithm handling. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1314 # [IPSEC]: Dont check algorithm availability unless CONFIG_CRYPTO. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1315 # [IPSEC]: Kill warning in xfrm_algo.c. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1316 # [IPSEC]: Clear SKB checksum state when mangling. # -------------------------------------------- # 03/05/07 thomas@bender.thinknerd.de 1.1317 # [IPSEC]: Fix some buglets in xfrm_user.c # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1318 # [IPSEC]: remove trailer_len from esp and xfrm properties. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1319 # [IPSEC]: Update ah documentation. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1320 # [IPSEC] Convert esp auth to use proper crypto api calls. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1321 # [IPSEC] Generic ICV handling for ESP. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1322 # [IPSEC]: in/out scatterlist support for ciphers. # -------------------------------------------- # 03/05/07 kunihiro@ipinfusion.com 1.1323 # [XFRM]: Add family member to xfrm_usersa_id. # -------------------------------------------- # 03/05/07 latten@austin.ibm.com 1.1324 # [IPSEC]: Make AF_KEY allow NULL encryption. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1325 # [IPSEC]: Make sure to clear sin_zero in AF_KEY. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1326 # [IPSEC]: Add missed bit of sin_zero fix. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1327 # [IPSEC] Make sure SADB_X_SPDADD messages have proper spid. # -------------------------------------------- # 03/05/07 kunihiro@ipinfusion.com 1.1328 # [IPSEC]: Add ipv6 support infrastructure. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1329 # [IPSEC]: Mark pfkey_sadb_addr2xfrm_addr static again. # -------------------------------------------- # 03/05/07 kunihiro@ipinfusion.com 1.1330 # [IPSEC]: Add ipv6 support to ipsec netlink sockets. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1331 # [AF_KEY]: Add missing credit. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1332 # [NET]: Convert dst->{input,output}() fully to dst_{input,output}(). # -------------------------------------------- # 03/05/07 mk@linux-ipv6.org 1.1333 # [IPSEC]: Add missing credit and include to xfrm_user ipv6 changes. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1334 # [IPSEC]: Move xfrm6 policy code to net/ipv4/xfrm_policy.c # -------------------------------------------- # 03/05/07 latten@austin.ibm.com 1.1335 # [IPSEC]: Make sure ESP output pads Null Encryption properly. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1336 # [IPSEC]: Add family argument to compile_policy. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1337 # [IPSEC]: Use dst_hold unless assigning result to something. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1338 # [IPSEC]: Add full ipv6 support. #=20 # Credits also to Mitsuru Kanda , # YOSHIFUJI Hideaki , # and Kunihiro Ishiguro. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1339 # [IPV4]: Fix multicast route lookups. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1340 # [IPSEC]: Fix obvious typo in xfrm_sk_clone_policy. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1341 # [NET]: hard_header reservation. # 1. Fix bad reservation in xfrm_state_check_space() # 2. Macroize formula for reservation, use the macro over all the places # in IP. # -------------------------------------------- # 03/05/07 kuznet@ms2.in.ac.ru 1.1342 # [NET]: miscellaneous fixes. # 1. Fix illegal dereference of potentially freed memory in xfrm_policy.c # 2. Complete wildcard flow addresses to real ones in xfrm_lookup(). # 3. Respect optional flag when chacking for input policy. # 4. Delete orphaned comments in ip.h. # 5. Fix mistakedly freed route in tcp connect. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1343 # [IPSEC]: fragmentation & tcp mss calculation. # 1. Add local_df field to struct sk_buff to mark packets which # are to be fragmented locally despite of their IPv6ness of IP DF flag # 2. Add ext2_header_len to tcp_opt to keep memory of part of header length # depending on route # 3. Add trailer_len to struct dst_entry and xfrm_state to know how # much of space should be reserved at tail of frame for subsequent # transformations. # 4. [BUG] icv_trun_len must be used while mss claculation, not # icv_full_length. # -------------------------------------------- # 03/05/07 thomas@bender.thinknerd.de 1.1344 # [IPSEC]: Fix null authentication/encryption. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1345 # [IPSEC]: fix skb leak in ah and esp. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1346 # [IPSEC]: return error when no dst in ah & esp output. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1347 # [IPSEC]: Add IPV6_{IPSEC,XFRM}_POLICY socket option support. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1348 # [IPSEC]: Export xfrm_user_policy. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1349 # [IPSEC]: net/xfrm.h needs net/sock.h # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1350 # [IPSEC-2.4]: try_inc_mod_count --> __MOD_INC_USE_COUNT. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1351 # [IPSEC-2.4]: Fix ip_select_ident args in ESP/v4. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1352 # [IPSEC-2.4]: Fixup AF_KEY for 2.4.x interface differences. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1353 # [IPSEC]: Fix parsing of 16-bit ipcomp cpi. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1354 # [IPSEC]: IPV6 source address not set correctly in xfrm_state. # -------------------------------------------- # 03/05/07 jgrimm2@us.ibm.com 1.1355 # [IPSEC]: Fix SKB alloc len in ip6_build_xmit. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1356 # [IPSEC] Add initial compression support for pfkey and xfrm_algo. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1357 # [IPSEC]: Split up XFRM Subsystem. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1358 # [IPSEC]: Fix build when ipsec is disabled. # -------------------------------------------- # 03/05/07 torvalds@transmeta.com 1.1359 # Avoid warning with modern gcc's in xfrm_policy.c # -------------------------------------------- # 03/05/07 mk@linux-ipv6.org 1.1360 # [IPV6]: Process all extension headers via ipproto->handler. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1361 # [IPSEC]: Fix bug in xfrm_parse_spi() # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1362 # [IPSEC]: Make get_acqseq() xfrm_state.c:xfrm_get_acqseq(). # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1363 # [IPSEC-2.4]: Fix ipv6 xfrm exports. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1364 # [IPSEC]: Fix IPV6 UDP policy checking. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1365 # [IPSEC-2.4]: Fix module get in xfrm_policy. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1366 # [IPSEC]: Kill skb_ah_walk, not needed. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1367 # [IPSEC]: Remove duplicate / obsolete entry in include/linux/dst.h # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1368 # [IPV4]: Make sure rtcache flush happens after sysctl updates. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1369 # [IPSEC]: Remove unused field owner from selector. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1370 # [IPSEC]: linux/xfrm.h u32 --> __u32. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1371 # [IPSEC]: Missing ipv6 policy checks. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1372 # [IPSEC]: IPV6 AH/ESP fixes. # -------------------------------------------- # 03/05/07 toml@us.ibm.com 1.1373 # [IPSEC]: Use "sizeof" for header sizes. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1374 # [IPSEC]: Fix xfrm_state refcounts. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1375 # [IPSEC-2.4]: Fix xfrm/Makefile for 2.4.x # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1376 # [NET]: Use current_text_addr instead of label tricks in dst_release. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1377 # [IPSEC]: xfrm_{state,user}.c need asm/uaccess.h # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1378 # [IPSEC-2.4]: Fix net/Makefile so xfrm modules get built. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1379 # [IPSEC]: Use of "sizeof" for header sizes, part II # -------------------------------------------- # 03/05/07 derek@ihtfp.com 1.1380 # [IPSEC]: Implement UDP Encapsulation framework. #=20 # In particular, implement ESPinUDP encapsulation for IPsec # Nat Traversal. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1381 # [IPSEC]: Store xfrm_encap_tmpl directly in xfrm_state. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1382 # [IPSEC]: Add encap support for xfrm_user. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1383 # [IPSEC]: Clean up decap state, minimize its size. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1384 # [IPSEC]: Move xfrm type destructor out of spinlock. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1385 # [IPSEC-2.4]: Use schedule_task for xfrm_state gc work. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1386 # [IPSEC]: AH/ESP forget to free private structs. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1387 # [IPSEC]: Really move type destructor out of spinlock. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1388 # [IPSEC]: Support for optional policies on input got lost. # -------------------------------------------- # 03/05/07 rusty@rustcorp.com.au 1.1389 # [IPSEC]: Avoid using SET_MODULE_OWNER. # -------------------------------------------- # 03/05/07 jef@linuxbe.org 1.1390 # [IPSEC]: Check xfrm state expiration on input after replay check. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1391 # [IPSEC]: Add initial IPCOMP support. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1392 # [IPSEC]: Add ipv4 tunnel transformer. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1393 # [IPSEC]: Fix handling of uncompressable packets in tunnel mode. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1394 # [IPV4]: xfrm4_tunnel and ipip need to privateize some symbols. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1395 # [IPV6]: Fixed multiple mistake extension header handling. # - double free if sending Parameter Problem message in reassembly code. # - (sometimes) broken checksum # - HbH not producing unknown header; it is only allowed at the beginning = of # the exthdrs chain. # - wrong pointer value in Parameter Problem message. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1396 # [NET]: Use fl6_{src,dst} etc. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1397 # [IPSEC-2.4]: Missing UDP_ENCAP_ESPINUDP define. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1398 # [IPSEC-2.4]: More __ip_select_ident args fixes. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1399 # [IPSEC-2.4]: Backport synchronize_net from 2.5 # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1400 # [IPSEC-2.4]: Missing bits of UDP encap changes. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1401 # [IPSEC]: nexthdr in xfrm6_input needs to be int. # -------------------------------------------- # 03/05/07 steve@gw.chygwyn.com 1.1402 # [IP_GRE]: Kill duplicate update_pmtu call. # -------------------------------------------- # 03/05/07 yoshfuji@linux-ipv6.org 1.1403 # [IPV6]: dst_alloc() clean-up. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1404 # [IPSEC]: allow only tunnel mode in xfrm4_tunnels. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1405 # [IPV4]: Use dst_pmtu not dev->mtu to determine if fragmentation is needed= . # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1406 # [IPV4]: Fix typos in ipip.c commented out code. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1407 # [IPSEC]: pmtu discovery support at local tunnel gateway. # -------------------------------------------- # 03/05/07 jmorris@intercode.com.au 1.1408 # [IPSEC]: Consolidate some output code into xfrm_check_output. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1409 # [IPSEC-2.4]: Fix mispatch, need to pass sk->allocation to kmalloc in ip_a= ppend_data. # -------------------------------------------- # 03/05/08 mk@linux-ipv6.org 1.1410 # [IPSEC]: Fix ipcomp header handling in ipv4 IPCOMP. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1411 # [IPSEC-2.4]: Fix mis-patch of ipt_REJECT.c # -------------------------------------------- # diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help --- a/Documentation/Configure.help Thu May 8 10:41:38 2003 +++ b/Documentation/Configure.help Thu May 8 10:41:38 2003 @@ -5349,6 +5349,14 @@ and you should also say Y to "Kernel/User network link driver", below. If unsure, say N. =20 +PF_KEY sockets +CONFIG_NET_KEY + PF_KEYv2 socket family, compatible to KAME ones. + They are required if you are going to use IPsec tools ported + from KAME. + + Say Y unless you know what you are doing. + TCP/IP networking CONFIG_INET These are the protocols used on the Internet and on most local @@ -5614,6 +5622,32 @@ gated-5). This routing protocol is not used widely, so say N unless you want to play with it. =20 +IP: AH transformation +CONFIG_INET_AH + Support for IPsec AH. + + If unsure, say Y. + +IP: ESP transformation +CONFIG_INET_ESP + Support for IPsec ESP. + + If unsure, say Y. + +IP: IPComp transformation +CONFIG_INET_IPCOMP + Support for IP Paylod Compression (RFC3173), typically needed + for IPsec. + + If unsure, say Y. + +IP: IPsec user configuration interface +CONFIG_XFRM_USER + Support for IPsec user configuration interface used + by native Linux tools. + + If unsure, say Y. + Unix domain sockets CONFIG_UNIX If you say Y here, you will include support for Unix domain sockets; @@ -26524,6 +26558,98 @@ This is experimental code, not yet tested on many boards. =20 If unsure, say N. + +CONFIG_CRYPTO + This option provides the core Cryptographic API. + +CONFIG_CRYPTO_HMAC + HMAC: Keyed-Hashing for Message Authentication (RFC2104). + This is required for IPSec. + +CONFIG_CRYPTO_NULL + These are 'Null' algorithms, used by IPsec, which do nothing. + +CONFIG_CRYPTO_MD4 + MD4 message digest algorithm (RFC1320). + =20 +CONFIG_CRYPTO_MD5 + MD5 message digest algorithm (RFC1321). + +CONFIG_CRYPTO_SHA1 + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + +CONFIG_CRYPTO_SHA256 + SHA256 secure hash standard (DFIPS 180-2). + + This version of SHA implements a 256 bit hash with 128 bits of + security against collision attacks. + +CONFIG_CRYPTO_SHA512 + SHA512 secure hash standard (DFIPS 180-2). + + This version of SHA implements a 512 bit hash with 256 bits of + security against collision attacks. + + This code also includes SHA-384, a 384 bit hash with 192 bits + of security against collision attacks. + +CONFIG_CRYPTO_DES + DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + +CONFIG_CRYPTO_BLOWFISH + Blowfish cipher algorithm, by Bruce Schneier. + + This is a variable key length cipher which can use keys from 32 + bits to 448 bits in length. It's fast, simple and specifically + designed for use on "large microprocessors". + + See also . + +CONFIG_CRYPTO_TWOFISH + Twofish cipher algorithm. + + Twofish was submitted as an AES (Advanced Encryption Standard) + candidate cipher by researchers at CounterPane Systems. It is a + 16 round block cipher supporting key sizes of 128, 192, and 256 + bits. + + See also: + http://www.counterpane.com/twofish.html + +CONFIG_CRYPTO_SERPENT + Serpent cipher algorithm, by Anderson, Biham & Knudsen. + + Keys are allowed to be from 0 to 256 bits in length, in steps + of 8 bits. + + See also: + http://www.cl.cam.ac.uk/~rja14/serpent.html + +CONFIG_CRYPTO_AES + AES cipher algorithms (FIPS-197). AES uses the Rijndael=20 + algorithm. + + Rijndael appears to be consistently a very good performer in + both hardware and software across a wide range of computing=20 + environments regardless of its use in feedback or non-feedback=20 + modes. Its key setup time is excellent, and its key agility is=20 + good. Rijndael's very low memory requirements make it very well=20 + suited for restricted-space environments, in which it also=20 + demonstrates excellent performance. Rijndael's operations are=20 + among the easiest to defend against power and timing attacks.=09 + + The AES specifies three key sizes: 128, 192 and 256 bits =20 + + See http://csrc.nist.gov/encryption/aes/ for more information. + +CONFIG_CRYPTO_DEFLATE + This is the Deflate algorithm (RFC1951), specified for use in + IPSec with the IPCOMP protocol (RFC3173, RFC2394). + + You will most probably want this if using IPSec. + +CONFIG_CRYPTO_TEST + Quick & dirty crypto test module. =20 # # A couple of things I keep forgetting: diff -Nru a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-i= ntro.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/crypto/api-intro.txt Thu May 8 10:41:38 2003 @@ -0,0 +1,221 @@ + + Scatterlist Cryptographic API + =20 +INTRODUCTION + +The Scatterlist Crypto API takes page vectors (scatterlists) as +arguments, and works directly on pages. In some cases (e.g. ECB +mode ciphers), this will allow for pages to be encrypted in-place +with no copying. + +One of the initial goals of this design was to readily support IPsec, +so that processing can be applied to paged skb's without the need +for linearization. + + +DETAILS + +At the lowest level are algorithms, which register dynamically with the +API. + +'Transforms' are user-instantiated objects, which maintain state, handle a= ll +of the implementation logic (e.g. manipulating page vectors), provide an=20 +abstraction to the underlying algorithms, and handle common logical=20 +operations (e.g. cipher modes, HMAC for digests). However, at the user=20 +level they are very simple. + +Conceptually, the API layering looks like this: + + [transform api] (user interface) + [transform ops] (per-type logic glue e.g. cipher.c, digest.c) + [algorithm api] (for registering algorithms) + =20 +The idea is to make the user interface and algorithm registration API +very simple, while hiding the core logic from both. Many good ideas +from existing APIs such as Cryptoapi and Nettle have been adapted for this= . + +The API currently supports three types of transforms: Ciphers, Digests and +Compressors. The compression algorithms especially seem to be performing +very well so far. + +Support for hardware crypto devices via an asynchronous interface is +under development. + +Here's an example of how to use the API: + + #include +=09 + struct scatterlist sg[2]; + char result[128]; + struct crypto_tfm *tfm; +=09 + tfm =3D crypto_alloc_tfm("md5", 0); + if (tfm =3D=3D NULL) + fail(); + =09 + /* ... set up the scatterlists ... */ +=09 + crypto_digest_init(tfm); + crypto_digest_update(tfm, &sg, 2); + crypto_digest_final(tfm, result); +=09 + crypto_free_tfm(tfm); + + =20 +Many real examples are available in the regression test module (tcrypt.c). + + +CONFIGURATION NOTES + +As Triple DES is part of the DES module, for those using modular builds, +add the following line to /etc/modules.conf: + + alias des3_ede des + +The Null algorithms reside in the crypto_null module, so these lines +should also be added: + + alias cipher_null crypto_null + alias digest_null crypto_null + alias compress_null crypto_null + +The SHA384 algorithm shares code within the SHA512 module, so you'll +also need: + alias sha384 sha512 + + +DEVELOPER NOTES + +Transforms may only be allocated in user context, and cryptographic +methods may only be called from softirq and user contexts. + +When using the API for ciphers, performance will be optimal if each +scatterlist contains data which is a multiple of the cipher's block +size (typically 8 bytes). This prevents having to do any copying +across non-aligned page fragment boundaries. + + +ADDING NEW ALGORITHMS + +When submitting a new algorithm for inclusion, a mandatory requirement +is that at least a few test vectors from known sources (preferably +standards) be included. + +Converting existing well known code is preferred, as it is more likely +to have been reviewed and widely tested. If submitting code from LGPL +sources, please consider changing the license to GPL (see section 3 of +the LGPL). + +Algorithms submitted must also be generally patent-free (e.g. IDEA +will not be included in the mainline until around 2011), and be based +on a recognized standard and/or have been subjected to appropriate +peer review. + +Also check for any RFCs which may relate to the use of specific algorithms= , +as well as general application notes such as RFC2451 ("The ESP CBC-Mode +Cipher Algorithms"). + +It's a good idea to avoid using lots of macros and use inlined functions +instead, as gcc does a good job with inlining, while excessive use of +macros can cause compilation problems on some platforms. + +Also check the TODO list at the web site listed below to see what people +might already be working on. + + +BUGS + +Send bug reports to: +James Morris +Cc: David S. Miller + + +FURTHER INFORMATION + +For further patches and various updates, including the current TODO +list, see: +http://samba.org/~jamesm/crypto/ + + +AUTHORS + +James Morris +David S. Miller + + +CREDITS + +The following people provided invaluable feedback during the development +of the API: + + Alexey Kuznetzov + Rusty Russell + Herbert Valerio Riedel + Jeff Garzik + Michael Richardson + Andrew Morton + Ingo Oeser + Christoph Hellwig + +Portions of this API were derived from the following projects: + =20 + Kerneli Cryptoapi (http://www.kerneli.org/) + Alexander Kjeldaas + Herbert Valerio Riedel + Kyle McMartin + Jean-Luc Cooke + David Bryson + Clemens Fruhwirth + Tobias Ringstrom + Harald Welte + +and; + =20 + Nettle (http://www.lysator.liu.se/~nisse/nettle/) + Niels M=F6ller + +Original developers of the crypto algorithms: + + Dana L. How (DES) + Andrew Tridgell and Steve French (MD4) + Colin Plumb (MD5) + Steve Reid (SHA1) + Jean-Luc Cooke (SHA256, SHA384, SHA512) + Kazunori Miyazawa / USAGI (HMAC) + Matthew Skala (Twofish) + Dag Arne Osvik (Serpent) + Brian Gladman (AES) + + +SHA1 algorithm contributors: + Jean-Francois Dive + =20 +DES algorithm contributors: + Raimar Falke + Gisle S=E6lensminde + Niels M=F6ller + +Blowfish algorithm contributors: + Herbert Valerio Riedel + Kyle McMartin + +Twofish algorithm contributors: + Werner Koch + Marc Mutz + +SHA256/384/512 algorithm contributors: + Andrew McDonald + Kyle McMartin + Herbert Valerio Riedel + =20 +AES algorithm contributors: + Alexander Kjeldaas + Herbert Valerio Riedel + Kyle McMartin + Adam J. Richter + +Generic scatterwalk code by Adam J. Richter + +Please send any credits updates or corrections to: +James Morris + diff -Nru a/Documentation/crypto/descore-readme.txt b/Documentation/crypto/= descore-readme.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/crypto/descore-readme.txt Thu May 8 10:41:38 2003 @@ -0,0 +1,352 @@ +Below is the orginal README file from the descore.shar package. +--------------------------------------------------------------------------= ---- + +des - fast & portable DES encryption & decryption. +Copyright (C) 1992 Dana L. How + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published = by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Author's address: how@isl.stanford.edu + +$Id: README,v 1.15 1992/05/20 00:25:32 how E $ + + +=3D=3D>> To compile after untarring/unsharring, just `make' <<=3D=3D + + +This package was designed with the following goals: +1. Highest possible encryption/decryption PERFORMANCE. +2. PORTABILITY to any byte-addressable host with a 32bit unsigned C type +3. Plug-compatible replacement for KERBEROS's low-level routines. + +This second release includes a number of performance enhancements for +register-starved machines. My discussions with Richard Outerbridge, +71755.204@compuserve.com, sparked a number of these enhancements. + +To more rapidly understand the code in this package, inspect desSmallFips.= i +(created by typing `make') BEFORE you tackle desCode.h. The latter is set +up in a parameterized fashion so it can easily be modified by speed-daemon +hackers in pursuit of that last microsecond. You will find it more +illuminating to inspect one specific implementation, +and then move on to the common abstract skeleton with this one in mind. + + +performance comparison to other available des code which i could +compile on a SPARCStation 1 (cc -O4, gcc -O2): + +this code (byte-order independent): + 30us per encryption (options: 64k tables, no IP/FP) + 33us per encryption (options: 64k tables, FIPS standard bit ordering) + 45us per encryption (options: 2k tables, no IP/FP) + 48us per encryption (options: 2k tables, FIPS standard bit ordering) + 275us to set a new key (uses 1k of key tables) + this has the quickest encryption/decryption routines i've seen. + since i was interested in fast des filters rather than crypt(3) + and password cracking, i haven't really bothered yet to speed up + the key setting routine. also, i have no interest in re-implementing + all the other junk in the mit kerberos des library, so i've just + provided my routines with little stub interfaces so they can be + used as drop-in replacements with mit's code or any of the mit- + compatible packages below. (note that the first two timings above + are highly variable because of cache effects). + +kerberos des replacement from australia (version 1.95): + 53us per encryption (uses 2k of tables) + 96us to set a new key (uses 2.25k of key tables) + so despite the author's inclusion of some of the performance + improvements i had suggested to him, this package's + encryption/decryption is still slower on the sparc and 68000. + more specifically, 19-40% slower on the 68020 and 11-35% slower + on the sparc, depending on the compiler; + in full gory detail (ALT_ECB is a libdes variant): + compiler machine desCore libdes ALT_ECB slower by + gcc 2.1 -O2 Sun 3/110 304 uS 369.5uS 461.8uS 22% + cc -O1 Sun 3/110 336 uS 436.6uS 399.3uS 19% + cc -O2 Sun 3/110 360 uS 532.4uS 505.1uS 40% + cc -O4 Sun 3/110 365 uS 532.3uS 505.3uS 38% + gcc 2.1 -O2 Sun 4/50 48 uS 53.4uS 57.5uS 11% + cc -O2 Sun 4/50 48 uS 64.6uS 64.7uS 35% + cc -O4 Sun 4/50 48 uS 64.7uS 64.9uS 35% + (my time measurements are not as accurate as his). + the comments in my first release of desCore on version 1.92: + 68us per encryption (uses 2k of tables) + 96us to set a new key (uses 2.25k of key tables) + this is a very nice package which implements the most important + of the optimizations which i did in my encryption routines. + it's a bit weak on common low-level optimizations which is why + it's 39%-106% slower. because he was interested in fast crypt(3) and + password-cracking applications, he also used the same ideas to + speed up the key-setting routines with impressive results. + (at some point i may do the same in my package). he also implements + the rest of the mit des library. + (code from eay@psych.psy.uq.oz.au via comp.sources.misc) + +fast crypt(3) package from denmark: + the des routine here is buried inside a loop to do the + crypt function and i didn't feel like ripping it out and measuring + performance. his code takes 26 sparc instructions to compute one + des iteration; above, Quick (64k) takes 21 and Small (2k) takes 37. + he claims to use 280k of tables but the iteration calculation seems + to use only 128k. his tables and code are machine independent. + (code from glad@daimi.aau.dk via alt.sources or comp.sources.misc) + +swedish reimplementation of Kerberos des library + 108us per encryption (uses 34k worth of tables) + 134us to set a new key (uses 32k of key tables to get this speed!) + the tables used seem to be machine-independent; + he seems to have included a lot of special case code + so that, e.g., `long' loads can be used instead of 4 `char' loads + when the machine's architecture allows it. + (code obtained from chalmers.se:pub/des) + +crack 3.3c package from england: + as in crypt above, the des routine is buried in a loop. it's + also very modified for crypt. his iteration code uses 16k + of tables and appears to be slow. + (code obtained from aem@aber.ac.uk via alt.sources or comp.sources.misc) + +``highly optimized'' and tweaked Kerberos/Athena code (byte-order dependen= t): + 165us per encryption (uses 6k worth of tables) + 478us to set a new key (uses <1k of key tables) + so despite the comments in this code, it was possible to get + faster code AND smaller tables, as well as making the tables + machine-independent. + (code obtained from prep.ai.mit.edu) + +UC Berkeley code (depends on machine-endedness): + 226us per encryption +10848us to set a new key + table sizes are unclear, but they don't look very small + (code obtained from wuarchive.wustl.edu) + + +motivation and history + +a while ago i wanted some des routines and the routines documented on sun'= s +man pages either didn't exist or dumped core. i had heard of kerberos, +and knew that it used des, so i figured i'd use its routines. but once +i got it and looked at the code, it really set off a lot of pet peeves - +it was too convoluted, the code had been written without taking +advantage of the regular structure of operations such as IP, E, and FP +(i.e. the author didn't sit down and think before coding), +it was excessively slow, the author had attempted to clarify the code +by adding MORE statements to make the data movement more `consistent' +instead of simplifying his implementation and cutting down on all data +movement (in particular, his use of L1, R1, L2, R2), and it was full of +idiotic `tweaks' for particular machines which failed to deliver significa= nt +speedups but which did obfuscate everything. so i took the test data +from his verification program and rewrote everything else. + +a while later i ran across the great crypt(3) package mentioned above. +the fact that this guy was computing 2 sboxes per table lookup rather +than one (and using a MUCH larger table in the process) emboldened me to +do the same - it was a trivial change from which i had been scared away +by the larger table size. in his case he didn't realize you don't need to= keep +the working data in TWO forms, one for easy use of half the sboxes in +indexing, the other for easy use of the other half; instead you can keep +it in the form for the first half and use a simple rotate to get the other +half. this means i have (almost) half the data manipulation and half +the table size. in fairness though he might be encoding something particu= lar +to crypt(3) in his tables - i didn't check. + +i'm glad that i implemented it the way i did, because this C version is +portable (the ifdef's are performance enhancements) and it is faster +than versions hand-written in assembly for the sparc! + + +porting notes + +one thing i did not want to do was write an enormous mess +which depended on endedness and other machine quirks, +and which necessarily produced different code and different lookup tables +for different machines. see the kerberos code for an example +of what i didn't want to do; all their endedness-specific `optimizations' +obfuscate the code and in the end were slower than a simpler machine +independent approach. however, there are always some portability +considerations of some kind, and i have included some options +for varying numbers of register variables. +perhaps some will still regard the result as a mess! + +1) i assume everything is byte addressable, although i don't actually + depend on the byte order, and that bytes are 8 bits. + i assume word pointers can be freely cast to and from char pointers. + note that 99% of C programs make these assumptions. + i always use unsigned char's if the high bit could be set. +2) the typedef `word' means a 32 bit unsigned integral type. + if `unsigned long' is not 32 bits, change the typedef in desCore.h. + i assume sizeof(word) =3D=3D 4 EVERYWHERE. + +the (worst-case) cost of my NOT doing endedness-specific optimizations +in the data loading and storing code surrounding the key iterations +is less than 12%. also, there is the added benefit that +the input and output work areas do not need to be word-aligned. + + +OPTIONAL performance optimizations + +1) you should define one of `i386,' `vax,' `mc68000,' or `sparc,' + whichever one is closest to the capabilities of your machine. + see the start of desCode.h to see exactly what this selection implies. + note that if you select the wrong one, the des code will still work; + these are just performance tweaks. +2) for those with functional `asm' keywords: you should change the + ROR and ROL macros to use machine rotate instructions if you have them. + this will save 2 instructions and a temporary per use, + or about 32 to 40 instructions per en/decryption. + note that gcc is smart enough to translate the ROL/R macros into + machine rotates! + +these optimizations are all rather persnickety, yet with them you should +be able to get performance equal to assembly-coding, except that: +1) with the lack of a bit rotate operator in C, rotates have to be synthes= ized + from shifts. so access to `asm' will speed things up if your machine + has rotates, as explained above in (3) (not necessary if you use gcc). +2) if your machine has less than 12 32-bit registers i doubt your compiler= will + generate good code. + `i386' tries to configure the code for a 386 by only declaring 3 regist= ers + (it appears that gcc can use ebx, esi and edi to hold register variable= s). + however, if you like assembly coding, the 386 does have 7 32-bit regist= ers, + and if you use ALL of them, use `scaled by 8' address modes with displa= cement + and other tricks, you can get reasonable routines for DesQuickCore... w= ith + about 250 instructions apiece. For DesSmall... it will help to rearran= ge + des_keymap, i.e., now the sbox # is the high part of the index and + the 6 bits of data is the low part; it helps to exchange these. + since i have no way to conveniently test it i have not provided my + shoehorned 386 version. note that with this release of desCore, gcc is= able + to put everything in registers(!), and generate about 370 instructions = apiece + for the DesQuickCore... routines! + +coding notes + +the en/decryption routines each use 6 necessary register variables, +with 4 being actively used at once during the inner iterations. +if you don't have 4 register variables get a new machine. +up to 8 more registers are used to hold constants in some configurations. + +i assume that the use of a constant is more expensive than using a registe= r: +a) additionally, i have tried to put the larger constants in registers. + registering priority was by the following: + anything more than 12 bits (bad for RISC and CISC) + greater than 127 in value (can't use movq or byte immediate on CISC) + 9-127 (may not be able to use CISC shift immediate or add/sub quick), + 1-8 were never registered, being the cheapest constants. +b) the compiler may be too stupid to realize table and table+256 should + be assigned to different constant registers and instead repetitively + do the arithmetic, so i assign these to explicit `m' register variables + when possible and helpful. + +i assume that indexing is cheaper or equivalent to auto increment/decremen= t, +where the index is 7 bits unsigned or smaller. +this assumption is reversed for 68k and vax. + +i assume that addresses can be cheaply formed from two registers, +or from a register and a small constant. +for the 68000, the `two registers and small offset' form is used sparingly= . +all index scaling is done explicitly - no hidden shifts by log2(sizeof). + +the code is written so that even a dumb compiler +should never need more than one hidden temporary, +increasing the chance that everything will fit in the registers. +KEEP THIS MORE SUBTLE POINT IN MIND IF YOU REWRITE ANYTHING. +(actually, there are some code fragments now which do require two temps, +but fixing it would either break the structure of the macros or +require declaring another temporary). + + +special efficient data format + +bits are manipulated in this arrangement most of the time (S7 S5 S3 S1): + 003130292827xxxx242322212019xxxx161514131211xxxx080706050403xxxx +(the x bits are still there, i'm just emphasizing where the S boxes are). +bits are rotated left 4 when computing S6 S4 S2 S0: + 282726252423xxxx201918171615xxxx121110090807xxxx040302010031xxxx +the rightmost two bits are usually cleared so the lower byte can be used +as an index into an sbox mapping table. the next two x'd bits are set +to various values to access different parts of the tables. + + +how to use the routines + +datatypes: + pointer to 8 byte area of type DesData + used to hold keys and input/output blocks to des. + + pointer to 128 byte area of type DesKeys + used to hold full 768-bit key. + must be long-aligned. + +DesQuickInit() + call this before using any other routine with `Quick' in its name. + it generates the special 64k table these routines need. +DesQuickDone() + frees this table + +DesMethod(m, k) + m points to a 128byte block, k points to an 8 byte des key + which must have odd parity (or -1 is returned) and which must + not be a (semi-)weak key (or -2 is returned). + normally DesMethod() returns 0. + m is filled in from k so that when one of the routines below + is called with m, the routine will act like standard des + en/decryption with the key k. if you use DesMethod, + you supply a standard 56bit key; however, if you fill in + m yourself, you will get a 768bit key - but then it won't + be standard. it's 768bits not 1024 because the least significant + two bits of each byte are not used. note that these two bits + will be set to magic constants which speed up the encryption/decryption + on some machines. and yes, each byte controls + a specific sbox during a specific iteration. + you really shouldn't use the 768bit format directly; i should + provide a routine that converts 128 6-bit bytes (specified in + S-box mapping order or something) into the right format for you. + this would entail some byte concatenation and rotation. + +Des{Small|Quick}{Fips|Core}{Encrypt|Decrypt}(d, m, s) + performs des on the 8 bytes at s into the 8 bytes at d. (d,s: char *). + uses m as a 768bit key as explained above. + the Encrypt|Decrypt choice is obvious. + Fips|Core determines whether a completely standard FIPS initial + and final permutation is done; if not, then the data is loaded + and stored in a nonstandard bit order (FIPS w/o IP/FP). + Fips slows down Quick by 10%, Small by 9%. + Small|Quick determines whether you use the normal routine + or the crazy quick one which gobbles up 64k more of memory. + Small is 50% slower then Quick, but Quick needs 32 times as much + memory. Quick is included for programs that do nothing but DES, + e.g., encryption filters, etc. + + +Getting it to compile on your machine + +there are no machine-dependencies in the code (see porting), +except perhaps the `now()' macro in desTest.c. +ALL generated tables are machine independent. +you should edit the Makefile with the appropriate optimization flags +for your compiler (MAX optimization). + + +Speeding up kerberos (and/or its des library) + +note that i have included a kerberos-compatible interface in desUtil.c +through the functions des_key_sched() and des_ecb_encrypt(). +to use these with kerberos or kerberos-compatible code put desCore.a +ahead of the kerberos-compatible library on your linker's command line. +you should not need to #include desCore.h; just include the header +file provided with the kerberos library. + +Other uses + +the macros in desCode.h would be very useful for putting inline des +functions in more complicated encryption routines. diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Thu May 8 10:41:37 2003 +++ b/MAINTAINERS Thu May 8 10:41:37 2003 @@ -430,6 +430,15 @@ W: http://developer.axis.com S: Maintained =20 +CRYPTO API +P: James Morris +M: jmorris@intercode.com.au +P: David S. Miller +M: davem@redhat.com +W http://samba.org/~jamesm/crypto/ +L: linux-kernel@vger.kernel.org +S: Maintained + CYBERPRO FB DRIVER P: Russell King M: rmk@arm.linux.org.uk diff -Nru a/Makefile b/Makefile --- a/Makefile Thu May 8 10:41:36 2003 +++ b/Makefile Thu May 8 10:41:36 2003 @@ -125,7 +125,7 @@ NETWORKS =3Dnet/network.o =20 LIBS =3D$(TOPDIR)/lib/lib.a -SUBDIRS =3Dkernel drivers mm fs net ipc lib +SUBDIRS =3Dkernel drivers mm fs net ipc lib crypto =20 DRIVERS-n :=3D DRIVERS-y :=3D @@ -190,6 +190,7 @@ DRIVERS-$(CONFIG_BLUEZ) +=3D drivers/bluetooth/bluetooth.o DRIVERS-$(CONFIG_HOTPLUG_PCI) +=3D drivers/hotplug/vmlinux-obj.o DRIVERS-$(CONFIG_ISDN_BOOL) +=3D drivers/isdn/vmlinux-obj.o +DRIVERS-$(CONFIG_CRYPTO) +=3D crypto/crypto.o =20 DRIVERS :=3D $(DRIVERS-y) =20 diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in --- a/arch/alpha/config.in Thu May 8 10:41:37 2003 +++ b/arch/alpha/config.in Thu May 8 10:41:37 2003 @@ -443,4 +443,5 @@ =20 endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/arm/config.in b/arch/arm/config.in --- a/arch/arm/config.in Thu May 8 10:41:36 2003 +++ b/arch/arm/config.in Thu May 8 10:41:36 2003 @@ -656,4 +656,5 @@ dep_bool ' Kernel low-level debugging messages via UART2' CONFIG_DEBUG_= CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/cris/config.in b/arch/cris/config.in --- a/arch/cris/config.in Thu May 8 10:41:36 2003 +++ b/arch/cris/config.in Thu May 8 10:41:36 2003 @@ -261,5 +261,6 @@ int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi =20 +source crypto/Config.in source lib/Config.in endmenu diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Thu May 8 10:41:37 2003 +++ b/arch/i386/config.in Thu May 8 10:41:37 2003 @@ -484,4 +484,5 @@ =20 endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in --- a/arch/ia64/config.in Thu May 8 10:41:37 2003 +++ b/arch/ia64/config.in Thu May 8 10:41:37 2003 @@ -243,6 +243,7 @@ source drivers/usb/Config.in =20 source lib/Config.in + source crypto/Config.in =20 if [ "$CONFIG_EXPERIMENTAL" =3D "y" ]; then source net/bluetooth/Config.in diff -Nru a/arch/m68k/config.in b/arch/m68k/config.in --- a/arch/m68k/config.in Thu May 8 10:41:37 2003 +++ b/arch/m68k/config.in Thu May 8 10:41:37 2003 @@ -562,4 +562,5 @@ =20 endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/mips/config-shared.in b/arch/mips/config-shared.in --- a/arch/mips/config-shared.in Thu May 8 10:41:37 2003 +++ b/arch/mips/config-shared.in Thu May 8 10:41:37 2003 @@ -800,4 +800,5 @@ fi endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/parisc/config.in b/arch/parisc/config.in --- a/arch/parisc/config.in Thu May 8 10:41:38 2003 +++ b/arch/parisc/config.in Thu May 8 10:41:38 2003 @@ -196,4 +196,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in --- a/arch/ppc/config.in Thu May 8 10:41:37 2003 +++ b/arch/ppc/config.in Thu May 8 10:41:37 2003 @@ -411,6 +411,7 @@ =20 source net/bluetooth/Config.in =20 +source crypto/Config.in source lib/Config.in =20 mainmenu_option next_comment diff -Nru a/arch/ppc64/config.in b/arch/ppc64/config.in --- a/arch/ppc64/config.in Thu May 8 10:41:37 2003 +++ b/arch/ppc64/config.in Thu May 8 10:41:37 2003 @@ -231,6 +231,8 @@ =20 source lib/Config.in =20 +source crypto/Config.in + mainmenu_option next_comment comment 'Kernel hacking' =20 diff -Nru a/arch/s390/config.in b/arch/s390/config.in --- a/arch/s390/config.in Thu May 8 10:41:37 2003 +++ b/arch/s390/config.in Thu May 8 10:41:37 2003 @@ -75,4 +75,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/s390x/config.in b/arch/s390x/config.in --- a/arch/s390x/config.in Thu May 8 10:41:36 2003 +++ b/arch/s390x/config.in Thu May 8 10:41:36 2003 @@ -79,4 +79,5 @@ bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/sh/config.in b/arch/sh/config.in --- a/arch/sh/config.in Thu May 8 10:41:37 2003 +++ b/arch/sh/config.in Thu May 8 10:41:37 2003 @@ -387,4 +387,5 @@ fi endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in --- a/arch/sparc/config.in Thu May 8 10:41:36 2003 +++ b/arch/sparc/config.in Thu May 8 10:41:36 2003 @@ -275,4 +275,5 @@ =20 endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in --- a/arch/sparc64/config.in Thu May 8 10:41:37 2003 +++ b/arch/sparc64/config.in Thu May 8 10:41:37 2003 @@ -309,4 +309,5 @@ =20 endmenu =20 +source crypto/Config.in source lib/Config.in diff -Nru a/arch/x86_64/config.in b/arch/x86_64/config.in --- a/arch/x86_64/config.in Thu May 8 10:41:37 2003 +++ b/arch/x86_64/config.in Thu May 8 10:41:37 2003 @@ -232,6 +232,8 @@ =20 source net/bluetooth/Config.in =20 +source crypto/Config.in + mainmenu_option next_comment comment 'Kernel hacking' =20 diff -Nru a/crypto/Config.in b/crypto/Config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/Config.in Thu May 8 10:41:38 2003 @@ -0,0 +1,61 @@ +# +# Cryptographic API Configuration +# +mainmenu_option next_comment +comment 'Cryptographic options' + +if [ "$CONFIG_INET_AH" =3D "y" -o \ + "$CONFIG_INET_AH" =3D "m" -o \ + "$CONFIG_INET_ESP" =3D "y" -o \ + "$CONFIG_INET_ESP" =3D "m" ]; then + define_bool CONFIG_CRYPTO y +else + bool 'Cryptographic API' CONFIG_CRYPTO +fi + +if [ "$CONFIG_CRYPTO" =3D "y" ]; then + if [ "$CONFIG_INET_AH" =3D "y" -o \ + "$CONFIG_INET_AH" =3D "m" -o \ + "$CONFIG_INET_ESP" =3D "y" -o \ + "$CONFIG_INET_ESP" =3D "m" ]; then + define_bool CONFIG_CRYPTO_HMAC y + else + bool ' HMAC support' CONFIG_CRYPTO_HMAC + fi + tristate ' NULL algorithms' CONFIG_CRYPTO_NULL + tristate ' MD4 digest algorithm' CONFIG_CRYPTO_MD4 + if [ "$CONFIG_INET_AH" =3D "y" -o \ + "$CONFIG_INET_AH" =3D "m" -o \ + "$CONFIG_INET_ESP" =3D "y" -o \ + "$CONFIG_INET_ESP" =3D "m" ]; then + define_bool CONFIG_CRYPTO_MD5 y + else + tristate ' MD5 digest algorithm' CONFIG_CRYPTO_MD5 + fi + if [ "$CONFIG_INET_AH" =3D "y" -o \ + "$CONFIG_INET_AH" =3D "m" -o \ + "$CONFIG_INET_ESP" =3D "y" -o \ + "$CONFIG_INET_ESP" =3D "m" ]; then + define_bool CONFIG_CRYPTO_SHA1 y + else + tristate ' SHA1 digest algorithm' CONFIG_CRYPTO_SHA1 + fi + tristate ' SHA256 digest algorithm' CONFIG_CRYPTO_SHA256 + tristate ' SHA384 and SHA512 digest algorithms' CONFIG_CRYPTO_SHA= 512 + if [ "$CONFIG_INET_AH" =3D "y" -o \ + "$CONFIG_INET_AH" =3D "m" -o \ + "$CONFIG_INET_ESP" =3D "y" -o \ + "$CONFIG_INET_ESP" =3D "m" ]; then + define_bool CONFIG_CRYPTO_DES y + else + tristate ' DES and Triple DES EDE cipher algorithms' CONFIG_CRY= PTO_DES + fi + tristate ' Blowfish cipher algorithm' CONFIG_CRYPTO_BLOWFISH + tristate ' Twofish cipher algorithm' CONFIG_CRYPTO_TWOFISH + tristate ' Serpent cipher algorithm' CONFIG_CRYPTO_SERPENT + tristate ' AES cipher algorithms' CONFIG_CRYPTO_AES + tristate ' Deflate compression algorithm' CONFIG_CRYPTO_DEFLATE + tristate ' Testing module' CONFIG_CRYPTO_TEST +fi + +endmenu diff -Nru a/crypto/Makefile b/crypto/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/Makefile Thu May 8 10:41:38 2003 @@ -0,0 +1,31 @@ +# +# Cryptographic API +# + +O_TARGET :=3D crypto.o + +export-objs :=3D api.o hmac.o + +autoload-crypto-$(CONFIG_KMOD) =3D autoload.o +proc-crypto-$(CONFIG_PROC_FS) =3D proc.o + +obj-$(CONFIG_CRYPTO) +=3D api.o cipher.o digest.o compress.o \ + $(autoload-crypto-y) $(proc-crypto-y) + +obj-$(CONFIG_CRYPTO_HMAC) +=3D hmac.o +obj-$(CONFIG_CRYPTO_NULL) +=3D crypto_null.o +obj-$(CONFIG_CRYPTO_MD4) +=3D md4.o +obj-$(CONFIG_CRYPTO_MD5) +=3D md5.o +obj-$(CONFIG_CRYPTO_SHA1) +=3D sha1.o +obj-$(CONFIG_CRYPTO_SHA256) +=3D sha256.o +obj-$(CONFIG_CRYPTO_SHA512) +=3D sha512.o +obj-$(CONFIG_CRYPTO_DES) +=3D des.o +obj-$(CONFIG_CRYPTO_BLOWFISH) +=3D blowfish.o +obj-$(CONFIG_CRYPTO_TWOFISH) +=3D twofish.o +obj-$(CONFIG_CRYPTO_SERPENT) +=3D serpent.o +obj-$(CONFIG_CRYPTO_AES) +=3D aes.o +obj-$(CONFIG_CRYPTO_DEFLATE) +=3D deflate.o + +obj-$(CONFIG_CRYPTO_TEST) +=3D tcrypt.o + +include $(TOPDIR)/Rules.make diff -Nru a/crypto/aes.c b/crypto/aes.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/aes.c Thu May 8 10:41:38 2003 @@ -0,0 +1,469 @@ +/*=20 + * Cryptographic API. + * + * AES Cipher Algorithm. + * + * Based on Brian Gladman's code. + * + * Linux developers: + * Alexander Kjeldaas + * Herbert Valerio Riedel + * Kyle McMartin + * Adam J. Richter (conversion to 2.5 API). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * -----------------------------------------------------------------------= ---- + * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK= . + * All rights reserved. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binar= y + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this prod= uct + * may be distributed under the terms of the GNU General Public License (G= PL), + * in which case the provisions of the GPL apply INSTEAD OF those given ab= ove. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warrantie= s + * in respect of its properties, including, but not limited to, correctnes= s + * and/or fitness for purpose. + * -----------------------------------------------------------------------= ---- + */ + +/* Some changes from the Gladman version: + s/RIJNDAEL(e_key)/E_KEY/g + s/RIJNDAEL(d_key)/D_KEY/g +*/ + +#include +#include +#include +#include +#include +#include + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define AES_BLOCK_SIZE 16 + +static inline=20 +u32 generic_rotr32 (const u32 x, const unsigned bits) +{ + const unsigned n =3D bits % 32; + return (x >> n) | (x << (32 - n)); +} + +static inline=20 +u32 generic_rotl32 (const u32 x, const unsigned bits) +{ + const unsigned n =3D bits % 32; + return (x << n) | (x >> (32 - n)); +} + +#define rotl generic_rotl32 +#define rotr generic_rotr32 + +/* + * #define byte(x, nr) ((unsigned char)((x) >> (nr*8)))=20 + */ +inline static u8 +byte(const u32 x, const unsigned n) +{ + return x >> (n << 3); +} + +#define u32_in(x) le32_to_cpu(*(const u32 *)(x)) +#define u32_out(to, from) (*(u32 *)(to) =3D cpu_to_le32(from)) + +struct aes_ctx { + int key_length; + u32 E[60]; + u32 D[60]; +}; + +#define E_KEY ctx->E +#define D_KEY ctx->D + +static u8 pow_tab[256]; +static u8 log_tab[256]; +static u8 sbx_tab[256]; +static u8 isb_tab[256]; +static u32 rco_tab[10]; +static u32 ft_tab[4][256]; +static u32 it_tab[4][256]; + +static u32 fl_tab[4][256]; +static u32 il_tab[4][256]; + +static inline u8 +f_mult (u8 a, u8 b) +{ + u8 aa =3D log_tab[a], cc =3D aa + log_tab[b]; + + return pow_tab[cc + (cc < aa ? 1 : 0)]; +} + +#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) + +#define f_rn(bo, bi, n, k) \ + bo[n] =3D ft_tab[0][byte(bi[n],0)] ^ \ + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rn(bo, bi, n, k) \ + bo[n] =3D it_tab[0][byte(bi[n],0)] ^ \ + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#define ls_box(x) \ + ( fl_tab[0][byte(x, 0)] ^ \ + fl_tab[1][byte(x, 1)] ^ \ + fl_tab[2][byte(x, 2)] ^ \ + fl_tab[3][byte(x, 3)] ) + +#define f_rl(bo, bi, n, k) \ + bo[n] =3D fl_tab[0][byte(bi[n],0)] ^ \ + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] =3D il_tab[0][byte(bi[n],0)] ^ \ + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +static void +gen_tabs (void) +{ + u32 i, t; + u8 p, q; + + /* log and power tables for GF(2**8) finite field with + 0x011b as modular polynomial - the simplest prmitive + root is 0x03, used here to generate the tables */ + + for (i =3D 0, p =3D 1; i < 256; ++i) { + pow_tab[i] =3D (u8) p; + log_tab[p] =3D (u8) i; + + p ^=3D (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + log_tab[1] =3D 0; + + for (i =3D 0, p =3D 1; i < 10; ++i) { + rco_tab[i] =3D p; + + p =3D (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + for (i =3D 0; i < 256; ++i) { + p =3D (i ? pow_tab[255 - log_tab[i]] : 0); + q =3D ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); + p ^=3D 0x63 ^ q ^ ((q >> 6) | (q << 2)); + sbx_tab[i] =3D p; + isb_tab[p] =3D (u8) i; + } + + for (i =3D 0; i < 256; ++i) { + p =3D sbx_tab[i]; + + t =3D p; + fl_tab[0][i] =3D t; + fl_tab[1][i] =3D rotl (t, 8); + fl_tab[2][i] =3D rotl (t, 16); + fl_tab[3][i] =3D rotl (t, 24); + + t =3D ((u32) ff_mult (2, p)) | + ((u32) p << 8) | + ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); + + ft_tab[0][i] =3D t; + ft_tab[1][i] =3D rotl (t, 8); + ft_tab[2][i] =3D rotl (t, 16); + ft_tab[3][i] =3D rotl (t, 24); + + p =3D isb_tab[i]; + + t =3D p; + il_tab[0][i] =3D t; + il_tab[1][i] =3D rotl (t, 8); + il_tab[2][i] =3D rotl (t, 16); + il_tab[3][i] =3D rotl (t, 24); + + t =3D ((u32) ff_mult (14, p)) | + ((u32) ff_mult (9, p) << 8) | + ((u32) ff_mult (13, p) << 16) | + ((u32) ff_mult (11, p) << 24); + + it_tab[0][i] =3D t; + it_tab[1][i] =3D rotl (t, 8); + it_tab[2][i] =3D rotl (t, 16); + it_tab[3][i] =3D rotl (t, 24); + } +} + +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) *= 0x1b) + +#define imix_col(y,x) \ + u =3D star_x(x); \ + v =3D star_x(u); \ + w =3D star_x(v); \ + t =3D w ^ (x); \ + (y) =3D u ^ v ^ w; \ + (y) ^=3D rotr(u ^ t, 8) ^ \ + rotr(v ^ t, 16) ^ \ + rotr(t,24) + +/* initialise the key schedule from the user supplied key */ + +#define loop4(i) \ +{ t =3D rotr(t, 8); t =3D ls_box(t) ^ rco_tab[i]; \ + t ^=3D E_KEY[4 * i]; E_KEY[4 * i + 4] =3D t; \ + t ^=3D E_KEY[4 * i + 1]; E_KEY[4 * i + 5] =3D t; \ + t ^=3D E_KEY[4 * i + 2]; E_KEY[4 * i + 6] =3D t; \ + t ^=3D E_KEY[4 * i + 3]; E_KEY[4 * i + 7] =3D t; \ +} + +#define loop6(i) \ +{ t =3D rotr(t, 8); t =3D ls_box(t) ^ rco_tab[i]; \ + t ^=3D E_KEY[6 * i]; E_KEY[6 * i + 6] =3D t; \ + t ^=3D E_KEY[6 * i + 1]; E_KEY[6 * i + 7] =3D t; \ + t ^=3D E_KEY[6 * i + 2]; E_KEY[6 * i + 8] =3D t; \ + t ^=3D E_KEY[6 * i + 3]; E_KEY[6 * i + 9] =3D t; \ + t ^=3D E_KEY[6 * i + 4]; E_KEY[6 * i + 10] =3D t; \ + t ^=3D E_KEY[6 * i + 5]; E_KEY[6 * i + 11] =3D t; \ +} + +#define loop8(i) \ +{ t =3D rotr(t, 8); ; t =3D ls_box(t) ^ rco_tab[i]; \ + t ^=3D E_KEY[8 * i]; E_KEY[8 * i + 8] =3D t; \ + t ^=3D E_KEY[8 * i + 1]; E_KEY[8 * i + 9] =3D t; \ + t ^=3D E_KEY[8 * i + 2]; E_KEY[8 * i + 10] =3D t; \ + t ^=3D E_KEY[8 * i + 3]; E_KEY[8 * i + 11] =3D t; \ + t =3D E_KEY[8 * i + 4] ^ ls_box(t); \ + E_KEY[8 * i + 12] =3D t; \ + t ^=3D E_KEY[8 * i + 5]; E_KEY[8 * i + 13] =3D t; \ + t ^=3D E_KEY[8 * i + 6]; E_KEY[8 * i + 14] =3D t; \ + t ^=3D E_KEY[8 * i + 7]; E_KEY[8 * i + 15] =3D t; \ +} + +static int +aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *fl= ags) +{ + struct aes_ctx *ctx =3D ctx_arg; + u32 i, t, u, v, w; + + if (key_len !=3D 16 && key_len !=3D 24 && key_len !=3D 32) { + *flags |=3D CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->key_length =3D key_len; + + E_KEY[0] =3D u32_in (in_key); + E_KEY[1] =3D u32_in (in_key + 4); + E_KEY[2] =3D u32_in (in_key + 8); + E_KEY[3] =3D u32_in (in_key + 12); + + switch (key_len) { + case 16: + t =3D E_KEY[3]; + for (i =3D 0; i < 10; ++i) + loop4 (i); + break; + + case 24: + E_KEY[4] =3D u32_in (in_key + 16); + t =3D E_KEY[5] =3D u32_in (in_key + 20); + for (i =3D 0; i < 8; ++i) + loop6 (i); + break; + + case 32: + E_KEY[4] =3D u32_in (in_key + 16); + E_KEY[5] =3D u32_in (in_key + 20); + E_KEY[6] =3D u32_in (in_key + 24); + t =3D E_KEY[7] =3D u32_in (in_key + 28); + for (i =3D 0; i < 7; ++i) + loop8 (i); + break; + } + + D_KEY[0] =3D E_KEY[0]; + D_KEY[1] =3D E_KEY[1]; + D_KEY[2] =3D E_KEY[2]; + D_KEY[3] =3D E_KEY[3]; + + for (i =3D 4; i < key_len + 24; ++i) { + imix_col (D_KEY[i], E_KEY[i]); + } + + return 0; +} + +/* encrypt a block of text */ + +#define f_nround(bo, bi, k) \ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k +=3D 4 + +#define f_lround(bo, bi, k) \ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k) + +static void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx =3D ctx_arg; + u32 b0[4], b1[4]; + const u32 *kp =3D E_KEY + 4; + + b0[0] =3D u32_in (in) ^ E_KEY[0]; + b0[1] =3D u32_in (in + 4) ^ E_KEY[1]; + b0[2] =3D u32_in (in + 8) ^ E_KEY[2]; + b0[3] =3D u32_in (in + 12) ^ E_KEY[3]; + + if (ctx->key_length > 24) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + if (ctx->key_length > 16) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_lround (b0, b1, kp); + + u32_out (out, b0[0]); + u32_out (out + 4, b0[1]); + u32_out (out + 8, b0[2]); + u32_out (out + 12, b0[3]); +} + +/* decrypt a block of text */ + +#define i_nround(bo, bi, k) \ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k -=3D 4 + +#define i_lround(bo, bi, k) \ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k) + +static void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx =3D ctx_arg; + u32 b0[4], b1[4]; + const int key_len =3D ctx->key_length; + const u32 *kp =3D D_KEY + key_len + 20; + + b0[0] =3D u32_in (in) ^ E_KEY[key_len + 24]; + b0[1] =3D u32_in (in + 4) ^ E_KEY[key_len + 25]; + b0[2] =3D u32_in (in + 8) ^ E_KEY[key_len + 26]; + b0[3] =3D u32_in (in + 12) ^ E_KEY[key_len + 27]; + + if (key_len > 24) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + if (key_len > 16) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_lround (b0, b1, kp); + + u32_out (out, b0[0]); + u32_out (out + 4, b0[1]); + u32_out (out + 8, b0[2]); + u32_out (out + 12, b0[3]); +} + + +static struct crypto_alg aes_alg =3D { + .cra_name =3D "aes", + .cra_flags =3D CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize =3D AES_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct aes_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u =3D { + .cipher =3D { + .cia_min_keysize =3D AES_MIN_KEY_SIZE, + .cia_max_keysize =3D AES_MAX_KEY_SIZE, + .cia_ivsize =3D AES_BLOCK_SIZE, + .cia_setkey =3D aes_set_key, + .cia_encrypt =3D aes_encrypt, + .cia_decrypt =3D aes_decrypt + } + } +}; + +static int __init aes_init(void) +{ + gen_tabs(); + return crypto_register_alg(&aes_alg); +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); +MODULE_LICENSE("Dual BSD/GPL"); + diff -Nru a/crypto/api.c b/crypto/api.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/api.c Thu May 8 10:41:38 2003 @@ -0,0 +1,227 @@ +/* + * Scatterlist Cryptographic API. + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * + * Portions derived from Cryptoapi, by Alexander Kjeldaas + * and Nettle, by Niels M=F6ller. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include "internal.h" + +LIST_HEAD(crypto_alg_list); +DECLARE_RWSEM(crypto_alg_sem); + +static inline int crypto_alg_get(struct crypto_alg *alg) +{ + return try_inc_mod_count(alg->cra_module); +} + +static inline void crypto_alg_put(struct crypto_alg *alg) +{ + if (alg->cra_module) + __MOD_DEC_USE_COUNT(alg->cra_module); +} + +struct crypto_alg *crypto_alg_lookup(const char *name) +{ + struct crypto_alg *q, *alg =3D NULL; +=09 + down_read(&crypto_alg_sem); +=09 + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (!(strcmp(q->cra_name, name))) { + if (crypto_alg_get(q)) + alg =3D q; + break; + } + } +=09 + up_read(&crypto_alg_sem); + return alg; +} + +static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) +{ + tfm->crt_flags =3D 0; +=09 + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + return crypto_init_cipher_flags(tfm, flags); + =09 + case CRYPTO_ALG_TYPE_DIGEST: + return crypto_init_digest_flags(tfm, flags); + =09 + case CRYPTO_ALG_TYPE_COMPRESS: + return crypto_init_compress_flags(tfm, flags); +=09 + default: + break; + } +=09 + BUG(); + return -EINVAL; +} + +static int crypto_init_ops(struct crypto_tfm *tfm) +{ + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + return crypto_init_cipher_ops(tfm); + =09 + case CRYPTO_ALG_TYPE_DIGEST: + return crypto_init_digest_ops(tfm); + =09 + case CRYPTO_ALG_TYPE_COMPRESS: + return crypto_init_compress_ops(tfm); +=09 + default: + break; + } +=09 + BUG(); + return -EINVAL; +} + +static void crypto_exit_ops(struct crypto_tfm *tfm) +{ + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + crypto_exit_cipher_ops(tfm); + break; + =09 + case CRYPTO_ALG_TYPE_DIGEST: + crypto_exit_digest_ops(tfm); + break; + =09 + case CRYPTO_ALG_TYPE_COMPRESS: + crypto_exit_compress_ops(tfm); + break; +=09 + default: + BUG(); + =09 + } +} + +struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) +{ + struct crypto_tfm *tfm =3D NULL; + struct crypto_alg *alg; + + alg =3D crypto_alg_mod_lookup(name); + if (alg =3D=3D NULL) + goto out; +=09 + tfm =3D kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL); + if (tfm =3D=3D NULL) + goto out_put; + + memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize); +=09 + tfm->__crt_alg =3D alg; +=09 + if (crypto_init_flags(tfm, flags)) + goto out_free_tfm; + =09 + if (crypto_init_ops(tfm)) { + crypto_exit_ops(tfm); + goto out_free_tfm; + } + + goto out; + +out_free_tfm: + kfree(tfm); + tfm =3D NULL; +out_put: + crypto_alg_put(alg); +out: + return tfm; +} + +void crypto_free_tfm(struct crypto_tfm *tfm) +{ + crypto_exit_ops(tfm); + crypto_alg_put(tfm->__crt_alg); + kfree(tfm); +} + +int crypto_register_alg(struct crypto_alg *alg) +{ + int ret =3D 0; + struct crypto_alg *q; +=09 + down_write(&crypto_alg_sem); +=09 + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (!(strcmp(q->cra_name, alg->cra_name))) { + ret =3D -EEXIST; + goto out; + } + } +=09 + list_add_tail(&alg->cra_list, &crypto_alg_list); +out:=09 + up_write(&crypto_alg_sem); + return ret; +} + +int crypto_unregister_alg(struct crypto_alg *alg) +{ + int ret =3D -ENOENT; + struct crypto_alg *q; +=09 + BUG_ON(!alg->cra_module); +=09 + down_write(&crypto_alg_sem); + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (alg =3D=3D q) { + list_del(&alg->cra_list); + ret =3D 0; + goto out; + } + } +out:=09 + up_write(&crypto_alg_sem); + return ret; +} + +int crypto_alg_available(const char *name, u32 flags) +{ + int ret =3D 0; + struct crypto_alg *alg =3D crypto_alg_mod_lookup(name); +=09 + if (alg) { + crypto_alg_put(alg); + ret =3D 1; + } +=09 + return ret; +} + +static int __init init_crypto(void) +{ + printk(KERN_INFO "Initializing Cryptographic API\n"); + crypto_init_proc(); + return 0; +} + +__initcall(init_crypto); + +EXPORT_SYMBOL_GPL(crypto_register_alg); +EXPORT_SYMBOL_GPL(crypto_unregister_alg); +EXPORT_SYMBOL_GPL(crypto_alloc_tfm); +EXPORT_SYMBOL_GPL(crypto_free_tfm); +EXPORT_SYMBOL_GPL(crypto_alg_available); diff -Nru a/crypto/autoload.c b/crypto/autoload.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/autoload.c Thu May 8 10:41:38 2003 @@ -0,0 +1,37 @@ +/* + * Cryptographic API. + * + * Algorithm autoloader. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include "internal.h" + +/* + * A far more intelligent version of this is planned. For now, just + * try an exact match on the name of the algorithm. + */ +void crypto_alg_autoload(const char *name) +{ + request_module(name); +} + +struct crypto_alg *crypto_alg_mod_lookup(const char *name) +{ + struct crypto_alg *alg =3D crypto_alg_lookup(name); + if (alg =3D=3D NULL) { + crypto_alg_autoload(name); + alg =3D crypto_alg_lookup(name); + } + return alg; +} diff -Nru a/crypto/blowfish.c b/crypto/blowfish.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/blowfish.c Thu May 8 10:41:38 2003 @@ -0,0 +1,479 @@ +/*=20 + * Cryptographic API. + * + * Blowfish Cipher Algorithm, by Bruce Schneier. + * http://www.counterpane.com/blowfish.html + *=20 + * Adapated from Kerneli implementation. + *=20 + * Copyright (c) Herbert Valerio Riedel + * Copyright (c) Kyle McMartin + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include + +#define BF_BLOCK_SIZE 8 +#define BF_MIN_KEY_SIZE 4 +#define BF_MAX_KEY_SIZE 56 + +struct bf_ctx { + u32 p[18]; + u32 s[1024]; +}; + +static const u32 bf_pbox[16 + 2] =3D { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b, +}; + +static const u32 bf_sbox[256 * 4] =3D { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, +}; + +/*=20 + * Round loop unrolling macros, S is a pointer to a S-Box array + * organized in 4 unsigned longs at a row. + */ +#define GET32_3(x) (((x) & 0xff)) +#define GET32_2(x) (((x) >> (8)) & (0xff)) +#define GET32_1(x) (((x) >> (16)) & (0xff)) +#define GET32_0(x) (((x) >> (24)) & (0xff)) + +#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \ + S[512 + GET32_2(x)]) + S[768 + GET32_3(x)]) + +#define ROUND(a, b, n) b ^=3D P[n]; a ^=3D bf_F (b) + +/* + * The blowfish encipher, processes 64-bit blocks. + * NOTE: This function MUSTN'T respect endianess=20 + */ +static inline void encrypt_block(struct bf_ctx *bctx, u32 *dst, u32 *src) +{ + const u32 *P =3D bctx->p; + const u32 *S =3D bctx->s; + u32 yl =3D src[0]; + u32 yr =3D src[1]; + + ROUND(yr, yl, 0); + ROUND(yl, yr, 1); + ROUND(yr, yl, 2); + ROUND(yl, yr, 3); + ROUND(yr, yl, 4); + ROUND(yl, yr, 5); + ROUND(yr, yl, 6); + ROUND(yl, yr, 7); + ROUND(yr, yl, 8); + ROUND(yl, yr, 9); + ROUND(yr, yl, 10); + ROUND(yl, yr, 11); + ROUND(yr, yl, 12); + ROUND(yl, yr, 13); + ROUND(yr, yl, 14); + ROUND(yl, yr, 15); + + yl ^=3D P[16]; + yr ^=3D P[17]; + + dst[0] =3D yr; + dst[1] =3D yl; +} + +static void bf_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + const u32 *in_blk =3D (const u32 *)src; + u32 *const out_blk =3D (u32 *)dst; + u32 in32[2], out32[2]; + + in32[0] =3D be32_to_cpu(in_blk[0]); + in32[1] =3D be32_to_cpu(in_blk[1]); + encrypt_block(ctx, out32, in32); + out_blk[0] =3D cpu_to_be32(out32[0]); + out_blk[1] =3D cpu_to_be32(out32[1]); +} + +static void bf_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + const u32 *in_blk =3D (const u32 *)src; + u32 *const out_blk =3D (u32 *)dst; + const u32 *P =3D ((struct bf_ctx *)ctx)->p; + const u32 *S =3D ((struct bf_ctx *)ctx)->s; + u32 yl =3D be32_to_cpu(in_blk[0]); + u32 yr =3D be32_to_cpu(in_blk[1]); + + ROUND(yr, yl, 17); + ROUND(yl, yr, 16); + ROUND(yr, yl, 15); + ROUND(yl, yr, 14); + ROUND(yr, yl, 13); + ROUND(yl, yr, 12); + ROUND(yr, yl, 11); + ROUND(yl, yr, 10); + ROUND(yr, yl, 9); + ROUND(yl, yr, 8); + ROUND(yr, yl, 7); + ROUND(yl, yr, 6); + ROUND(yr, yl, 5); + ROUND(yl, yr, 4); + ROUND(yr, yl, 3); + ROUND(yl, yr, 2); + + yl ^=3D P[1]; + yr ^=3D P[0]; + + out_blk[0] =3D cpu_to_be32(yr); + out_blk[1] =3D cpu_to_be32(yl); +} + +/*=20 + * Calculates the blowfish S and P boxes for encryption and decryption. + */ +static int bf_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *f= lags) +{ + short i, j, count; + u32 data[2], temp; + u32 *P =3D ((struct bf_ctx *)ctx)->p; + u32 *S =3D ((struct bf_ctx *)ctx)->s; + + /* Copy the initialization s-boxes */ + for (i =3D 0, count =3D 0; i < 256; i++) + for (j =3D 0; j < 4; j++, count++) + S[count] =3D bf_sbox[count]; + + /* Set the p-boxes */ + for (i =3D 0; i < 16 + 2; i++) + P[i] =3D bf_pbox[i]; + + /* Actual subkey generation */ + for (j =3D 0, i =3D 0; i < 16 + 2; i++) { + temp =3D (((u32 )key[j] << 24) | + ((u32 )key[(j + 1) % keylen] << 16) | + ((u32 )key[(j + 2) % keylen] << 8) | + ((u32 )key[(j + 3) % keylen])); + + P[i] =3D P[i] ^ temp; + j =3D (j + 4) % keylen; + } + + data[0] =3D 0x00000000; + data[1] =3D 0x00000000; + + for (i =3D 0; i < 16 + 2; i +=3D 2) { + encrypt_block((struct bf_ctx *)ctx, data, data); + + P[i] =3D data[0]; + P[i + 1] =3D data[1]; + } + + for (i =3D 0; i < 4; i++) { + for (j =3D 0, count =3D i * 256; j < 256; j +=3D 2, count +=3D 2) { + encrypt_block((struct bf_ctx *)ctx, data, data); + + S[count] =3D data[0]; + S[count + 1] =3D data[1]; + } + } +=09 + /* Bruce says not to bother with the weak key check. */ + return 0; +} + +static struct crypto_alg alg =3D { + .cra_name =3D "blowfish", + .cra_flags =3D CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize =3D BF_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct bf_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(alg.cra_list), + .cra_u =3D { .cipher =3D { + .cia_min_keysize =3D BF_MIN_KEY_SIZE, + .cia_max_keysize =3D BF_MAX_KEY_SIZE, + .cia_ivsize =3D BF_BLOCK_SIZE, + .cia_setkey =3D bf_setkey, + .cia_encrypt =3D bf_encrypt, + .cia_decrypt =3D bf_decrypt } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Blowfish Cipher Algorithm"); diff -Nru a/crypto/cipher.c b/crypto/cipher.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/cipher.c Thu May 8 10:41:38 2003 @@ -0,0 +1,417 @@ +/* + * Cryptographic API. + * + * Cipher operations. + * + * Copyright (c) 2002 James Morris + * Generic scatterwalk code by Adam J. Richter . + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +typedef void (cryptfn_t)(void *, u8 *, const u8 *); +typedef void (procfn_t)(struct crypto_tfm *, u8 *, + u8*, cryptfn_t, int enc, void *); + +struct scatter_walk { + struct scatterlist *sg; + struct page *page; + void *data; + unsigned int len_this_page; + unsigned int len_this_segment; + unsigned int offset; +}; + +enum km_type crypto_km_types[] =3D { + KM_USER0, + KM_USER1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, +}; + +static inline void xor_64(u8 *a, const u8 *b) +{ + ((u32 *)a)[0] ^=3D ((u32 *)b)[0]; + ((u32 *)a)[1] ^=3D ((u32 *)b)[1]; +} + +static inline void xor_128(u8 *a, const u8 *b) +{ + ((u32 *)a)[0] ^=3D ((u32 *)b)[0]; + ((u32 *)a)[1] ^=3D ((u32 *)b)[1]; + ((u32 *)a)[2] ^=3D ((u32 *)b)[2]; + ((u32 *)a)[3] ^=3D ((u32 *)b)[3]; +} + + +/* Define sg_next is an inline routine now in case we want to change + scatterlist to a linked list later. */ +static inline struct scatterlist *sg_next(struct scatterlist *sg) +{ + return sg + 1; +} + +void *which_buf(struct scatter_walk *walk, unsigned int nbytes, void *scra= tch) +{ + if (nbytes <=3D walk->len_this_page && + (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <=3D + PAGE_CACHE_SIZE) + return walk->data; + else + return scratch; +} + +static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) +{ + if (out) + memcpy(sgdata, buf, nbytes); + else + memcpy(buf, sgdata, nbytes); +} + +static void scatterwalk_start(struct scatter_walk *walk, struct scatterlis= t *sg) +{ + unsigned int rest_of_page; + + walk->sg =3D sg; + + walk->page =3D sg->page; + walk->len_this_segment =3D sg->length; + + rest_of_page =3D PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); + walk->len_this_page =3D min(sg->length, rest_of_page); + walk->offset =3D sg->offset; +} + +static void scatterwalk_map(struct scatter_walk *walk, int out) +{ + walk->data =3D crypto_kmap(walk->page, out) + walk->offset; +} + +static void scatter_page_done(struct scatter_walk *walk, int out, + unsigned int more) +{ + /* walk->data may be pointing the first byte of the next page; + however, we know we transfered at least one byte. So, + walk->data - 1 will be a virutual address in the mapped page. */ + + if (out) + flush_dcache_page(walk->page); + + if (more) { + walk->len_this_segment -=3D walk->len_this_page; + + if (walk->len_this_segment) { + walk->page++; + walk->len_this_page =3D min(walk->len_this_segment, + (unsigned)PAGE_CACHE_SIZE); + walk->offset =3D 0; + } + else + scatterwalk_start(walk, sg_next(walk->sg)); + } +} + +static void scatter_done(struct scatter_walk *walk, int out, int more) +{ + crypto_kunmap(walk->data, out); + if (walk->len_this_page =3D=3D 0 || !more) + scatter_page_done(walk, out, more); +} + +/* + * Do not call this unless the total length of all of the fragments=20 + * has been verified as multiple of the block size. + */ +static int copy_chunks(void *buf, struct scatter_walk *walk, + size_t nbytes, int out) +{ + if (buf !=3D walk->data) { + while (nbytes > walk->len_this_page) { + memcpy_dir(buf, walk->data, walk->len_this_page, out); + buf +=3D walk->len_this_page; + nbytes -=3D walk->len_this_page; + + crypto_kunmap(walk->data, out); + scatter_page_done(walk, out, 1); + scatterwalk_map(walk, out); + } + + memcpy_dir(buf, walk->data, nbytes, out); + } + + walk->offset +=3D nbytes; + walk->len_this_page -=3D nbytes; + walk->len_this_segment -=3D nbytes; + return 0; +} + +/*=20 + * Generic encrypt/decrypt wrapper for ciphers, handles operations across + * multiple page boundaries by using temporary blocks. In user context, + * the kernel is given a chance to schedule us once per block. + */ +static int crypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, cryptfn_t crfn, + procfn_t prfn, int enc, void *info) +{ + struct scatter_walk walk_in, walk_out; + const unsigned int bsize =3D crypto_tfm_alg_blocksize(tfm); + u8 tmp_src[nbytes > src->length ? bsize : 0]; + u8 tmp_dst[nbytes > dst->length ? bsize : 0]; + + if (!nbytes) + return 0; + + if (nbytes % bsize) { + tfm->crt_flags |=3D CRYPTO_TFM_RES_BAD_BLOCK_LEN; + return -EINVAL; + } + + scatterwalk_start(&walk_in, src); + scatterwalk_start(&walk_out, dst); + + for(;;) { + u8 *src_p, *dst_p; + + scatterwalk_map(&walk_in, 0); + scatterwalk_map(&walk_out, 1); + src_p =3D which_buf(&walk_in, bsize, tmp_src); + dst_p =3D which_buf(&walk_out, bsize, tmp_dst); + + nbytes -=3D bsize; + + copy_chunks(src_p, &walk_in, bsize, 0); + + prfn(tfm, dst_p, src_p, crfn, enc, info); + + scatter_done(&walk_in, 0, nbytes); + + copy_chunks(dst_p, &walk_out, bsize, 1); + scatter_done(&walk_out, 1, nbytes); + + if (!nbytes) + return 0; + + crypto_yield(tfm); + } +} + +static void cbc_process(struct crypto_tfm *tfm, + u8 *dst, u8 *src, cryptfn_t fn, int enc, void *inf= o) +{ + u8 *iv =3D info; +=09 + /* Null encryption */ + if (!iv) + return; + =09 + if (enc) { + tfm->crt_u.cipher.cit_xor_block(iv, src); + fn(crypto_tfm_ctx(tfm), dst, iv); + memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm)); + } else { + const int need_stack =3D (src =3D=3D dst); + u8 stack[need_stack ? crypto_tfm_alg_blocksize(tfm) : 0]; + u8 *buf =3D need_stack ? stack : dst; + =09 + fn(crypto_tfm_ctx(tfm), buf, src); + tfm->crt_u.cipher.cit_xor_block(buf, iv); + memcpy(iv, src, crypto_tfm_alg_blocksize(tfm)); + if (buf !=3D dst) + memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm)); + } +} + +static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, + cryptfn_t fn, int enc, void *info) +{ + fn(crypto_tfm_ctx(tfm), dst, src); +} + +static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keyl= en) +{ + struct cipher_alg *cia =3D &tfm->__crt_alg->cra_cipher; +=09 + if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { + tfm->crt_flags |=3D CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } else + return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen, + &tfm->crt_flags); +} + +static int ecb_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + ecb_process, 1, NULL); +} + +static int ecb_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + ecb_process, 1, NULL); +} + +static int cbc_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + cbc_process, 1, tfm->crt_cipher.cit_iv); +} + +static int cbc_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + cbc_process, 1, iv); +} + +static int cbc_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + cbc_process, 0, tfm->crt_cipher.cit_iv); +} + +static int cbc_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + cbc_process, 0, iv); +} + +static int nocrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return -ENOSYS; +} + +static int nocrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return -ENOSYS; +} + +int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) +{ + u32 mode =3D flags & CRYPTO_TFM_MODE_MASK; +=09 + tfm->crt_cipher.cit_mode =3D mode ? mode : CRYPTO_TFM_MODE_ECB; + if (flags & CRYPTO_TFM_REQ_WEAK_KEY) + tfm->crt_flags =3D CRYPTO_TFM_REQ_WEAK_KEY; +=09 + return 0; +} + +int crypto_init_cipher_ops(struct crypto_tfm *tfm) +{ + int ret =3D 0; + struct crypto_alg *alg =3D tfm->__crt_alg; + struct cipher_tfm *ops =3D &tfm->crt_cipher; + + ops->cit_setkey =3D setkey; + + switch (tfm->crt_cipher.cit_mode) { + case CRYPTO_TFM_MODE_ECB: + ops->cit_encrypt =3D ecb_encrypt; + ops->cit_decrypt =3D ecb_decrypt; + break; + =09 + case CRYPTO_TFM_MODE_CBC: + ops->cit_encrypt =3D cbc_encrypt; + ops->cit_decrypt =3D cbc_decrypt; + ops->cit_encrypt_iv =3D cbc_encrypt_iv; + ops->cit_decrypt_iv =3D cbc_decrypt_iv; + break; + =09 + case CRYPTO_TFM_MODE_CFB: + ops->cit_encrypt =3D nocrypt; + ops->cit_decrypt =3D nocrypt; + ops->cit_encrypt_iv =3D nocrypt_iv; + ops->cit_decrypt_iv =3D nocrypt_iv; + break; +=09 + case CRYPTO_TFM_MODE_CTR: + ops->cit_encrypt =3D nocrypt; + ops->cit_decrypt =3D nocrypt; + ops->cit_encrypt_iv =3D nocrypt_iv; + ops->cit_decrypt_iv =3D nocrypt_iv; + break; + + default: + BUG(); + } +=09 + if (alg->cra_cipher.cia_ivsize && + ops->cit_mode !=3D CRYPTO_TFM_MODE_ECB) { + =09 + switch (crypto_tfm_alg_blocksize(tfm)) { + case 8: + ops->cit_xor_block =3D xor_64; + break; + =09 + case 16: + ops->cit_xor_block =3D xor_128; + break; + =09 + default: + printk(KERN_WARNING "%s: block size %u not supported\n", + crypto_tfm_alg_name(tfm), + crypto_tfm_alg_blocksize(tfm)); + ret =3D -EINVAL; + goto out; + } + =09 + ops->cit_iv =3D kmalloc(alg->cra_cipher.cia_ivsize, GFP_KERNEL); + if (ops->cit_iv =3D=3D NULL) + ret =3D -ENOMEM; + } + +out:=09 + return ret; +} + +void crypto_exit_cipher_ops(struct crypto_tfm *tfm) +{ + if (tfm->crt_cipher.cit_iv) + kfree(tfm->crt_cipher.cit_iv); +} diff -Nru a/crypto/compress.c b/crypto/compress.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/compress.c Thu May 8 10:41:38 2003 @@ -0,0 +1,63 @@ +/* + * Cryptographic API. + * + * Compression operations. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include "internal.h" + +static int crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); +} + +static int crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); +} + +int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) +{ + return flags ? -EINVAL : 0; +} + +int crypto_init_compress_ops(struct crypto_tfm *tfm) +{ + int ret =3D 0; + struct compress_tfm *ops =3D &tfm->crt_compress; +=09 + ret =3D tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm)); + if (ret) + goto out; + + ops->cot_compress =3D crypto_compress; + ops->cot_decompress =3D crypto_decompress; +=09 +out: + return ret; +} + +void crypto_exit_compress_ops(struct crypto_tfm *tfm) +{ + tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm)); +} diff -Nru a/crypto/crypto_null.c b/crypto/crypto_null.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/crypto_null.c Thu May 8 10:41:38 2003 @@ -0,0 +1,134 @@ +/*=20 + * Cryptographic API. + * + * Null algorithms, aka Much Ado About Nothing. + * + * These are needed for IPsec, and may be useful in general for + * testing & debugging. + *=20 + * The null cipher is compliant with RFC2410. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include + +#define NULL_KEY_SIZE 0 +#define NULL_BLOCK_SIZE 1 +#define NULL_DIGEST_SIZE 0 + +static int null_compress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ return 0; } + +static int null_decompress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ return 0; } + +static void null_init(void *ctx) +{ } + +static void null_update(void *ctx, const u8 *data, unsigned int len) +{ } + +static void null_final(void *ctx, u8 *out) +{ } + +static int null_setkey(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags) +{ return 0; } + +static void null_encrypt(void *ctx, u8 *dst, const u8 *src) +{ } + +static void null_decrypt(void *ctx, u8 *dst, const u8 *src) +{ } + +static struct crypto_alg compress_null =3D { + .cra_name =3D "compress_null", + .cra_flags =3D CRYPTO_ALG_TYPE_COMPRESS, + .cra_blocksize =3D NULL_BLOCK_SIZE, + .cra_ctxsize =3D 0, + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(compress_null.cra_list), + .cra_u =3D { .compress =3D { + .coa_compress =3D null_compress, + .coa_decompress =3D null_decompress } } +}; + +static struct crypto_alg digest_null =3D { + .cra_name =3D "digest_null", + .cra_flags =3D CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize =3D NULL_BLOCK_SIZE, + .cra_ctxsize =3D 0, + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(digest_null.cra_list),=09 + .cra_u =3D { .digest =3D { + .dia_digestsize =3D NULL_DIGEST_SIZE, + .dia_init =3D null_init, + .dia_update =3D null_update, + .dia_final =3D null_final } } +}; + +static struct crypto_alg cipher_null =3D { + .cra_name =3D "cipher_null", + .cra_flags =3D CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize =3D NULL_BLOCK_SIZE, + .cra_ctxsize =3D 0, + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(cipher_null.cra_list), + .cra_u =3D { .cipher =3D { + .cia_min_keysize =3D NULL_KEY_SIZE, + .cia_max_keysize =3D NULL_KEY_SIZE, + .cia_ivsize =3D 0, + .cia_setkey =3D null_setkey, + .cia_encrypt =3D null_encrypt, + .cia_decrypt =3D null_decrypt } } +}; + +static int __init init(void) +{ + int ret =3D 0; +=09 + ret =3D crypto_register_alg(&cipher_null); + if (ret < 0) + goto out; + + ret =3D crypto_register_alg(&digest_null); + if (ret < 0) { + crypto_unregister_alg(&cipher_null); + goto out; + } + + ret =3D crypto_register_alg(&compress_null); + if (ret < 0) { + crypto_unregister_alg(&digest_null); + crypto_unregister_alg(&cipher_null); + goto out; + } + +out:=09 + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&compress_null); + crypto_unregister_alg(&digest_null); + crypto_unregister_alg(&cipher_null); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Null Cryptographic Algorithms"); diff -Nru a/crypto/deflate.c b/crypto/deflate.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/deflate.c Thu May 8 10:41:38 2003 @@ -0,0 +1,236 @@ +/*=20 + * Cryptographic API. + * + * Deflate algorithm (RFC 1951), implemented here primarily for use + * by IPCOMP (RFC 3173 & RFC 2394). + * + * Copyright (c) 2003 James Morris + *=20 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + * FIXME: deflate transforms will require up to a total of about 436k of k= ernel + * memory on i386 (390k for compression, the rest for decompression), as t= he + * current zlib kernel code uses a worst case pre-allocation system by def= ault. + * This needs to be fixed so that the amount of memory required is properl= y + * related to the winbits and memlevel parameters. + * + * The default winbits of 11 should suit most packets, and it may be somet= hing + * to configure on a per-tfm basis in the future. + * + * Currently, compression history is not maintained between tfm calls, as + * it is not needed for IPCOMP and keeps the code simpler. It can be + * implemented if someone wants it. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION +#define DEFLATE_DEF_WINBITS 11 +#define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL + +struct deflate_ctx { + int comp_initialized; + int decomp_initialized; + struct z_stream_s comp_stream; + struct z_stream_s decomp_stream; +}; + +static inline int deflate_gfp(void) +{ + return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; +} + +static int deflate_init(void *ctx) +{ + return 0; +} + +static void deflate_exit(void *ctx) +{ + struct deflate_ctx *dctx =3D ctx; + + if (dctx->comp_initialized) + vfree(dctx->comp_stream.workspace); + if (dctx->decomp_initialized) + kfree(dctx->decomp_stream.workspace); +} + +/* + * Lazy initialization to make interface simple without allocating + * un-needed workspaces. Thus can be called in softirq context. + */ +static int deflate_comp_init(struct deflate_ctx *ctx) +{ + int ret =3D 0; + struct z_stream_s *stream =3D &ctx->comp_stream; + + stream->workspace =3D __vmalloc(zlib_deflate_workspacesize(), + deflate_gfp()|__GFP_HIGHMEM, + PAGE_KERNEL); + if (!stream->workspace ) { + ret =3D -ENOMEM; + goto out; + } + memset(stream->workspace, 0, sizeof(stream->workspace)); + ret =3D zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED, + -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (ret !=3D Z_OK) { + ret =3D -EINVAL; + goto out_free; + } + ctx->comp_initialized =3D 1; +out:=09 + return ret; +out_free: + vfree(stream->workspace); + goto out; +} + +static int deflate_decomp_init(struct deflate_ctx *ctx) +{ + int ret =3D 0; + struct z_stream_s *stream =3D &ctx->decomp_stream; + + stream->workspace =3D kmalloc(zlib_inflate_workspacesize(), + deflate_gfp()); + if (!stream->workspace ) { + ret =3D -ENOMEM; + goto out; + } + memset(stream->workspace, 0, sizeof(stream->workspace)); + ret =3D zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS); + if (ret !=3D Z_OK) { + ret =3D -EINVAL; + goto out_free; + } + ctx->decomp_initialized =3D 1; +out: + return ret; +out_free: + kfree(stream->workspace); + goto out; +} + +static int deflate_compress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + int ret =3D 0; + struct deflate_ctx *dctx =3D ctx; + struct z_stream_s *stream =3D &dctx->comp_stream; + + if (!dctx->comp_initialized) { + ret =3D deflate_comp_init(dctx); + if (ret) + goto out; + } + + ret =3D zlib_deflateReset(stream); + if (ret !=3D Z_OK) { + ret =3D -EINVAL; + goto out; + } + + stream->next_in =3D (u8 *)src; + stream->avail_in =3D slen; + stream->next_out =3D (u8 *)dst; + stream->avail_out =3D *dlen; + + ret =3D zlib_deflate(stream, Z_FINISH); + if (ret !=3D Z_STREAM_END) { + ret =3D -EINVAL; + goto out; + } + ret =3D 0; + *dlen =3D stream->total_out; +out: + return ret; +} +=20 +static int deflate_decompress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ +=09 + int ret =3D 0; + struct deflate_ctx *dctx =3D ctx; + struct z_stream_s *stream =3D &dctx->decomp_stream; + + if (!dctx->decomp_initialized) { + ret =3D deflate_decomp_init(dctx); + if (ret) + goto out; + } + + ret =3D zlib_inflateReset(stream); + if (ret !=3D Z_OK) { + ret =3D -EINVAL; + goto out; + } + + stream->next_in =3D (u8 *)src; + stream->avail_in =3D slen; + stream->next_out =3D (u8 *)dst; + stream->avail_out =3D *dlen; + + ret =3D zlib_inflate(stream, Z_SYNC_FLUSH); + /* + * Work around a bug in zlib, which sometimes wants to taste an extra + * byte when being used in the (undocumented) raw deflate mode. + * (From USAGI). + */ + if (ret =3D=3D Z_OK && !stream->avail_in && stream->avail_out) { + u8 zerostuff =3D 0; + stream->next_in =3D &zerostuff; + stream->avail_in =3D 1;=20 + ret =3D zlib_inflate(stream, Z_FINISH); + } + if (ret !=3D Z_STREAM_END) { + ret =3D -EINVAL; + goto out; + } + ret =3D 0; + *dlen =3D stream->total_out; +out: + return ret; +} + +static struct crypto_alg alg =3D { + .cra_name =3D "deflate", + .cra_flags =3D CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize =3D sizeof(struct deflate_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(alg.cra_list), + .cra_u =3D { .compress =3D { + .coa_init =3D deflate_init, + .coa_exit =3D deflate_exit, + .coa_compress =3D deflate_compress, + .coa_decompress =3D deflate_decompress } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); +MODULE_AUTHOR("James Morris "); + diff -Nru a/crypto/des.c b/crypto/des.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/des.c Thu May 8 10:41:38 2003 @@ -0,0 +1,1299 @@ +/*=20 + * Cryptographic API. + * + * DES & Triple DES EDE Cipher Algorithms. + * + * Originally released as descore by Dana L. How . + * Modified by Raimar Falke for the Linux-Kernel. + * Derived from Cryptoapi and Nettle implementations, adapted for in-place + * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. + * + * Copyright (c) 1992 Dana L. How. + * Copyright (c) Raimar Falke =20 + * Copyright (c) Gisle S=E6lensminde + * Copyright (C) 2001 Niels M=F6ller. + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include + +#define DES_KEY_SIZE 8 +#define DES_EXPKEY_WORDS 32 +#define DES_BLOCK_SIZE 8 + +#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS) +#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE + +#define ROR(d,c,o) ((d) =3D (d) >> (c) | (d) << (o)) + +struct des_ctx { + u8 iv[DES_BLOCK_SIZE]; + u32 expkey[DES_EXPKEY_WORDS]; +}; + +struct des3_ede_ctx { + u8 iv[DES_BLOCK_SIZE]; + u32 expkey[DES3_EDE_EXPKEY_WORDS]; +}; + +const static u32 des_keymap[] =3D { + 0x02080008, 0x02082000, 0x00002008, 0x00000000, + 0x02002000, 0x00080008, 0x02080000, 0x02082008, + 0x00000008, 0x02000000, 0x00082000, 0x00002008, + 0x00082008, 0x02002008, 0x02000008, 0x02080000, + 0x00002000, 0x00082008, 0x00080008, 0x02002000, + 0x02082008, 0x02000008, 0x00000000, 0x00082000, + 0x02000000, 0x00080000, 0x02002008, 0x02080008, + 0x00080000, 0x00002000, 0x02082000, 0x00000008, + 0x00080000, 0x00002000, 0x02000008, 0x02082008, + 0x00002008, 0x02000000, 0x00000000, 0x00082000, + 0x02080008, 0x02002008, 0x02002000, 0x00080008, + 0x02082000, 0x00000008, 0x00080008, 0x02002000, + 0x02082008, 0x00080000, 0x02080000, 0x02000008, + 0x00082000, 0x00002008, 0x02002008, 0x02080000, + 0x00000008, 0x02082000, 0x00082008, 0x00000000, + 0x02000000, 0x02080008, 0x00002000, 0x00082008, + + 0x08000004, 0x00020004, 0x00000000, 0x08020200, + 0x00020004, 0x00000200, 0x08000204, 0x00020000, + 0x00000204, 0x08020204, 0x00020200, 0x08000000, + 0x08000200, 0x08000004, 0x08020000, 0x00020204, + 0x00020000, 0x08000204, 0x08020004, 0x00000000, + 0x00000200, 0x00000004, 0x08020200, 0x08020004, + 0x08020204, 0x08020000, 0x08000000, 0x00000204, + 0x00000004, 0x00020200, 0x00020204, 0x08000200, + 0x00000204, 0x08000000, 0x08000200, 0x00020204, + 0x08020200, 0x00020004, 0x00000000, 0x08000200, + 0x08000000, 0x00000200, 0x08020004, 0x00020000, + 0x00020004, 0x08020204, 0x00020200, 0x00000004, + 0x08020204, 0x00020200, 0x00020000, 0x08000204, + 0x08000004, 0x08020000, 0x00020204, 0x00000000, + 0x00000200, 0x08000004, 0x08000204, 0x08020200, + 0x08020000, 0x00000204, 0x00000004, 0x08020004, + + 0x80040100, 0x01000100, 0x80000000, 0x81040100, + 0x00000000, 0x01040000, 0x81000100, 0x80040000, + 0x01040100, 0x81000000, 0x01000000, 0x80000100, + 0x81000000, 0x80040100, 0x00040000, 0x01000000, + 0x81040000, 0x00040100, 0x00000100, 0x80000000, + 0x00040100, 0x81000100, 0x01040000, 0x00000100, + 0x80000100, 0x00000000, 0x80040000, 0x01040100, + 0x01000100, 0x81040000, 0x81040100, 0x00040000, + 0x81040000, 0x80000100, 0x00040000, 0x81000000, + 0x00040100, 0x01000100, 0x80000000, 0x01040000, + 0x81000100, 0x00000000, 0x00000100, 0x80040000, + 0x00000000, 0x81040000, 0x01040100, 0x00000100, + 0x01000000, 0x81040100, 0x80040100, 0x00040000, + 0x81040100, 0x80000000, 0x01000100, 0x80040100, + 0x80040000, 0x00040100, 0x01040000, 0x81000100, + 0x80000100, 0x01000000, 0x81000000, 0x01040100, + + 0x04010801, 0x00000000, 0x00010800, 0x04010000, + 0x04000001, 0x00000801, 0x04000800, 0x00010800, + 0x00000800, 0x04010001, 0x00000001, 0x04000800, + 0x00010001, 0x04010800, 0x04010000, 0x00000001, + 0x00010000, 0x04000801, 0x04010001, 0x00000800, + 0x00010801, 0x04000000, 0x00000000, 0x00010001, + 0x04000801, 0x00010801, 0x04010800, 0x04000001, + 0x04000000, 0x00010000, 0x00000801, 0x04010801, + 0x00010001, 0x04010800, 0x04000800, 0x00010801, + 0x04010801, 0x00010001, 0x04000001, 0x00000000, + 0x04000000, 0x00000801, 0x00010000, 0x04010001, + 0x00000800, 0x04000000, 0x00010801, 0x04000801, + 0x04010800, 0x00000800, 0x00000000, 0x04000001, + 0x00000001, 0x04010801, 0x00010800, 0x04010000, + 0x04010001, 0x00010000, 0x00000801, 0x04000800, + 0x04000801, 0x00000001, 0x04010000, 0x00010800, + + 0x00000400, 0x00000020, 0x00100020, 0x40100000, + 0x40100420, 0x40000400, 0x00000420, 0x00000000, + 0x00100000, 0x40100020, 0x40000020, 0x00100400, + 0x40000000, 0x00100420, 0x00100400, 0x40000020, + 0x40100020, 0x00000400, 0x40000400, 0x40100420, + 0x00000000, 0x00100020, 0x40100000, 0x00000420, + 0x40100400, 0x40000420, 0x00100420, 0x40000000, + 0x40000420, 0x40100400, 0x00000020, 0x00100000, + 0x40000420, 0x00100400, 0x40100400, 0x40000020, + 0x00000400, 0x00000020, 0x00100000, 0x40100400, + 0x40100020, 0x40000420, 0x00000420, 0x00000000, + 0x00000020, 0x40100000, 0x40000000, 0x00100020, + 0x00000000, 0x40100020, 0x00100020, 0x00000420, + 0x40000020, 0x00000400, 0x40100420, 0x00100000, + 0x00100420, 0x40000000, 0x40000400, 0x40100420, + 0x40100000, 0x00100420, 0x00100400, 0x40000400, + + 0x00800000, 0x00001000, 0x00000040, 0x00801042, + 0x00801002, 0x00800040, 0x00001042, 0x00801000, + 0x00001000, 0x00000002, 0x00800002, 0x00001040, + 0x00800042, 0x00801002, 0x00801040, 0x00000000, + 0x00001040, 0x00800000, 0x00001002, 0x00000042, + 0x00800040, 0x00001042, 0x00000000, 0x00800002, + 0x00000002, 0x00800042, 0x00801042, 0x00001002, + 0x00801000, 0x00000040, 0x00000042, 0x00801040, + 0x00801040, 0x00800042, 0x00001002, 0x00801000, + 0x00001000, 0x00000002, 0x00800002, 0x00800040, + 0x00800000, 0x00001040, 0x00801042, 0x00000000, + 0x00001042, 0x00800000, 0x00000040, 0x00001002, + 0x00800042, 0x00000040, 0x00000000, 0x00801042, + 0x00801002, 0x00801040, 0x00000042, 0x00001000, + 0x00001040, 0x00801002, 0x00800040, 0x00000042, + 0x00000002, 0x00001042, 0x00801000, 0x00800002, + + 0x10400000, 0x00404010, 0x00000010, 0x10400010, + 0x10004000, 0x00400000, 0x10400010, 0x00004010, + 0x00400010, 0x00004000, 0x00404000, 0x10000000, + 0x10404010, 0x10000010, 0x10000000, 0x10404000, + 0x00000000, 0x10004000, 0x00404010, 0x00000010, + 0x10000010, 0x10404010, 0x00004000, 0x10400000, + 0x10404000, 0x00400010, 0x10004010, 0x00404000, + 0x00004010, 0x00000000, 0x00400000, 0x10004010, + 0x00404010, 0x00000010, 0x10000000, 0x00004000, + 0x10000010, 0x10004000, 0x00404000, 0x10400010, + 0x00000000, 0x00404010, 0x00004010, 0x10404000, + 0x10004000, 0x00400000, 0x10404010, 0x10000000, + 0x10004010, 0x10400000, 0x00400000, 0x10404010, + 0x00004000, 0x00400010, 0x10400010, 0x00004010, + 0x00400010, 0x00000000, 0x10404000, 0x10000010, + 0x10400000, 0x10004010, 0x00000010, 0x00404000, + + 0x00208080, 0x00008000, 0x20200000, 0x20208080, + 0x00200000, 0x20008080, 0x20008000, 0x20200000, + 0x20008080, 0x00208080, 0x00208000, 0x20000080, + 0x20200080, 0x00200000, 0x00000000, 0x20008000, + 0x00008000, 0x20000000, 0x00200080, 0x00008080, + 0x20208080, 0x00208000, 0x20000080, 0x00200080, + 0x20000000, 0x00000080, 0x00008080, 0x20208000, + 0x00000080, 0x20200080, 0x20208000, 0x00000000, + 0x00000000, 0x20208080, 0x00200080, 0x20008000, + 0x00208080, 0x00008000, 0x20000080, 0x00200080, + 0x20208000, 0x00000080, 0x00008080, 0x20200000, + 0x20008080, 0x20000000, 0x20200000, 0x00208000, + 0x20208080, 0x00008080, 0x00208000, 0x20200080, + 0x00200000, 0x20000080, 0x20008000, 0x00000000, + 0x00008000, 0x00200000, 0x20200080, 0x00208080, + 0x20000000, 0x20208000, 0x00000080, 0x20008080, +}; + +const static u8 rotors[] =3D { + 34, 13, 5, 46, 47, 18, 32, 41, 11, 53, 33, 20, + 14, 36, 30, 24, 49, 2, 15, 37, 42, 50, 0, 21, + 38, 48, 6, 26, 39, 4, 52, 25, 12, 27, 31, 40, + 1, 17, 28, 29, 23, 51, 35, 7, 3, 22, 9, 43, + + 41, 20, 12, 53, 54, 25, 39, 48, 18, 31, 40, 27, + 21, 43, 37, 0, 1, 9, 22, 44, 49, 2, 7, 28, + 45, 55, 13, 33, 46, 11, 6, 32, 19, 34, 38, 47, + 8, 24, 35, 36, 30, 3, 42, 14, 10, 29, 16, 50, + + 55, 34, 26, 38, 11, 39, 53, 5, 32, 45, 54, 41, + 35, 2, 51, 14, 15, 23, 36, 3, 8, 16, 21, 42, + 6, 12, 27, 47, 31, 25, 20, 46, 33, 48, 52, 4, + 22, 7, 49, 50, 44, 17, 1, 28, 24, 43, 30, 9, + + 12, 48, 40, 52, 25, 53, 38, 19, 46, 6, 11, 55, + 49, 16, 10, 28, 29, 37, 50, 17, 22, 30, 35, 1, + 20, 26, 41, 4, 45, 39, 34, 31, 47, 5, 13, 18, + 36, 21, 8, 9, 3, 0, 15, 42, 7, 2, 44, 23, + + 26, 5, 54, 13, 39, 38, 52, 33, 31, 20, 25, 12, + 8, 30, 24, 42, 43, 51, 9, 0, 36, 44, 49, 15, + 34, 40, 55, 18, 6, 53, 48, 45, 4, 19, 27, 32, + 50, 35, 22, 23, 17, 14, 29, 1, 21, 16, 3, 37, + + 40, 19, 11, 27, 53, 52, 13, 47, 45, 34, 39, 26, + 22, 44, 7, 1, 2, 10, 23, 14, 50, 3, 8, 29, + 48, 54, 12, 32, 20, 38, 5, 6, 18, 33, 41, 46, + 9, 49, 36, 37, 0, 28, 43, 15, 35, 30, 17, 51, + + 54, 33, 25, 41, 38, 13, 27, 4, 6, 48, 53, 40, + 36, 3, 21, 15, 16, 24, 37, 28, 9, 17, 22, 43, + 5, 11, 26, 46, 34, 52, 19, 20, 32, 47, 55, 31, + 23, 8, 50, 51, 14, 42, 2, 29, 49, 44, 0, 10, + + 11, 47, 39, 55, 52, 27, 41, 18, 20, 5, 38, 54, + 50, 17, 35, 29, 30, 7, 51, 42, 23, 0, 36, 2, + 19, 25, 40, 31, 48, 13, 33, 34, 46, 4, 12, 45, + 37, 22, 9, 10, 28, 1, 16, 43, 8, 3, 14, 24, + + 18, 54, 46, 5, 6, 34, 48, 25, 27, 12, 45, 4, + 2, 24, 42, 36, 37, 14, 3, 49, 30, 7, 43, 9, + 26, 32, 47, 38, 55, 20, 40, 41, 53, 11, 19, 52, + 44, 29, 16, 17, 35, 8, 23, 50, 15, 10, 21, 0, + + 32, 11, 31, 19, 20, 48, 5, 39, 41, 26, 6, 18, + 16, 7, 1, 50, 51, 28, 17, 8, 44, 21, 2, 23, + 40, 46, 4, 52, 12, 34, 54, 55, 38, 25, 33, 13, + 3, 43, 30, 0, 49, 22, 37, 9, 29, 24, 35, 14, + + 46, 25, 45, 33, 34, 5, 19, 53, 55, 40, 20, 32, + 30, 21, 15, 9, 10, 42, 0, 22, 3, 35, 16, 37, + 54, 31, 18, 13, 26, 48, 11, 12, 52, 39, 47, 27, + 17, 2, 44, 14, 8, 36, 51, 23, 43, 7, 49, 28, + + 31, 39, 6, 47, 48, 19, 33, 38, 12, 54, 34, 46, + 44, 35, 29, 23, 24, 1, 14, 36, 17, 49, 30, 51, + 11, 45, 32, 27, 40, 5, 25, 26, 13, 53, 4, 41, + 0, 16, 3, 28, 22, 50, 10, 37, 2, 21, 8, 42, + + 45, 53, 20, 4, 5, 33, 47, 52, 26, 11, 48, 31, + 3, 49, 43, 37, 7, 15, 28, 50, 0, 8, 44, 10, + 25, 6, 46, 41, 54, 19, 39, 40, 27, 38, 18, 55, + 14, 30, 17, 42, 36, 9, 24, 51, 16, 35, 22, 1, + + 6, 38, 34, 18, 19, 47, 4, 13, 40, 25, 5, 45, + 17, 8, 2, 51, 21, 29, 42, 9, 14, 22, 3, 24, + 39, 20, 31, 55, 11, 33, 53, 54, 41, 52, 32, 12, + 28, 44, 0, 1, 50, 23, 7, 10, 30, 49, 36, 15, + + 20, 52, 48, 32, 33, 4, 18, 27, 54, 39, 19, 6, + 0, 22, 16, 10, 35, 43, 1, 23, 28, 36, 17, 7, + 53, 34, 45, 12, 25, 47, 38, 11, 55, 13, 46, 26, + 42, 3, 14, 15, 9, 37, 21, 24, 44, 8, 50, 29, + + 27, 6, 55, 39, 40, 11, 25, 34, 4, 46, 26, 13, + 7, 29, 23, 17, 42, 50, 8, 30, 35, 43, 24, 14, + 31, 41, 52, 19, 32, 54, 45, 18, 5, 20, 53, 33, + 49, 10, 21, 22, 16, 44, 28, 0, 51, 15, 2, 36, +}; + +const static u8 parity[] =3D { + 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8, +}; + + +static void des_small_fips_encrypt(u32 *expkey, u8 *dst, const u8 *src) +{ + u32 x, y, z; +=09 + x =3D src[7]; + x <<=3D 8; + x |=3D src[6]; + x <<=3D 8; + x |=3D src[5]; + x <<=3D 8; + x |=3D src[4]; + y =3D src[3]; + y <<=3D 8; + y |=3D src[2]; + y <<=3D 8; + y |=3D src[1]; + y <<=3D 8; + y |=3D src[0]; + z =3D ((x >> 004) ^ y) & 0x0F0F0F0FL; + x ^=3D z << 004; + y ^=3D z; + z =3D ((y >> 020) ^ x) & 0x0000FFFFL; + y ^=3D z << 020; + x ^=3D z; + z =3D ((x >> 002) ^ y) & 0x33333333L; + x ^=3D z << 002; + y ^=3D z; + z =3D ((y >> 010) ^ x) & 0x00FF00FFL; + y ^=3D z << 010; + x ^=3D z; + x =3D x >> 1 | x << 31; + z =3D (x ^ y) & 0x55555555L; + y ^=3D z; + x ^=3D z; + y =3D y >> 1 | y << 31; + z =3D expkey[0]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[1]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[2]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[3]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[4]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[5]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[6]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[7]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[8]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[9]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[10]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[11]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[12]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[13]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[14]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[15]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[16]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[17]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[18]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[19]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[20]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[21]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[22]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[23]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[24]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[25]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[26]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[27]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[28]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[29]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[30]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[31]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + x =3D x << 1 | x >> 31; + z =3D (x ^ y) & 0x55555555L; + y ^=3D z; + x ^=3D z; + y =3D y << 1 | y >> 31; + z =3D ((x >> 010) ^ y) & 0x00FF00FFL; + x ^=3D z << 010; + y ^=3D z; + z =3D ((y >> 002) ^ x) & 0x33333333L; + y ^=3D z << 002; + x ^=3D z; + z =3D ((x >> 020) ^ y) & 0x0000FFFFL; + x ^=3D z << 020; + y ^=3D z; + z =3D ((y >> 004) ^ x) & 0x0F0F0F0FL; + y ^=3D z << 004; + x ^=3D z; + dst[0] =3D x; + x >>=3D 8; + dst[1] =3D x; + x >>=3D 8; + dst[2] =3D x; + x >>=3D 8; + dst[3] =3D x; + dst[4] =3D y; + y >>=3D 8; + dst[5] =3D y; + y >>=3D 8; + dst[6] =3D y; + y >>=3D 8; + dst[7] =3D y; +} + +static void des_small_fips_decrypt(u32 *expkey, u8 *dst, const u8 *src) +{ + u32 x, y, z; +=09 + x =3D src[7]; + x <<=3D 8; + x |=3D src[6]; + x <<=3D 8; + x |=3D src[5]; + x <<=3D 8; + x |=3D src[4]; + y =3D src[3]; + y <<=3D 8; + y |=3D src[2]; + y <<=3D 8; + y |=3D src[1]; + y <<=3D 8; + y |=3D src[0]; + z =3D ((x >> 004) ^ y) & 0x0F0F0F0FL; + x ^=3D z << 004; + y ^=3D z; + z =3D ((y >> 020) ^ x) & 0x0000FFFFL; + y ^=3D z << 020; + x ^=3D z; + z =3D ((x >> 002) ^ y) & 0x33333333L; + x ^=3D z << 002; + y ^=3D z; + z =3D ((y >> 010) ^ x) & 0x00FF00FFL; + y ^=3D z << 010; + x ^=3D z; + x =3D x >> 1 | x << 31; + z =3D (x ^ y) & 0x55555555L; + y ^=3D z; + x ^=3D z; + y =3D y >> 1 | y << 31; + z =3D expkey[31]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[30]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[29]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[28]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[27]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[26]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[25]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[24]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[23]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[22]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[21]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[20]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[19]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[18]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[17]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[16]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[15]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[14]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[13]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[12]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[11]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[10]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[9]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[8]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[7]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[6]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[5]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[4]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[3]; + z ^=3D y; + z =3D z << 4 | z >> 28; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[2]; + z ^=3D y; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + x ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + z =3D expkey[1]; + z ^=3D x; + z =3D z << 4 | z >> 28; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z)); + z =3D expkey[0]; + z ^=3D x; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z)); + z >>=3D 8; + y ^=3D * (u32 *) ((u8 *) des_keymap + (0xFC & z)); + x =3D x << 1 | x >> 31; + z =3D (x ^ y) & 0x55555555L; + y ^=3D z; + x ^=3D z; + y =3D y << 1 | y >> 31; + z =3D ((x >> 010) ^ y) & 0x00FF00FFL; + x ^=3D z << 010; + y ^=3D z; + z =3D ((y >> 002) ^ x) & 0x33333333L; + y ^=3D z << 002; + x ^=3D z; + z =3D ((x >> 020) ^ y) & 0x0000FFFFL; + x ^=3D z << 020; + y ^=3D z; + z =3D ((y >> 004) ^ x) & 0x0F0F0F0FL; + y ^=3D z << 004; + x ^=3D z; + dst[0] =3D x; + x >>=3D 8; + dst[1] =3D x; + x >>=3D 8; + dst[2] =3D x; + x >>=3D 8; + dst[3] =3D x; + dst[4] =3D y; + y >>=3D 8; + dst[5] =3D y; + y >>=3D 8; + dst[6] =3D y; + y >>=3D 8; + dst[7] =3D y; +} + +/* + * RFC2451: Weak key checks SHOULD be performed. + */ +static int setkey(u32 *expkey, const u8 *key, unsigned int keylen, u32 *fl= ags) +{ + const u8 *k; + u8 *b0, *b1; + u32 n, w; + u8 bits0[56], bits1[56]; + + n =3D parity[key[0]]; n <<=3D 4; + n |=3D parity[key[1]]; n <<=3D 4; + n |=3D parity[key[2]]; n <<=3D 4; + n |=3D parity[key[3]]; n <<=3D 4; + n |=3D parity[key[4]]; n <<=3D 4; + n |=3D parity[key[5]]; n <<=3D 4; + n |=3D parity[key[6]]; n <<=3D 4; + n |=3D parity[key[7]]; + w =3D 0x88888888L; +=09 + if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) + && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */ + if (n < 0x41415151) { + if (n < 0x31312121) { + if (n < 0x14141515) { + /* 01 01 01 01 01 01 01 01 */ + if (n =3D=3D 0x11111111) goto weak; + /* 01 1F 01 1F 01 0E 01 0E */ + if (n =3D=3D 0x13131212) goto weak; + } else { + /* 01 E0 01 E0 01 F1 01 F1 */ + if (n =3D=3D 0x14141515) goto weak; + /* 01 FE 01 FE 01 FE 01 FE */ + if (n =3D=3D 0x16161616) goto weak; + } + } else { + if (n < 0x34342525) { + /* 1F 01 1F 01 0E 01 0E 01 */ + if (n =3D=3D 0x31312121) goto weak; + /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */ + if (n =3D=3D 0x33332222) goto weak; + } else { + /* 1F E0 1F E0 0E F1 0E F1 */ + if (n =3D=3D 0x34342525) goto weak; + /* 1F FE 1F FE 0E FE 0E FE */ + if (n =3D=3D 0x36362626) goto weak; + } + } + } else { + if (n < 0x61616161) { + if (n < 0x44445555) { + /* E0 01 E0 01 F1 01 F1 01 */ + if (n =3D=3D 0x41415151) goto weak; + /* E0 1F E0 1F F1 0E F1 0E */ + if (n =3D=3D 0x43435252) goto weak; + } else { + /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */ + if (n =3D=3D 0x44445555) goto weak; + /* E0 FE E0 FE F1 FE F1 FE */ + if (n =3D=3D 0x46465656) goto weak; + } + } else { + if (n < 0x64646565) { + /* FE 01 FE 01 FE 01 FE 01 */ + if (n =3D=3D 0x61616161) goto weak; + /* FE 1F FE 1F FE 0E FE 0E */ + if (n =3D=3D 0x63636262) goto weak; + } else { + /* FE E0 FE E0 FE F1 FE F1 */ + if (n =3D=3D 0x64646565) goto weak; + /* FE FE FE FE FE FE FE FE */ + if (n =3D=3D 0x66666666) goto weak; + } + } + } +=09 + goto not_weak; +weak: + *flags |=3D CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; + } + +not_weak: + + /* explode the bits */ + n =3D 56; + b0 =3D bits0; + b1 =3D bits1; +=09 + do { + w =3D (256 | *key++) << 2; + do { + --n; + b1[n] =3D 8 & w; + w >>=3D 1; + b0[n] =3D 4 & w; + } while ( w >=3D 16 ); + } while ( n ); +=09 + /* put the bits in the correct places */ + n =3D 16; + k =3D rotors; +=09 + do { + w =3D (b1[k[ 0 ]] | b0[k[ 1 ]]) << 4; + w |=3D (b1[k[ 2 ]] | b0[k[ 3 ]]) << 2; + w |=3D b1[k[ 4 ]] | b0[k[ 5 ]]; + w <<=3D 8; + w |=3D (b1[k[ 6 ]] | b0[k[ 7 ]]) << 4; + w |=3D (b1[k[ 8 ]] | b0[k[ 9 ]]) << 2; + w |=3D b1[k[10 ]] | b0[k[11 ]]; + w <<=3D 8; + w |=3D (b1[k[12 ]] | b0[k[13 ]]) << 4; + w |=3D (b1[k[14 ]] | b0[k[15 ]]) << 2; + w |=3D b1[k[16 ]] | b0[k[17 ]]; + w <<=3D 8; + w |=3D (b1[k[18 ]] | b0[k[19 ]]) << 4; + w |=3D (b1[k[20 ]] | b0[k[21 ]]) << 2; + w |=3D b1[k[22 ]] | b0[k[23 ]]; + expkey[0] =3D w; + =09 + w =3D (b1[k[ 0+24]] | b0[k[ 1+24]]) << 4; + w |=3D (b1[k[ 2+24]] | b0[k[ 3+24]]) << 2; + w |=3D b1[k[ 4+24]] | b0[k[ 5+24]]; + w <<=3D 8; + w |=3D (b1[k[ 6+24]] | b0[k[ 7+24]]) << 4; + w |=3D (b1[k[ 8+24]] | b0[k[ 9+24]]) << 2; + w |=3D b1[k[10+24]] | b0[k[11+24]]; + w <<=3D 8; + w |=3D (b1[k[12+24]] | b0[k[13+24]]) << 4; + w |=3D (b1[k[14+24]] | b0[k[15+24]]) << 2; + w |=3D b1[k[16+24]] | b0[k[17+24]]; + w <<=3D 8; + w |=3D (b1[k[18+24]] | b0[k[19+24]]) << 4; + w |=3D (b1[k[20+24]] | b0[k[21+24]]) << 2; + w |=3D b1[k[22+24]] | b0[k[23+24]]; + =09 + ROR(w, 4, 28); /* could be eliminated */ + expkey[1] =3D w; + + k +=3D 48; + expkey +=3D 2; + } while (--n); + + return 0; +} + +static int des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *= flags) +{ + return setkey(((struct des_ctx *)ctx)->expkey, key, keylen, flags); +} + +static void des_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + des_small_fips_encrypt(((struct des_ctx *)ctx)->expkey, dst, src); +} + +static void des_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + des_small_fips_decrypt(((struct des_ctx *)ctx)->expkey, dst, src); +} + +/*=20 + * RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the first two or last two independent 64-bit keys are + * equal (k1 =3D=3D k2 or k2 =3D=3D k3), then the DES3 operation is simp= ly the + * same as DES. Implementers MUST reject keys that exhibit this + * property. + * + */ +static int des3_ede_setkey(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags) +{ + unsigned int i, off; + struct des3_ede_ctx *dctx =3D ctx; + + if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&=20 + memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], + DES_KEY_SIZE))) { + + *flags |=3D CRYPTO_TFM_RES_BAD_KEY_SCHED; + return -EINVAL; + } +=09 + for (i =3D 0, off =3D 0; i < 3; i++, off +=3D DES_EXPKEY_WORDS, + key +=3D DES_KEY_SIZE) { + int ret =3D setkey(&dctx->expkey[off], key, DES_KEY_SIZE, flags); + if (ret < 0) + return ret; + }=09 + return 0; +} + +static void des3_ede_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct des3_ede_ctx *dctx =3D ctx; +=09 + des_small_fips_encrypt(dctx->expkey, dst, src); + des_small_fips_decrypt(&dctx->expkey[DES_EXPKEY_WORDS], dst, dst); + des_small_fips_encrypt(&dctx->expkey[DES_EXPKEY_WORDS * 2], dst, dst); +} + +static void des3_ede_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct des3_ede_ctx *dctx =3D ctx; + + des_small_fips_decrypt(&dctx->expkey[DES_EXPKEY_WORDS * 2], dst, src); + des_small_fips_encrypt(&dctx->expkey[DES_EXPKEY_WORDS], dst, dst); + des_small_fips_decrypt(dctx->expkey, dst, dst); +} + +static struct crypto_alg des_alg =3D { + .cra_name =3D "des", + .cra_flags =3D CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize =3D DES_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct des_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(des_alg.cra_list), + .cra_u =3D { .cipher =3D { + .cia_min_keysize =3D DES_KEY_SIZE, + .cia_max_keysize =3D DES_KEY_SIZE, + .cia_ivsize =3D DES_BLOCK_SIZE, + .cia_setkey =3D des_setkey, + .cia_encrypt =3D des_encrypt, + .cia_decrypt =3D des_decrypt } } +}; + +static struct crypto_alg des3_ede_alg =3D { + .cra_name =3D "des3_ede", + .cra_flags =3D CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize =3D DES3_EDE_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct des3_ede_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(des3_ede_alg.cra_list), + .cra_u =3D { .cipher =3D { + .cia_min_keysize =3D DES3_EDE_KEY_SIZE, + .cia_max_keysize =3D DES3_EDE_KEY_SIZE, + .cia_ivsize =3D DES3_EDE_BLOCK_SIZE, + .cia_setkey =3D des3_ede_setkey, + .cia_encrypt =3D des3_ede_encrypt, + .cia_decrypt =3D des3_ede_decrypt } } +}; + +static int __init init(void) +{ + int ret =3D 0; +=09 + ret =3D crypto_register_alg(&des_alg); + if (ret < 0) + goto out; + + ret =3D crypto_register_alg(&des3_ede_alg); + if (ret < 0) + crypto_unregister_alg(&des_alg); +out:=09 + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&des3_ede_alg); + crypto_unregister_alg(&des_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); diff -Nru a/crypto/digest.c b/crypto/digest.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/digest.c Thu May 8 10:41:38 2003 @@ -0,0 +1,82 @@ +/* + * Cryptographic API. + * + * Digest operations. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include "internal.h" + +static void init(struct crypto_tfm *tfm) +{ + tfm->__crt_alg->cra_digest.dia_init(crypto_tfm_ctx(tfm)); +} + +static void update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg) +{ + unsigned int i; +=09 + for (i =3D 0; i < nsg; i++) { + char *p =3D crypto_kmap(sg[i].page, 0) + sg[i].offset; + tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), + p, sg[i].length); + crypto_kunmap(p, 0); + crypto_yield(tfm); + } +} + +static void final(struct crypto_tfm *tfm, u8 *out) +{ + tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out); +} + +static void digest(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg, u8 *out) +{ + unsigned int i; + + tfm->crt_digest.dit_init(tfm); + =09 + for (i =3D 0; i < nsg; i++) { + char *p =3D crypto_kmap(sg[i].page, 0) + sg[i].offset; + tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), + p, sg[i].length); + crypto_kunmap(p, 0); + crypto_yield(tfm); + } + crypto_digest_final(tfm, out); +} + +int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) +{ + return flags ? -EINVAL : 0; +} + +int crypto_init_digest_ops(struct crypto_tfm *tfm) +{ + struct digest_tfm *ops =3D &tfm->crt_digest; +=09 + ops->dit_init =3D init; + ops->dit_update =3D update; + ops->dit_final =3D final; + ops->dit_digest =3D digest; +=09 + return crypto_alloc_hmac_block(tfm); +} + +void crypto_exit_digest_ops(struct crypto_tfm *tfm) +{ + crypto_free_hmac_block(tfm); +} diff -Nru a/crypto/hmac.c b/crypto/hmac.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/hmac.c Thu May 8 10:41:38 2003 @@ -0,0 +1,134 @@ +/* + * Cryptographic API. + * + * HMAC: Keyed-Hashing for Message Authentication (RFC2104). + * + * Copyright (c) 2002 James Morris + * + * The HMAC implementation is derived from USAGI. + * Copyright (c) 2002 Kazunori Miyazawa / USAGI + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include "internal.h" + +static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen) +{ + struct scatterlist tmp; +=09 + tmp.page =3D virt_to_page(key); + tmp.offset =3D ((long)key & ~PAGE_MASK); + tmp.length =3D keylen; + crypto_digest_digest(tfm, &tmp, 1, key); + =09 +} + +int crypto_alloc_hmac_block(struct crypto_tfm *tfm) +{ + int ret =3D 0; + + BUG_ON(!crypto_tfm_alg_blocksize(tfm)); +=09 + tfm->crt_digest.dit_hmac_block =3D kmalloc(crypto_tfm_alg_blocksize(tfm), + GFP_KERNEL); + if (tfm->crt_digest.dit_hmac_block =3D=3D NULL) + ret =3D -ENOMEM; + + return ret; + =09 +} + +void crypto_free_hmac_block(struct crypto_tfm *tfm) +{ + if (tfm->crt_digest.dit_hmac_block) + kfree(tfm->crt_digest.dit_hmac_block); +} + +void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keyle= n) +{ + unsigned int i; + struct scatterlist tmp; + char *ipad =3D tfm->crt_digest.dit_hmac_block; +=09 + if (*keylen > crypto_tfm_alg_blocksize(tfm)) { + hash_key(tfm, key, *keylen); + *keylen =3D crypto_tfm_alg_digestsize(tfm); + } + + memset(ipad, 0, crypto_tfm_alg_blocksize(tfm)); + memcpy(ipad, key, *keylen); + + for (i =3D 0; i < crypto_tfm_alg_blocksize(tfm); i++) + ipad[i] ^=3D 0x36; + + tmp.page =3D virt_to_page(ipad); + tmp.offset =3D ((long)ipad & ~PAGE_MASK); + tmp.length =3D crypto_tfm_alg_blocksize(tfm); +=09 + crypto_digest_init(tfm); + crypto_digest_update(tfm, &tmp, 1); +} + +void crypto_hmac_update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg) +{ + crypto_digest_update(tfm, sg, nsg); +} + +void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, + unsigned int *keylen, u8 *out) +{ + unsigned int i; + struct scatterlist tmp; + char *opad =3D tfm->crt_digest.dit_hmac_block; +=09 + if (*keylen > crypto_tfm_alg_blocksize(tfm)) { + hash_key(tfm, key, *keylen); + *keylen =3D crypto_tfm_alg_digestsize(tfm); + } + + crypto_digest_final(tfm, out); + + memset(opad, 0, crypto_tfm_alg_blocksize(tfm)); + memcpy(opad, key, *keylen); + =09 + for (i =3D 0; i < crypto_tfm_alg_blocksize(tfm); i++) + opad[i] ^=3D 0x5c; + + tmp.page =3D virt_to_page(opad); + tmp.offset =3D ((long)opad & ~PAGE_MASK); + tmp.length =3D crypto_tfm_alg_blocksize(tfm); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, &tmp, 1); +=09 + tmp.page =3D virt_to_page(out); + tmp.offset =3D ((long)out & ~PAGE_MASK); + tmp.length =3D crypto_tfm_alg_digestsize(tfm); +=09 + crypto_digest_update(tfm, &tmp, 1); + crypto_digest_final(tfm, out); +} + +void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, + struct scatterlist *sg, unsigned int nsg, u8 *out) +{ + crypto_hmac_init(tfm, key, keylen); + crypto_hmac_update(tfm, sg, nsg); + crypto_hmac_final(tfm, key, keylen, out); +} + +EXPORT_SYMBOL_GPL(crypto_hmac_init); +EXPORT_SYMBOL_GPL(crypto_hmac_update); +EXPORT_SYMBOL_GPL(crypto_hmac_final); +EXPORT_SYMBOL_GPL(crypto_hmac); + diff -Nru a/crypto/internal.h b/crypto/internal.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/internal.h Thu May 8 10:41:38 2003 @@ -0,0 +1,94 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#ifndef _CRYPTO_INTERNAL_H +#define _CRYPTO_INTERNAL_H +#include +#include +#include +#include +#include +#include + +extern enum km_type crypto_km_types[]; + +static inline enum km_type crypto_kmap_type(int out) +{ + return crypto_km_types[(in_softirq() ? 2 : 0) + out]; +} + +static inline void *crypto_kmap(struct page *page, int out) +{ + return kmap_atomic(page, crypto_kmap_type(out)); +} + +static inline void crypto_kunmap(void *vaddr, int out) +{ + kunmap_atomic(vaddr, crypto_kmap_type(out)); +} + +static inline void crypto_yield(struct crypto_tfm *tfm) +{ + if (!in_softirq()) + cond_resched(); +} + +static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) +{ + return (void *)&tfm[1]; +} + +struct crypto_alg *crypto_alg_lookup(const char *name); + +#ifdef CONFIG_KMOD +void crypto_alg_autoload(const char *name); +struct crypto_alg *crypto_alg_mod_lookup(const char *name); +#else +static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) +{ + return crypto_alg_lookup(name); +} +#endif + +#ifdef CONFIG_CRYPTO_HMAC +int crypto_alloc_hmac_block(struct crypto_tfm *tfm); +void crypto_free_hmac_block(struct crypto_tfm *tfm); +#else +static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm) +{ + return 0; +} + +static inline void crypto_free_hmac_block(struct crypto_tfm *tfm) +{ } +#endif + +#ifdef CONFIG_PROC_FS +void __init crypto_init_proc(void); +#else +static inline void crypto_init_proc(void) +{ } +#endif + +int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); +int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); +int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); + +int crypto_init_digest_ops(struct crypto_tfm *tfm); +int crypto_init_cipher_ops(struct crypto_tfm *tfm); +int crypto_init_compress_ops(struct crypto_tfm *tfm); + +void crypto_exit_digest_ops(struct crypto_tfm *tfm); +void crypto_exit_cipher_ops(struct crypto_tfm *tfm); +void crypto_exit_compress_ops(struct crypto_tfm *tfm); + +#endif /* _CRYPTO_INTERNAL_H */ + diff -Nru a/crypto/md4.c b/crypto/md4.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/md4.c Thu May 8 10:41:38 2003 @@ -0,0 +1,250 @@ +/*=20 + * Cryptographic API. + * + * MD4 Message Digest Algorithm (RFC1320). + * + * Implementation derived from Andrew Tridgell and Steve French's + * CIFS MD4 implementation, and the cryptoapi implementation + * originally based on the public domain implementation written + * by Colin Plumb in 1993. + * + * Copyright (c) Andrew Tridgell 1997-1998. + * Modified by Steve French (sfrench@us.ibm.com) 2002 + * Copyright (c) Cryptoapi developers. + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include + +#define MD4_DIGEST_SIZE 16 +#define MD4_HMAC_BLOCK_SIZE 64 +#define MD4_BLOCK_WORDS 16 +#define MD4_HASH_WORDS 4 + +struct md4_ctx { + u32 hash[MD4_HASH_WORDS]; + u32 block[MD4_BLOCK_WORDS]; + u64 byte_count; +}; + +static inline u32 lshift(u32 x, unsigned int s) +{ + x &=3D 0xFFFFFFFF; + return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); +} + +static inline u32 F(u32 x, u32 y, u32 z) +{ + return (x & y) | ((~x) & z); +} + +static inline u32 G(u32 x, u32 y, u32 z) +{ + return (x & y) | (x & z) | (y & z); +} + +static inline u32 H(u32 x, u32 y, u32 z) +{ + return x ^ y ^ z; +} + =20 +#define ROUND1(a,b,c,d,k,s) (a =3D lshift(a + F(b,c,d) + k, s)) +#define ROUND2(a,b,c,d,k,s) (a =3D lshift(a + G(b,c,d) + k + (u32)0x5A8279= 99,s)) +#define ROUND3(a,b,c,d,k,s) (a =3D lshift(a + H(b,c,d) + k + (u32)0x6ED9EB= A1,s)) + +/* XXX: this stuff can be optimized */ +static inline void le32_to_cpu_array(u32 *buf, unsigned int words) +{ + while (words--) { + __le32_to_cpus(buf); + buf++; + } +} + +static inline void cpu_to_le32_array(u32 *buf, unsigned int words) +{ + while (words--) { + __cpu_to_le32s(buf); + buf++; + } +} + +static void md4_transform(u32 *hash, u32 const *in) +{ + u32 a, b, c, d; + + a =3D hash[0]; + b =3D hash[1]; + c =3D hash[2]; + d =3D hash[3]; + + ROUND1(a, b, c, d, in[0], 3); + ROUND1(d, a, b, c, in[1], 7); + ROUND1(c, d, a, b, in[2], 11); + ROUND1(b, c, d, a, in[3], 19); + ROUND1(a, b, c, d, in[4], 3); + ROUND1(d, a, b, c, in[5], 7); + ROUND1(c, d, a, b, in[6], 11); + ROUND1(b, c, d, a, in[7], 19); + ROUND1(a, b, c, d, in[8], 3); + ROUND1(d, a, b, c, in[9], 7); + ROUND1(c, d, a, b, in[10], 11); + ROUND1(b, c, d, a, in[11], 19); + ROUND1(a, b, c, d, in[12], 3); + ROUND1(d, a, b, c, in[13], 7); + ROUND1(c, d, a, b, in[14], 11); + ROUND1(b, c, d, a, in[15], 19); + + ROUND2(a, b, c, d,in[ 0], 3); + ROUND2(d, a, b, c, in[4], 5); + ROUND2(c, d, a, b, in[8], 9); + ROUND2(b, c, d, a, in[12], 13); + ROUND2(a, b, c, d, in[1], 3); + ROUND2(d, a, b, c, in[5], 5); + ROUND2(c, d, a, b, in[9], 9); + ROUND2(b, c, d, a, in[13], 13); + ROUND2(a, b, c, d, in[2], 3); + ROUND2(d, a, b, c, in[6], 5); + ROUND2(c, d, a, b, in[10], 9); + ROUND2(b, c, d, a, in[14], 13); + ROUND2(a, b, c, d, in[3], 3); + ROUND2(d, a, b, c, in[7], 5); + ROUND2(c, d, a, b, in[11], 9); + ROUND2(b, c, d, a, in[15], 13); + + ROUND3(a, b, c, d,in[ 0], 3); + ROUND3(d, a, b, c, in[8], 9); + ROUND3(c, d, a, b, in[4], 11); + ROUND3(b, c, d, a, in[12], 15); + ROUND3(a, b, c, d, in[2], 3); + ROUND3(d, a, b, c, in[10], 9); + ROUND3(c, d, a, b, in[6], 11); + ROUND3(b, c, d, a, in[14], 15); + ROUND3(a, b, c, d, in[1], 3); + ROUND3(d, a, b, c, in[9], 9); + ROUND3(c, d, a, b, in[5], 11); + ROUND3(b, c, d, a, in[13], 15); + ROUND3(a, b, c, d, in[3], 3); + ROUND3(d, a, b, c, in[11], 9); + ROUND3(c, d, a, b, in[7], 11); + ROUND3(b, c, d, a, in[15], 15); + + hash[0] +=3D a; + hash[1] +=3D b; + hash[2] +=3D c; + hash[3] +=3D d; +} + +static inline void md4_transform_helper(struct md4_ctx *ctx) +{ + le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); + md4_transform(ctx->hash, ctx->block); +} + +static void md4_init(void *ctx) +{ + struct md4_ctx *mctx =3D ctx; + + mctx->hash[0] =3D 0x67452301; + mctx->hash[1] =3D 0xefcdab89; + mctx->hash[2] =3D 0x98badcfe; + mctx->hash[3] =3D 0x10325476; + mctx->byte_count =3D 0; +} + +static void md4_update(void *ctx, const u8 *data, unsigned int len) +{ + struct md4_ctx *mctx =3D ctx; + const u32 avail =3D sizeof(mctx->block) - (mctx->byte_count & 0x3f); + + mctx->byte_count +=3D len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + return; + } + + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, avail); + + md4_transform_helper(mctx); + data +=3D avail; + len -=3D avail; + + while (len >=3D sizeof(mctx->block)) { + memcpy(mctx->block, data, sizeof(mctx->block)); + md4_transform_helper(mctx); + data +=3D sizeof(mctx->block); + len -=3D sizeof(mctx->block); + } + + memcpy(mctx->block, data, len); +} + +static void md4_final(void *ctx, u8 *out) +{ + struct md4_ctx *mctx =3D ctx; + const unsigned int offset =3D mctx->byte_count & 0x3f; + char *p =3D (char *)mctx->block + offset; + int padding =3D 56 - (offset + 1); + + *p++ =3D 0x80; + if (padding < 0) { + memset(p, 0x00, padding + sizeof (u64)); + md4_transform_helper(mctx); + p =3D (char *)mctx->block; + padding =3D 56; + } + + memset(p, 0, padding); + mctx->block[14] =3D mctx->byte_count << 3; + mctx->block[15] =3D mctx->byte_count >> 29; + le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - + sizeof(u64)) / sizeof(u32)); + md4_transform(mctx->hash, mctx->block); + cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); + memcpy(out, mctx->hash, sizeof(mctx->hash)); + memset(mctx, 0, sizeof(mctx)); +} + +static struct crypto_alg alg =3D { + .cra_name =3D "md4", + .cra_flags =3D CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize =3D MD4_HMAC_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct md4_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(alg.cra_list),=09 + .cra_u =3D { .digest =3D { + .dia_digestsize =3D MD4_DIGEST_SIZE, + .dia_init =3D md4_init, + .dia_update =3D md4_update, + .dia_final =3D md4_final } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MD4 Message Digest Algorithm"); + diff -Nru a/crypto/md5.c b/crypto/md5.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/md5.c Thu May 8 10:41:38 2003 @@ -0,0 +1,244 @@ +/*=20 + * Cryptographic API. + * + * MD5 Message Digest Algorithm (RFC1321). + * + * Derived from cryptoapi implementation, originally based on the + * public domain implementation written by Colin Plumb in 1993. + * + * Copyright (c) Cryptoapi developers. + * Copyright (c) 2002 James Morris + *=20 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include + +#define MD5_DIGEST_SIZE 16 +#define MD5_HMAC_BLOCK_SIZE 64 +#define MD5_BLOCK_WORDS 16 +#define MD5_HASH_WORDS 4 + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, in, s) \ + (w +=3D f(x, y, z) + in, w =3D (w<>(32-s)) + x) + +struct md5_ctx { + u32 hash[MD5_HASH_WORDS]; + u32 block[MD5_BLOCK_WORDS]; + u64 byte_count; +}; + +static void md5_transform(u32 *hash, u32 const *in) +{ + u32 a, b, c, d; + + a =3D hash[0]; + b =3D hash[1]; + c =3D hash[2]; + d =3D hash[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + hash[0] +=3D a; + hash[1] +=3D b; + hash[2] +=3D c; + hash[3] +=3D d; +} + +/* XXX: this stuff can be optimized */ +static inline void le32_to_cpu_array(u32 *buf, unsigned int words) +{ + while (words--) { + __le32_to_cpus(buf); + buf++; + } +} + +static inline void cpu_to_le32_array(u32 *buf, unsigned int words) +{ + while (words--) { + __cpu_to_le32s(buf); + buf++; + } +} + +static inline void md5_transform_helper(struct md5_ctx *ctx) +{ + le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); + md5_transform(ctx->hash, ctx->block); +} + +static void md5_init(void *ctx) +{ + struct md5_ctx *mctx =3D ctx; + + mctx->hash[0] =3D 0x67452301; + mctx->hash[1] =3D 0xefcdab89; + mctx->hash[2] =3D 0x98badcfe; + mctx->hash[3] =3D 0x10325476; + mctx->byte_count =3D 0; +} + +static void md5_update(void *ctx, const u8 *data, unsigned int len) +{ + struct md5_ctx *mctx =3D ctx; + const u32 avail =3D sizeof(mctx->block) - (mctx->byte_count & 0x3f); + + mctx->byte_count +=3D len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + return; + } + + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, avail); + + md5_transform_helper(mctx); + data +=3D avail; + len -=3D avail; + + while (len >=3D sizeof(mctx->block)) { + memcpy(mctx->block, data, sizeof(mctx->block)); + md5_transform_helper(mctx); + data +=3D sizeof(mctx->block); + len -=3D sizeof(mctx->block); + } + + memcpy(mctx->block, data, len); +} + +static void md5_final(void *ctx, u8 *out) +{ + struct md5_ctx *mctx =3D ctx; + const unsigned int offset =3D mctx->byte_count & 0x3f; + char *p =3D (char *)mctx->block + offset; + int padding =3D 56 - (offset + 1); + + *p++ =3D 0x80; + if (padding < 0) { + memset(p, 0x00, padding + sizeof (u64)); + md5_transform_helper(mctx); + p =3D (char *)mctx->block; + padding =3D 56; + } + + memset(p, 0, padding); + mctx->block[14] =3D mctx->byte_count << 3; + mctx->block[15] =3D mctx->byte_count >> 29; + le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - + sizeof(u64)) / sizeof(u32)); + md5_transform(mctx->hash, mctx->block); + cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); + memcpy(out, mctx->hash, sizeof(mctx->hash)); + memset(mctx, 0, sizeof(mctx)); +} + +static struct crypto_alg alg =3D { + .cra_name =3D "md5", + .cra_flags =3D CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize =3D MD5_HMAC_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct md5_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(alg.cra_list), + .cra_u =3D { .digest =3D { + .dia_digestsize =3D MD5_DIGEST_SIZE, + .dia_init =3D md5_init, + .dia_update =3D md5_update, + .dia_final =3D md5_final } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MD5 Message Digest Algorithm"); diff -Nru a/crypto/proc.c b/crypto/proc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/proc.c Thu May 8 10:41:38 2003 @@ -0,0 +1,106 @@ +/* + * Scatterlist Cryptographic API. + * + * Procfs information. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include "internal.h" + +extern struct list_head crypto_alg_list; +extern struct rw_semaphore crypto_alg_sem; + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + struct list_head *v; + loff_t n =3D *pos; + + down_read(&crypto_alg_sem); + list_for_each(v, &crypto_alg_list) + if (!n--) + return list_entry(v, struct crypto_alg, cra_list); + return NULL; +} + +static void *c_next(struct seq_file *m, void *p, loff_t *pos) +{ + struct list_head *v =3D p; +=09 + (*pos)++; + v =3D v->next; + return (v =3D=3D &crypto_alg_list) ? + NULL : list_entry(v, struct crypto_alg, cra_list); +} + +static void c_stop(struct seq_file *m, void *p) +{ + up_read(&crypto_alg_sem); +} + +static int c_show(struct seq_file *m, void *p) +{ + struct crypto_alg *alg =3D (struct crypto_alg *)p; +=09 + seq_printf(m, "name : %s\n", alg->cra_name); + seq_printf(m, "module : %s\n", alg->cra_module->name); +=09 + switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_CIPHER: + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "min keysize : %u\n", + alg->cra_cipher.cia_min_keysize); + seq_printf(m, "max keysize : %u\n", + alg->cra_cipher.cia_max_keysize); + seq_printf(m, "ivsize : %u\n", + alg->cra_cipher.cia_ivsize); + break; + =09 + case CRYPTO_ALG_TYPE_DIGEST: + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "digestsize : %u\n", + alg->cra_digest.dia_digestsize); + break; + } + + seq_putc(m, '\n'); + return 0; +} + +static struct seq_operations crypto_seq_ops =3D { + .start =3D c_start, + .next =3D c_next, + .stop =3D c_stop, + .show =3D c_show +}; + +static int crypto_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &crypto_seq_ops); +} + =20 +static struct file_operations proc_crypto_ops =3D { + .open =3D crypto_info_open, + .read =3D seq_read, + .llseek =3D seq_lseek, + .release =3D seq_release +}; + +void __init crypto_init_proc(void) +{ + struct proc_dir_entry *proc; +=09 + proc =3D create_proc_entry("crypto", 0, NULL); + if (proc) + proc->proc_fops =3D &proc_crypto_ops; +} diff -Nru a/crypto/serpent.c b/crypto/serpent.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/serpent.c Thu May 8 10:41:38 2003 @@ -0,0 +1,507 @@ +/* + * Cryptographic API. + * + * Serpent Cipher Algorithm. + * + * Copyright (C) 2002 Dag Arne Osvik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +/* Key is padded to the maximum of 256 bits before round key generation. + * Any key length <=3D 256 bits (32 bytes) is allowed by the algorithm. + */ + +#define SERPENT_MIN_KEY_SIZE 0 +#define SERPENT_MAX_KEY_SIZE 32 +#define SERPENT_EXPKEY_WORDS 132 +#define SERPENT_BLOCK_SIZE 16 + +#define PHI 0x9e3779b9UL +#define ROL(x,r) ((x) =3D ((x) << (r)) | ((x) >> (32-(r)))) +#define ROR(x,r) ((x) =3D ((x) >> (r)) | ((x) << (32-(r)))) + +#define keyiter(a,b,c,d,i,j) \ + b ^=3D d; b ^=3D c; b ^=3D a; b ^=3D PHI ^ i; ROL(b,11); k[j] =3D = b; + +#define loadkeys(x0,x1,x2,x3,i) \ + x0=3Dk[i]; x1=3Dk[i+1]; x2=3Dk[i+2]; x3=3Dk[i+3]; + +#define storekeys(x0,x1,x2,x3,i) \ + k[i]=3Dx0; k[i+1]=3Dx1; k[i+2]=3Dx2; k[i+3]=3Dx3; + +#define K(x0,x1,x2,x3,i) \ + x3 ^=3D k[4*(i)+3]; x2 ^=3D k[4*(i)+2]; \ + x1 ^=3D k[4*(i)+1]; x0 ^=3D k[4*(i)+0]; + +#define LK(x0,x1,x2,x3,x4,i) \ + ROL(x0,13); \ + ROL(x2,3); x1 ^=3D x0; x4 =3D x0 << 3; \ + x3 ^=3D x2; x1 ^=3D x2; \ + ROL(x1,1); x3 ^=3D x4; \ + ROL(x3,7); x4 =3D x1; \ + x0 ^=3D x1; x4 <<=3D 7; x2 ^=3D x3; \ + x0 ^=3D x3; x2 ^=3D x4; x3 ^=3D k[4*i+3]; \ + x1 ^=3D k[4*i+1]; ROL(x0,5); ROL(x2,22); \ + x0 ^=3D k[4*i+0]; x2 ^=3D k[4*i+2]; + +#define KL(x0,x1,x2,x3,x4,i) \ + x0 ^=3D k[4*i+0]; x1 ^=3D k[4*i+1]; x2 ^=3D k[4*i+2]; \ + x3 ^=3D k[4*i+3]; ROR(x0,5); ROR(x2,22); \ + x4 =3D x1; x2 ^=3D x3; x0 ^=3D x3; \ + x4 <<=3D 7; x0 ^=3D x1; ROR(x1,1); \ + x2 ^=3D x4; ROR(x3,7); x4 =3D x0 << 3; \ + x1 ^=3D x0; x3 ^=3D x4; ROR(x0,13); \ + x1 ^=3D x2; x3 ^=3D x2; ROR(x2,3); + +#define S0(x0,x1,x2,x3,x4) \ + x4 =3D x3; \ + x3 |=3D x0; x0 ^=3D x4; x4 ^=3D x2; \ + x4 =3D~ x4; x3 ^=3D x1; x1 &=3D x0; \ + x1 ^=3D x4; x2 ^=3D x0; x0 ^=3D x3; \ + x4 |=3D x0; x0 ^=3D x2; x2 &=3D x1; \ + x3 ^=3D x2; x1 =3D~ x1; x2 ^=3D x4; \ + x1 ^=3D x2; + +#define S1(x0,x1,x2,x3,x4) \ + x4 =3D x1; \ + x1 ^=3D x0; x0 ^=3D x3; x3 =3D~ x3; \ + x4 &=3D x1; x0 |=3D x1; x3 ^=3D x2; \ + x0 ^=3D x3; x1 ^=3D x3; x3 ^=3D x4; \ + x1 |=3D x4; x4 ^=3D x2; x2 &=3D x0; \ + x2 ^=3D x1; x1 |=3D x0; x0 =3D~ x0; \ + x0 ^=3D x2; x4 ^=3D x1; + +#define S2(x0,x1,x2,x3,x4) \ + x3 =3D~ x3; \ + x1 ^=3D x0; x4 =3D x0; x0 &=3D x2; \ + x0 ^=3D x3; x3 |=3D x4; x2 ^=3D x1; \ + x3 ^=3D x1; x1 &=3D x0; x0 ^=3D x2; \ + x2 &=3D x3; x3 |=3D x1; x0 =3D~ x0; \ + x3 ^=3D x0; x4 ^=3D x0; x0 ^=3D x2; \ + x1 |=3D x2; + +#define S3(x0,x1,x2,x3,x4) \ + x4 =3D x1; \ + x1 ^=3D x3; x3 |=3D x0; x4 &=3D x0; \ + x0 ^=3D x2; x2 ^=3D x1; x1 &=3D x3; \ + x2 ^=3D x3; x0 |=3D x4; x4 ^=3D x3; \ + x1 ^=3D x0; x0 &=3D x3; x3 &=3D x4; \ + x3 ^=3D x2; x4 |=3D x1; x2 &=3D x1; \ + x4 ^=3D x3; x0 ^=3D x3; x3 ^=3D x2; + +#define S4(x0,x1,x2,x3,x4) \ + x4 =3D x3; \ + x3 &=3D x0; x0 ^=3D x4; \ + x3 ^=3D x2; x2 |=3D x4; x0 ^=3D x1; \ + x4 ^=3D x3; x2 |=3D x0; \ + x2 ^=3D x1; x1 &=3D x0; \ + x1 ^=3D x4; x4 &=3D x2; x2 ^=3D x3; \ + x4 ^=3D x0; x3 |=3D x1; x1 =3D~ x1; \ + x3 ^=3D x0; + +#define S5(x0,x1,x2,x3,x4) \ + x4 =3D x1; x1 |=3D x0; \ + x2 ^=3D x1; x3 =3D~ x3; x4 ^=3D x0; \ + x0 ^=3D x2; x1 &=3D x4; x4 |=3D x3; \ + x4 ^=3D x0; x0 &=3D x3; x1 ^=3D x3; \ + x3 ^=3D x2; x0 ^=3D x1; x2 &=3D x4; \ + x1 ^=3D x2; x2 &=3D x0; \ + x3 ^=3D x2; + +#define S6(x0,x1,x2,x3,x4) \ + x4 =3D x1; \ + x3 ^=3D x0; x1 ^=3D x2; x2 ^=3D x0; \ + x0 &=3D x3; x1 |=3D x3; x4 =3D~ x4; \ + x0 ^=3D x1; x1 ^=3D x2; \ + x3 ^=3D x4; x4 ^=3D x0; x2 &=3D x0; \ + x4 ^=3D x1; x2 ^=3D x3; x3 &=3D x1; \ + x3 ^=3D x0; x1 ^=3D x2; + +#define S7(x0,x1,x2,x3,x4) \ + x1 =3D~ x1; \ + x4 =3D x1; x0 =3D~ x0; x1 &=3D x2; \ + x1 ^=3D x3; x3 |=3D x4; x4 ^=3D x2; \ + x2 ^=3D x3; x3 ^=3D x0; x0 |=3D x1; \ + x2 &=3D x0; x0 ^=3D x4; x4 ^=3D x3; \ + x3 &=3D x0; x4 ^=3D x1; \ + x2 ^=3D x4; x3 ^=3D x1; x4 |=3D x0; \ + x4 ^=3D x1; + +#define SI0(x0,x1,x2,x3,x4) \ + x4 =3D x3; x1 ^=3D x0; \ + x3 |=3D x1; x4 ^=3D x1; x0 =3D~ x0; \ + x2 ^=3D x3; x3 ^=3D x0; x0 &=3D x1; \ + x0 ^=3D x2; x2 &=3D x3; x3 ^=3D x4; \ + x2 ^=3D x3; x1 ^=3D x3; x3 &=3D x0; \ + x1 ^=3D x0; x0 ^=3D x2; x4 ^=3D x3; + +#define SI1(x0,x1,x2,x3,x4) \ + x1 ^=3D x3; x4 =3D x0; \ + x0 ^=3D x2; x2 =3D~ x2; x4 |=3D x1; \ + x4 ^=3D x3; x3 &=3D x1; x1 ^=3D x2; \ + x2 &=3D x4; x4 ^=3D x1; x1 |=3D x3; \ + x3 ^=3D x0; x2 ^=3D x0; x0 |=3D x4; \ + x2 ^=3D x4; x1 ^=3D x0; \ + x4 ^=3D x1; + +#define SI2(x0,x1,x2,x3,x4) \ + x2 ^=3D x1; x4 =3D x3; x3 =3D~ x3; \ + x3 |=3D x2; x2 ^=3D x4; x4 ^=3D x0; \ + x3 ^=3D x1; x1 |=3D x2; x2 ^=3D x0; \ + x1 ^=3D x4; x4 |=3D x3; x2 ^=3D x3; \ + x4 ^=3D x2; x2 &=3D x1; \ + x2 ^=3D x3; x3 ^=3D x4; x4 ^=3D x0; + +#define SI3(x0,x1,x2,x3,x4) \ + x2 ^=3D x1; \ + x4 =3D x1; x1 &=3D x2; \ + x1 ^=3D x0; x0 |=3D x4; x4 ^=3D x3; \ + x0 ^=3D x3; x3 |=3D x1; x1 ^=3D x2; \ + x1 ^=3D x3; x0 ^=3D x2; x2 ^=3D x3; \ + x3 &=3D x1; x1 ^=3D x0; x0 &=3D x2; \ + x4 ^=3D x3; x3 ^=3D x0; x0 ^=3D x1; + +#define SI4(x0,x1,x2,x3,x4) \ + x2 ^=3D x3; x4 =3D x0; x0 &=3D x1; \ + x0 ^=3D x2; x2 |=3D x3; x4 =3D~ x4; \ + x1 ^=3D x0; x0 ^=3D x2; x2 &=3D x4; \ + x2 ^=3D x0; x0 |=3D x4; \ + x0 ^=3D x3; x3 &=3D x2; \ + x4 ^=3D x3; x3 ^=3D x1; x1 &=3D x0; \ + x4 ^=3D x1; x0 ^=3D x3; + +#define SI5(x0,x1,x2,x3,x4) \ + x4 =3D x1; x1 |=3D x2; \ + x2 ^=3D x4; x1 ^=3D x3; x3 &=3D x4; \ + x2 ^=3D x3; x3 |=3D x0; x0 =3D~ x0; \ + x3 ^=3D x2; x2 |=3D x0; x4 ^=3D x1; \ + x2 ^=3D x4; x4 &=3D x0; x0 ^=3D x1; \ + x1 ^=3D x3; x0 &=3D x2; x2 ^=3D x3; \ + x0 ^=3D x2; x2 ^=3D x4; x4 ^=3D x3; + +#define SI6(x0,x1,x2,x3,x4) \ + x0 ^=3D x2; \ + x4 =3D x0; x0 &=3D x3; x2 ^=3D x3; \ + x0 ^=3D x2; x3 ^=3D x1; x2 |=3D x4; \ + x2 ^=3D x3; x3 &=3D x0; x0 =3D~ x0; \ + x3 ^=3D x1; x1 &=3D x2; x4 ^=3D x0; \ + x3 ^=3D x4; x4 ^=3D x2; x0 ^=3D x1; \ + x2 ^=3D x0; + +#define SI7(x0,x1,x2,x3,x4) \ + x4 =3D x3; x3 &=3D x0; x0 ^=3D x2; \ + x2 |=3D x4; x4 ^=3D x1; x0 =3D~ x0; \ + x1 |=3D x3; x4 ^=3D x0; x0 &=3D x2; \ + x0 ^=3D x1; x1 &=3D x2; x3 ^=3D x2; \ + x4 ^=3D x3; x2 &=3D x3; x3 |=3D x0; \ + x1 ^=3D x4; x3 ^=3D x4; x4 &=3D x0; \ + x4 ^=3D x2; + +struct serpent_ctx { + u8 iv[SERPENT_BLOCK_SIZE]; + u32 expkey[SERPENT_EXPKEY_WORDS]; +}; + +static int setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flag= s) +{ + u32 *k =3D ((struct serpent_ctx *)ctx)->expkey; + u8 *k8 =3D (u8 *)k; + u32 r0,r1,r2,r3,r4; + int i; + + if ((keylen < SERPENT_MIN_KEY_SIZE) + || (keylen > SERPENT_MAX_KEY_SIZE)) + { + *flags |=3D CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* Copy key, add padding */ + + for (i =3D 0; i < keylen; ++i) + k8[i] =3D key[i]; + if (i < SERPENT_MAX_KEY_SIZE) + k8[i++] =3D 1; + while (i < SERPENT_MAX_KEY_SIZE) + k8[i++] =3D 0; + + /* Expand key using polynomial */ + + r0 =3D le32_to_cpu(k[3]); + r1 =3D le32_to_cpu(k[4]); + r2 =3D le32_to_cpu(k[5]); + r3 =3D le32_to_cpu(k[6]); + r4 =3D le32_to_cpu(k[7]); + + keyiter(le32_to_cpu(k[0]),r0,r4,r2,0,0); + keyiter(le32_to_cpu(k[1]),r1,r0,r3,1,1); + keyiter(le32_to_cpu(k[2]),r2,r1,r4,2,2); + keyiter(le32_to_cpu(k[3]),r3,r2,r0,3,3); + keyiter(le32_to_cpu(k[4]),r4,r3,r1,4,4); + keyiter(le32_to_cpu(k[5]),r0,r4,r2,5,5); + keyiter(le32_to_cpu(k[6]),r1,r0,r3,6,6); + keyiter(le32_to_cpu(k[7]),r2,r1,r4,7,7); + + keyiter(k[ 0],r3,r2,r0, 8, 8); keyiter(k[ 1],r4,r3,r1, 9, 9); + keyiter(k[ 2],r0,r4,r2, 10, 10); keyiter(k[ 3],r1,r0,r3, 11, 11); + keyiter(k[ 4],r2,r1,r4, 12, 12); keyiter(k[ 5],r3,r2,r0, 13, 13); + keyiter(k[ 6],r4,r3,r1, 14, 14); keyiter(k[ 7],r0,r4,r2, 15, 15); + keyiter(k[ 8],r1,r0,r3, 16, 16); keyiter(k[ 9],r2,r1,r4, 17, 17); + keyiter(k[ 10],r3,r2,r0, 18, 18); keyiter(k[ 11],r4,r3,r1, 19, 19); + keyiter(k[ 12],r0,r4,r2, 20, 20); keyiter(k[ 13],r1,r0,r3, 21, 21); + keyiter(k[ 14],r2,r1,r4, 22, 22); keyiter(k[ 15],r3,r2,r0, 23, 23); + keyiter(k[ 16],r4,r3,r1, 24, 24); keyiter(k[ 17],r0,r4,r2, 25, 25); + keyiter(k[ 18],r1,r0,r3, 26, 26); keyiter(k[ 19],r2,r1,r4, 27, 27); + keyiter(k[ 20],r3,r2,r0, 28, 28); keyiter(k[ 21],r4,r3,r1, 29, 29); + keyiter(k[ 22],r0,r4,r2, 30, 30); keyiter(k[ 23],r1,r0,r3, 31, 31); + + k +=3D 50; + + keyiter(k[-26],r2,r1,r4, 32,-18); keyiter(k[-25],r3,r2,r0, 33,-17); + keyiter(k[-24],r4,r3,r1, 34,-16); keyiter(k[-23],r0,r4,r2, 35,-15); + keyiter(k[-22],r1,r0,r3, 36,-14); keyiter(k[-21],r2,r1,r4, 37,-13); + keyiter(k[-20],r3,r2,r0, 38,-12); keyiter(k[-19],r4,r3,r1, 39,-11); + keyiter(k[-18],r0,r4,r2, 40,-10); keyiter(k[-17],r1,r0,r3, 41, -9); + keyiter(k[-16],r2,r1,r4, 42, -8); keyiter(k[-15],r3,r2,r0, 43, -7); + keyiter(k[-14],r4,r3,r1, 44, -6); keyiter(k[-13],r0,r4,r2, 45, -5); + keyiter(k[-12],r1,r0,r3, 46, -4); keyiter(k[-11],r2,r1,r4, 47, -3); + keyiter(k[-10],r3,r2,r0, 48, -2); keyiter(k[ -9],r4,r3,r1, 49, -1); + keyiter(k[ -8],r0,r4,r2, 50, 0); keyiter(k[ -7],r1,r0,r3, 51, 1); + keyiter(k[ -6],r2,r1,r4, 52, 2); keyiter(k[ -5],r3,r2,r0, 53, 3); + keyiter(k[ -4],r4,r3,r1, 54, 4); keyiter(k[ -3],r0,r4,r2, 55, 5); + keyiter(k[ -2],r1,r0,r3, 56, 6); keyiter(k[ -1],r2,r1,r4, 57, 7); + keyiter(k[ 0],r3,r2,r0, 58, 8); keyiter(k[ 1],r4,r3,r1, 59, 9); + keyiter(k[ 2],r0,r4,r2, 60, 10); keyiter(k[ 3],r1,r0,r3, 61, 11); + keyiter(k[ 4],r2,r1,r4, 62, 12); keyiter(k[ 5],r3,r2,r0, 63, 13); + keyiter(k[ 6],r4,r3,r1, 64, 14); keyiter(k[ 7],r0,r4,r2, 65, 15); + keyiter(k[ 8],r1,r0,r3, 66, 16); keyiter(k[ 9],r2,r1,r4, 67, 17); + keyiter(k[ 10],r3,r2,r0, 68, 18); keyiter(k[ 11],r4,r3,r1, 69, 19); + keyiter(k[ 12],r0,r4,r2, 70, 20); keyiter(k[ 13],r1,r0,r3, 71, 21); + keyiter(k[ 14],r2,r1,r4, 72, 22); keyiter(k[ 15],r3,r2,r0, 73, 23); + keyiter(k[ 16],r4,r3,r1, 74, 24); keyiter(k[ 17],r0,r4,r2, 75, 25); + keyiter(k[ 18],r1,r0,r3, 76, 26); keyiter(k[ 19],r2,r1,r4, 77, 27); + keyiter(k[ 20],r3,r2,r0, 78, 28); keyiter(k[ 21],r4,r3,r1, 79, 29); + keyiter(k[ 22],r0,r4,r2, 80, 30); keyiter(k[ 23],r1,r0,r3, 81, 31); + + k +=3D 50; + + keyiter(k[-26],r2,r1,r4, 82,-18); keyiter(k[-25],r3,r2,r0, 83,-17); + keyiter(k[-24],r4,r3,r1, 84,-16); keyiter(k[-23],r0,r4,r2, 85,-15); + keyiter(k[-22],r1,r0,r3, 86,-14); keyiter(k[-21],r2,r1,r4, 87,-13); + keyiter(k[-20],r3,r2,r0, 88,-12); keyiter(k[-19],r4,r3,r1, 89,-11); + keyiter(k[-18],r0,r4,r2, 90,-10); keyiter(k[-17],r1,r0,r3, 91, -9); + keyiter(k[-16],r2,r1,r4, 92, -8); keyiter(k[-15],r3,r2,r0, 93, -7); + keyiter(k[-14],r4,r3,r1, 94, -6); keyiter(k[-13],r0,r4,r2, 95, -5); + keyiter(k[-12],r1,r0,r3, 96, -4); keyiter(k[-11],r2,r1,r4, 97, -3); + keyiter(k[-10],r3,r2,r0, 98, -2); keyiter(k[ -9],r4,r3,r1, 99, -1); + keyiter(k[ -8],r0,r4,r2,100, 0); keyiter(k[ -7],r1,r0,r3,101, 1); + keyiter(k[ -6],r2,r1,r4,102, 2); keyiter(k[ -5],r3,r2,r0,103, 3); + keyiter(k[ -4],r4,r3,r1,104, 4); keyiter(k[ -3],r0,r4,r2,105, 5); + keyiter(k[ -2],r1,r0,r3,106, 6); keyiter(k[ -1],r2,r1,r4,107, 7); + keyiter(k[ 0],r3,r2,r0,108, 8); keyiter(k[ 1],r4,r3,r1,109, 9); + keyiter(k[ 2],r0,r4,r2,110, 10); keyiter(k[ 3],r1,r0,r3,111, 11); + keyiter(k[ 4],r2,r1,r4,112, 12); keyiter(k[ 5],r3,r2,r0,113, 13); + keyiter(k[ 6],r4,r3,r1,114, 14); keyiter(k[ 7],r0,r4,r2,115, 15); + keyiter(k[ 8],r1,r0,r3,116, 16); keyiter(k[ 9],r2,r1,r4,117, 17); + keyiter(k[ 10],r3,r2,r0,118, 18); keyiter(k[ 11],r4,r3,r1,119, 19); + keyiter(k[ 12],r0,r4,r2,120, 20); keyiter(k[ 13],r1,r0,r3,121, 21); + keyiter(k[ 14],r2,r1,r4,122, 22); keyiter(k[ 15],r3,r2,r0,123, 23); + keyiter(k[ 16],r4,r3,r1,124, 24); keyiter(k[ 17],r0,r4,r2,125, 25); + keyiter(k[ 18],r1,r0,r3,126, 26); keyiter(k[ 19],r2,r1,r4,127, 27); + keyiter(k[ 20],r3,r2,r0,128, 28); keyiter(k[ 21],r4,r3,r1,129, 29); + keyiter(k[ 22],r0,r4,r2,130, 30); keyiter(k[ 23],r1,r0,r3,131, 31); + + /* Apply S-boxes */ + + S3(r3,r4,r0,r1,r2); storekeys(r1,r2,r4,r3, 28); loadkeys(r1,r2,r4,r3, 24)= ; + S4(r1,r2,r4,r3,r0); storekeys(r2,r4,r3,r0, 24); loadkeys(r2,r4,r3,r0, 20)= ; + S5(r2,r4,r3,r0,r1); storekeys(r1,r2,r4,r0, 20); loadkeys(r1,r2,r4,r0, 16)= ; + S6(r1,r2,r4,r0,r3); storekeys(r4,r3,r2,r0, 16); loadkeys(r4,r3,r2,r0, 12)= ; + S7(r4,r3,r2,r0,r1); storekeys(r1,r2,r0,r4, 12); loadkeys(r1,r2,r0,r4, 8)= ; + S0(r1,r2,r0,r4,r3); storekeys(r0,r2,r4,r1, 8); loadkeys(r0,r2,r4,r1, 4)= ; + S1(r0,r2,r4,r1,r3); storekeys(r3,r4,r1,r0, 4); loadkeys(r3,r4,r1,r0, 0)= ; + S2(r3,r4,r1,r0,r2); storekeys(r2,r4,r3,r0, 0); loadkeys(r2,r4,r3,r0, -4)= ; + S3(r2,r4,r3,r0,r1); storekeys(r0,r1,r4,r2, -4); loadkeys(r0,r1,r4,r2, -8)= ; + S4(r0,r1,r4,r2,r3); storekeys(r1,r4,r2,r3, -8); loadkeys(r1,r4,r2,r3,-12)= ; + S5(r1,r4,r2,r3,r0); storekeys(r0,r1,r4,r3,-12); loadkeys(r0,r1,r4,r3,-16)= ; + S6(r0,r1,r4,r3,r2); storekeys(r4,r2,r1,r3,-16); loadkeys(r4,r2,r1,r3,-20)= ; + S7(r4,r2,r1,r3,r0); storekeys(r0,r1,r3,r4,-20); loadkeys(r0,r1,r3,r4,-24)= ; + S0(r0,r1,r3,r4,r2); storekeys(r3,r1,r4,r0,-24); loadkeys(r3,r1,r4,r0,-28)= ; + k -=3D 50; + S1(r3,r1,r4,r0,r2); storekeys(r2,r4,r0,r3, 22); loadkeys(r2,r4,r0,r3, 18)= ; + S2(r2,r4,r0,r3,r1); storekeys(r1,r4,r2,r3, 18); loadkeys(r1,r4,r2,r3, 14)= ; + S3(r1,r4,r2,r3,r0); storekeys(r3,r0,r4,r1, 14); loadkeys(r3,r0,r4,r1, 10)= ; + S4(r3,r0,r4,r1,r2); storekeys(r0,r4,r1,r2, 10); loadkeys(r0,r4,r1,r2, 6)= ; + S5(r0,r4,r1,r2,r3); storekeys(r3,r0,r4,r2, 6); loadkeys(r3,r0,r4,r2, 2)= ; + S6(r3,r0,r4,r2,r1); storekeys(r4,r1,r0,r2, 2); loadkeys(r4,r1,r0,r2, -2)= ; + S7(r4,r1,r0,r2,r3); storekeys(r3,r0,r2,r4, -2); loadkeys(r3,r0,r2,r4, -6)= ; + S0(r3,r0,r2,r4,r1); storekeys(r2,r0,r4,r3, -6); loadkeys(r2,r0,r4,r3,-10)= ; + S1(r2,r0,r4,r3,r1); storekeys(r1,r4,r3,r2,-10); loadkeys(r1,r4,r3,r2,-14)= ; + S2(r1,r4,r3,r2,r0); storekeys(r0,r4,r1,r2,-14); loadkeys(r0,r4,r1,r2,-18)= ; + S3(r0,r4,r1,r2,r3); storekeys(r2,r3,r4,r0,-18); loadkeys(r2,r3,r4,r0,-22)= ; + k -=3D 50; + S4(r2,r3,r4,r0,r1); storekeys(r3,r4,r0,r1, 28); loadkeys(r3,r4,r0,r1, 24)= ; + S5(r3,r4,r0,r1,r2); storekeys(r2,r3,r4,r1, 24); loadkeys(r2,r3,r4,r1, 20)= ; + S6(r2,r3,r4,r1,r0); storekeys(r4,r0,r3,r1, 20); loadkeys(r4,r0,r3,r1, 16)= ; + S7(r4,r0,r3,r1,r2); storekeys(r2,r3,r1,r4, 16); loadkeys(r2,r3,r1,r4, 12)= ; + S0(r2,r3,r1,r4,r0); storekeys(r1,r3,r4,r2, 12); loadkeys(r1,r3,r4,r2, 8)= ; + S1(r1,r3,r4,r2,r0); storekeys(r0,r4,r2,r1, 8); loadkeys(r0,r4,r2,r1, 4)= ; + S2(r0,r4,r2,r1,r3); storekeys(r3,r4,r0,r1, 4); loadkeys(r3,r4,r0,r1, 0)= ; + S3(r3,r4,r0,r1,r2); storekeys(r1,r2,r4,r3, 0); + + return 0; +} + +static void encrypt(void *ctx, u8 *dst, const u8 *src) +{ + const u32 + *k =3D ((struct serpent_ctx *)ctx)->expkey, + *s =3D (const u32 *)src; + u32 *d =3D (u32 *)dst, + r0, r1, r2, r3, r4; + +/* + * Note: The conversions between u8* and u32* might cause trouble + * on architectures with stricter alignment rules than x86 + */ + + r0 =3D le32_to_cpu(s[0]); + r1 =3D le32_to_cpu(s[1]); + r2 =3D le32_to_cpu(s[2]); + r3 =3D le32_to_cpu(s[3]); + + K(r0,r1,r2,r3,0); + S0(r0,r1,r2,r3,r4); LK(r2,r1,r3,r0,r4,1); + S1(r2,r1,r3,r0,r4); LK(r4,r3,r0,r2,r1,2); + S2(r4,r3,r0,r2,r1); LK(r1,r3,r4,r2,r0,3); + S3(r1,r3,r4,r2,r0); LK(r2,r0,r3,r1,r4,4); + S4(r2,r0,r3,r1,r4); LK(r0,r3,r1,r4,r2,5); + S5(r0,r3,r1,r4,r2); LK(r2,r0,r3,r4,r1,6); + S6(r2,r0,r3,r4,r1); LK(r3,r1,r0,r4,r2,7); + S7(r3,r1,r0,r4,r2); LK(r2,r0,r4,r3,r1,8); + S0(r2,r0,r4,r3,r1); LK(r4,r0,r3,r2,r1,9); + S1(r4,r0,r3,r2,r1); LK(r1,r3,r2,r4,r0,10); + S2(r1,r3,r2,r4,r0); LK(r0,r3,r1,r4,r2,11); + S3(r0,r3,r1,r4,r2); LK(r4,r2,r3,r0,r1,12); + S4(r4,r2,r3,r0,r1); LK(r2,r3,r0,r1,r4,13); + S5(r2,r3,r0,r1,r4); LK(r4,r2,r3,r1,r0,14); + S6(r4,r2,r3,r1,r0); LK(r3,r0,r2,r1,r4,15); + S7(r3,r0,r2,r1,r4); LK(r4,r2,r1,r3,r0,16); + S0(r4,r2,r1,r3,r0); LK(r1,r2,r3,r4,r0,17); + S1(r1,r2,r3,r4,r0); LK(r0,r3,r4,r1,r2,18); + S2(r0,r3,r4,r1,r2); LK(r2,r3,r0,r1,r4,19); + S3(r2,r3,r0,r1,r4); LK(r1,r4,r3,r2,r0,20); + S4(r1,r4,r3,r2,r0); LK(r4,r3,r2,r0,r1,21); + S5(r4,r3,r2,r0,r1); LK(r1,r4,r3,r0,r2,22); + S6(r1,r4,r3,r0,r2); LK(r3,r2,r4,r0,r1,23); + S7(r3,r2,r4,r0,r1); LK(r1,r4,r0,r3,r2,24); + S0(r1,r4,r0,r3,r2); LK(r0,r4,r3,r1,r2,25); + S1(r0,r4,r3,r1,r2); LK(r2,r3,r1,r0,r4,26); + S2(r2,r3,r1,r0,r4); LK(r4,r3,r2,r0,r1,27); + S3(r4,r3,r2,r0,r1); LK(r0,r1,r3,r4,r2,28); + S4(r0,r1,r3,r4,r2); LK(r1,r3,r4,r2,r0,29); + S5(r1,r3,r4,r2,r0); LK(r0,r1,r3,r2,r4,30); + S6(r0,r1,r3,r2,r4); LK(r3,r4,r1,r2,r0,31); + S7(r3,r4,r1,r2,r0); K(r0,r1,r2,r3,32); + + d[0] =3D cpu_to_le32(r0); + d[1] =3D cpu_to_le32(r1); + d[2] =3D cpu_to_le32(r2); + d[3] =3D cpu_to_le32(r3); +} + +static void decrypt(void *ctx, u8 *dst, const u8 *src) +{ + const u32 + *k =3D ((struct serpent_ctx *)ctx)->expkey, + *s =3D (const u32 *)src; + u32 *d =3D (u32 *)dst, + r0, r1, r2, r3, r4; + + r0 =3D le32_to_cpu(s[0]); + r1 =3D le32_to_cpu(s[1]); + r2 =3D le32_to_cpu(s[2]); + r3 =3D le32_to_cpu(s[3]); + + K(r0,r1,r2,r3,32); + SI7(r0,r1,r2,r3,r4); KL(r1,r3,r0,r4,r2,31); + SI6(r1,r3,r0,r4,r2); KL(r0,r2,r4,r1,r3,30); + SI5(r0,r2,r4,r1,r3); KL(r2,r3,r0,r4,r1,29); + SI4(r2,r3,r0,r4,r1); KL(r2,r0,r1,r4,r3,28); + SI3(r2,r0,r1,r4,r3); KL(r1,r2,r3,r4,r0,27); + SI2(r1,r2,r3,r4,r0); KL(r2,r0,r4,r3,r1,26); + SI1(r2,r0,r4,r3,r1); KL(r1,r0,r4,r3,r2,25); + SI0(r1,r0,r4,r3,r2); KL(r4,r2,r0,r1,r3,24); + SI7(r4,r2,r0,r1,r3); KL(r2,r1,r4,r3,r0,23); + SI6(r2,r1,r4,r3,r0); KL(r4,r0,r3,r2,r1,22); + SI5(r4,r0,r3,r2,r1); KL(r0,r1,r4,r3,r2,21); + SI4(r0,r1,r4,r3,r2); KL(r0,r4,r2,r3,r1,20); + SI3(r0,r4,r2,r3,r1); KL(r2,r0,r1,r3,r4,19); + SI2(r2,r0,r1,r3,r4); KL(r0,r4,r3,r1,r2,18); + SI1(r0,r4,r3,r1,r2); KL(r2,r4,r3,r1,r0,17); + SI0(r2,r4,r3,r1,r0); KL(r3,r0,r4,r2,r1,16); + SI7(r3,r0,r4,r2,r1); KL(r0,r2,r3,r1,r4,15); + SI6(r0,r2,r3,r1,r4); KL(r3,r4,r1,r0,r2,14); + SI5(r3,r4,r1,r0,r2); KL(r4,r2,r3,r1,r0,13); + SI4(r4,r2,r3,r1,r0); KL(r4,r3,r0,r1,r2,12); + SI3(r4,r3,r0,r1,r2); KL(r0,r4,r2,r1,r3,11); + SI2(r0,r4,r2,r1,r3); KL(r4,r3,r1,r2,r0,10); + SI1(r4,r3,r1,r2,r0); KL(r0,r3,r1,r2,r4,9); + SI0(r0,r3,r1,r2,r4); KL(r1,r4,r3,r0,r2,8); + SI7(r1,r4,r3,r0,r2); KL(r4,r0,r1,r2,r3,7); + SI6(r4,r0,r1,r2,r3); KL(r1,r3,r2,r4,r0,6); + SI5(r1,r3,r2,r4,r0); KL(r3,r0,r1,r2,r4,5); + SI4(r3,r0,r1,r2,r4); KL(r3,r1,r4,r2,r0,4); + SI3(r3,r1,r4,r2,r0); KL(r4,r3,r0,r2,r1,3); + SI2(r4,r3,r0,r2,r1); KL(r3,r1,r2,r0,r4,2); + SI1(r3,r1,r2,r0,r4); KL(r4,r1,r2,r0,r3,1); + SI0(r4,r1,r2,r0,r3); K(r2,r3,r1,r4,0); + + d[0] =3D cpu_to_le32(r2); + d[1] =3D cpu_to_le32(r3); + d[2] =3D cpu_to_le32(r1); + d[3] =3D cpu_to_le32(r4); +} + +static struct crypto_alg serpent_alg =3D { + .cra_name =3D "serpent", + .cra_flags =3D CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize =3D SERPENT_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct serpent_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(serpent_alg.cra_list), + .cra_u =3D { .cipher =3D { + .cia_min_keysize =3D SERPENT_MIN_KEY_SIZE, + .cia_max_keysize =3D SERPENT_MAX_KEY_SIZE, + .cia_ivsize =3D SERPENT_BLOCK_SIZE, + .cia_setkey =3D setkey, + .cia_encrypt =3D encrypt, + .cia_decrypt =3D decrypt } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&serpent_alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&serpent_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Serpent Cipher Algorithm"); +MODULE_AUTHOR("Dag Arne Osvik "); diff -Nru a/crypto/sha1.c b/crypto/sha1.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/sha1.c Thu May 8 10:41:38 2003 @@ -0,0 +1,208 @@ +/* + * Cryptographic API. + * + * SHA1 Secure Hash Algorithm. + * + * Derived from cryptoapi implementation, adapted for in-place + * scatterlist interface. Originally based on the public domain + * implementation written by Steve Reid. + * + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald + * Copyright (c) Jean-Francois Dive + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_HMAC_BLOCK_SIZE 64 + +static inline u32 rol(u32 value, u32 bits) +{ + return (((value) << (bits)) | ((value) >> (32 - (bits)))); +} + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +# define blk0(i) block32[i] + +#define blk(i) (block32[i&15] =3D rol(block32[(i+13)&15]^block32[(i+8)&15]= \ + ^block32[(i+2)&15]^block32[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=3D((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5); \ + w=3Drol(w,30); +#define R1(v,w,x,y,z,i) z+=3D((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5); \ + w=3Drol(w,30); +#define R2(v,w,x,y,z,i) z+=3D(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=3Drol(w,= 30); +#define R3(v,w,x,y,z,i) z+=3D(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);= \ + w=3Drol(w,30); +#define R4(v,w,x,y,z,i) z+=3D(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=3Drol(w,= 30); + +struct sha1_ctx { + u64 count; + u32 state[5]; + u8 buffer[64]; +}; + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void sha1_transform(u32 *state, const u8 *in) +{ + u32 a, b, c, d, e; + u32 block32[16]; + + /* convert/copy data to workspace */ + for (a =3D 0; a < sizeof(block32)/sizeof(u32); a++) + block32[a] =3D be32_to_cpu (((const u32 *)in)[a]); + + /* Copy context->state[] to working vars */ + a =3D state[0]; + b =3D state[1]; + c =3D state[2]; + d =3D state[3]; + e =3D state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] +=3D a; + state[1] +=3D b; + state[2] +=3D c; + state[3] +=3D d; + state[4] +=3D e; + /* Wipe variables */ + a =3D b =3D c =3D d =3D e =3D 0; + memset (block32, 0x00, sizeof block32); +} + +static void sha1_init(void *ctx) +{ + struct sha1_ctx *sctx =3D ctx; + static const struct sha1_ctx initstate =3D { + 0, + { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, + { 0, } + }; + + *sctx =3D initstate; +} + +static void sha1_update(void *ctx, const u8 *data, unsigned int len) +{ + struct sha1_ctx *sctx =3D ctx; + unsigned int i, j; + + j =3D (sctx->count >> 3) & 0x3f; + sctx->count +=3D len << 3; + + if ((j + len) > 63) { + memcpy(&sctx->buffer[j], data, (i =3D 64-j)); + sha1_transform(sctx->state, sctx->buffer); + for ( ; i + 63 < len; i +=3D 64) { + sha1_transform(sctx->state, &data[i]); + } + j =3D 0; + } + else i =3D 0; + memcpy(&sctx->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ +static void sha1_final(void* ctx, u8 *out) +{ + struct sha1_ctx *sctx =3D ctx; + u32 i, j, index, padlen; + u64 t; + u8 bits[8] =3D { 0, }; + static const u8 padding[64] =3D { 0x80, }; + + t =3D sctx->count; + bits[7] =3D 0xff & t; t>>=3D8; + bits[6] =3D 0xff & t; t>>=3D8; + bits[5] =3D 0xff & t; t>>=3D8; + bits[4] =3D 0xff & t; t>>=3D8; + bits[3] =3D 0xff & t; t>>=3D8; + bits[2] =3D 0xff & t; t>>=3D8; + bits[1] =3D 0xff & t; t>>=3D8; + bits[0] =3D 0xff & t; + + /* Pad out to 56 mod 64 */ + index =3D (sctx->count >> 3) & 0x3f; + padlen =3D (index < 56) ? (56 - index) : ((64+56) - index); + sha1_update(sctx, padding, padlen); + + /* Append length */ + sha1_update(sctx, bits, sizeof bits);=20 + + /* Store state in digest */ + for (i =3D j =3D 0; i < 5; i++, j +=3D 4) { + u32 t2 =3D sctx->state[i]; + out[j+3] =3D t2 & 0xff; t2>>=3D8; + out[j+2] =3D t2 & 0xff; t2>>=3D8; + out[j+1] =3D t2 & 0xff; t2>>=3D8; + out[j ] =3D t2 & 0xff; + } + + /* Wipe context */ + memset(sctx, 0, sizeof *sctx); +} + +static struct crypto_alg alg =3D { + .cra_name =3D "sha1", + .cra_flags =3D CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize =3D SHA1_HMAC_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct sha1_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(alg.cra_list), + .cra_u =3D { .digest =3D { + .dia_digestsize =3D SHA1_DIGEST_SIZE, + .dia_init =3D sha1_init, + .dia_update =3D sha1_update, + .dia_final =3D sha1_final } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); diff -Nru a/crypto/sha256.c b/crypto/sha256.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/sha256.c Thu May 8 10:41:38 2003 @@ -0,0 +1,362 @@ +/* + * Cryptographic API. + * + * SHA-256, as specified in + * http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf + * + * SHA-256 code by Jean-Luc Cooke . + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_HMAC_BLOCK_SIZE 64 + +struct sha256_ctx { + u32 count[2]; + u32 state[8]; + u8 buf[128]; +}; + +static inline u32 Ch(u32 x, u32 y, u32 z) +{ + return ((x & y) ^ (~x & z)); +} + +static inline u32 Maj(u32 x, u32 y, u32 z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} + +static inline u32 RORu32(u32 x, u32 y) +{ + return (x >> y) | (x << (32 - y)); +} + +#define e0(x) (RORu32(x, 2) ^ RORu32(x,13) ^ RORu32(x,22)) +#define e1(x) (RORu32(x, 6) ^ RORu32(x,11) ^ RORu32(x,25)) +#define s0(x) (RORu32(x, 7) ^ RORu32(x,18) ^ (x >> 3)) +#define s1(x) (RORu32(x,17) ^ RORu32(x,19) ^ (x >> 10)) + +#define H0 0x6a09e667 +#define H1 0xbb67ae85 +#define H2 0x3c6ef372 +#define H3 0xa54ff53a +#define H4 0x510e527f +#define H5 0x9b05688c +#define H6 0x1f83d9ab +#define H7 0x5be0cd19 + +static inline void LOAD_OP(int I, u32 *W, const u8 *input) +{ + u32 t1 =3D input[(4 * I)] & 0xff; + + t1 <<=3D 8; + t1 |=3D input[(4 * I) + 1] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(4 * I) + 2] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(4 * I) + 3] & 0xff; + W[I] =3D t1; +} + +static inline void BLEND_OP(int I, u32 *W) +{ + W[I] =3D s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; +} + +static void sha256_transform(u32 *state, const u8 *input) +{ + u32 a, b, c, d, e, f, g, h, t1, t2; + u32 W[64]; + int i; + + /* load the input */ + for (i =3D 0; i < 16; i++) + LOAD_OP(i, W, input); + + /* now blend */ + for (i =3D 16; i < 64; i++) + BLEND_OP(i, W); + =20 + /* load the state into our registers */ + a=3Dstate[0]; b=3Dstate[1]; c=3Dstate[2]; d=3Dstate[3]; + e=3Dstate[4]; f=3Dstate[5]; g=3Dstate[6]; h=3Dstate[7]; + + /* now iterate */ + t1 =3D h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + t1 =3D h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0x243185be + W[10]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + t1 =3D h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + t1 =3D h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + t1 =3D h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + t1 =3D h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + t1 =3D h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + t1 =3D h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + + state[0] +=3D a; state[1] +=3D b; state[2] +=3D c; state[3] +=3D d; + state[4] +=3D e; state[5] +=3D f; state[6] +=3D g; state[7] +=3D h; + + /* clear any sensitive info... */ + a =3D b =3D c =3D d =3D e =3D f =3D g =3D h =3D t1 =3D t2 =3D 0; + memset(W, 0, 64 * sizeof(u32)); +} + +static void sha256_init(void *ctx) +{ + struct sha256_ctx *sctx =3D ctx; + sctx->state[0] =3D H0; + sctx->state[1] =3D H1; + sctx->state[2] =3D H2; + sctx->state[3] =3D H3; + sctx->state[4] =3D H4; + sctx->state[5] =3D H5; + sctx->state[6] =3D H6; + sctx->state[7] =3D H7; + sctx->count[0] =3D sctx->count[1] =3D 0; + memset(sctx->buf, 0, sizeof(sctx->buf)); +} + +static void sha256_update(void *ctx, const u8 *data, unsigned int len) +{ + struct sha256_ctx *sctx =3D ctx; + unsigned int i, index, part_len; + + /* Compute number of bytes mod 128 */ + index =3D (unsigned int)((sctx->count[0] >> 3) & 0x3f); + + /* Update number of bits */ + if ((sctx->count[0] +=3D (len << 3)) < (len << 3)) { + sctx->count[1]++; + sctx->count[1] +=3D (len >> 29); + } + + part_len =3D 64 - index; + + /* Transform as many times as possible. */ + if (len >=3D part_len) { + memcpy(&sctx->buf[index], data, part_len); + sha256_transform(sctx->state, sctx->buf); + + for (i =3D part_len; i + 63 < len; i +=3D 64) + sha256_transform(sctx->state, &data[i]); + index =3D 0; + } else { + i =3D 0; + } +=09 + /* Buffer remaining input */ + memcpy(&sctx->buf[index], &data[i], len-i); +} + +static void sha256_final(void* ctx, u8 *out) +{ + struct sha256_ctx *sctx =3D ctx; + u8 bits[8]; + unsigned int index, pad_len, t; + int i, j; + const u8 padding[64] =3D { 0x80, }; + + /* Save number of bits */ + t =3D sctx->count[0]; + bits[7] =3D t; t >>=3D 8; + bits[6] =3D t; t >>=3D 8; + bits[5] =3D t; t >>=3D 8; + bits[4] =3D t; + t =3D sctx->count[1]; + bits[3] =3D t; t >>=3D 8; + bits[2] =3D t; t >>=3D 8; + bits[1] =3D t; t >>=3D 8; + bits[0] =3D t; + + /* Pad out to 56 mod 64. */ + index =3D (sctx->count[0] >> 3) & 0x3f; + pad_len =3D (index < 56) ? (56 - index) : ((64+56) - index); + sha256_update(sctx, padding, pad_len); + + /* Append length (before padding) */ + sha256_update(sctx, bits, 8); + + /* Store state in digest */ + for (i =3D j =3D 0; i < 8; i++, j +=3D 4) { + t =3D sctx->state[i]; + out[j+3] =3D t; t >>=3D 8; + out[j+2] =3D t; t >>=3D 8; + out[j+1] =3D t; t >>=3D 8; + out[j ] =3D t; + } + + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(*sctx)); +} + + +static struct crypto_alg alg =3D { + .cra_name =3D "sha256", + .cra_flags =3D CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize =3D SHA256_HMAC_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct sha256_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(alg.cra_list), + .cra_u =3D { .digest =3D { + .dia_digestsize =3D SHA256_DIGEST_SIZE, + .dia_init =3D sha256_init, + .dia_update =3D sha256_update, + .dia_final =3D sha256_final } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm"); diff -Nru a/crypto/sha512.c b/crypto/sha512.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/sha512.c Thu May 8 10:41:38 2003 @@ -0,0 +1,373 @@ +/* SHA-512 code by Jean-Luc Cooke + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2003 Kyle McMartin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#define SHA384_DIGEST_SIZE 48 +#define SHA512_DIGEST_SIZE 64 +#define SHA384_HMAC_BLOCK_SIZE 96 +#define SHA512_HMAC_BLOCK_SIZE 128 + +struct sha512_ctx { + u64 state[8]; + u32 count[4]; + u8 buf[128]; +}; + +static inline u64 Ch(u64 x, u64 y, u64 z) +{ + return ((x & y) ^ (~x & z)); +} + +static inline u64 Maj(u64 x, u64 y, u64 z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} + +static inline u64 RORu64(u64 x, u64 y) +{ + return (x >> y) | (x << (64 - y)); +} + +const u64 sha512_K[80] =3D { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, + 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, + 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, + 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, +}; + +#define e0(x) (RORu64(x,28) ^ RORu64(x,34) ^ RORu64(x,39)) +#define e1(x) (RORu64(x,14) ^ RORu64(x,18) ^ RORu64(x,41)) +#define s0(x) (RORu64(x, 1) ^ RORu64(x, 8) ^ (x >> 7)) +#define s1(x) (RORu64(x,19) ^ RORu64(x,61) ^ (x >> 6)) + +/* H* initial state for SHA-512 */ +#define H0 0x6a09e667f3bcc908 +#define H1 0xbb67ae8584caa73b +#define H2 0x3c6ef372fe94f82b +#define H3 0xa54ff53a5f1d36f1 +#define H4 0x510e527fade682d1 +#define H5 0x9b05688c2b3e6c1f +#define H6 0x1f83d9abfb41bd6b +#define H7 0x5be0cd19137e2179 + +/* H'* initial state for SHA-384 */ +#define HP0 0xcbbb9d5dc1059ed8 +#define HP1 0x629a292a367cd507 +#define HP2 0x9159015a3070dd17 +#define HP3 0x152fecd8f70e5939 +#define HP4 0x67332667ffc00b31 +#define HP5 0x8eb44a8768581511 +#define HP6 0xdb0c2e0d64f98fa7 +#define HP7 0x47b5481dbefa4fa4 + +static inline void LOAD_OP(int I, u64 *W, const u8 *input) +{ + u64 t1 =3D input[(8*I) ] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(8*I)+1] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(8*I)+2] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(8*I)+3] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(8*I)+4] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(8*I)+5] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(8*I)+6] & 0xff; + t1 <<=3D 8; + t1 |=3D input[(8*I)+7] & 0xff; + W[I] =3D t1; +} + +static inline void BLEND_OP(int I, u64 *W) +{ + W[I] =3D s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; +} + +static void +sha512_transform(u64 *state, const u8 *input) +{ + u64 a, b, c, d, e, f, g, h, t1, t2; + u64 W[80]; + + int i; + + /* load the input */ + for (i =3D 0; i < 16; i++) + LOAD_OP(i, W, input); + + for (i =3D 16; i < 80; i++) { + BLEND_OP(i, W); + } + + /* load the state into our registers */ + a=3Dstate[0]; b=3Dstate[1]; c=3Dstate[2]; d=3Dstate[3]; =20 + e=3Dstate[4]; f=3Dstate[5]; g=3Dstate[6]; h=3Dstate[7]; =20 + =20 + /* now iterate */ + for (i=3D0; i<80; i+=3D8) { + t1 =3D h + e1(e) + Ch(e,f,g) + sha512_K[i ] + W[i ]; + t2 =3D e0(a) + Maj(a,b,c); d+=3Dt1; h=3Dt1+t2; + t1 =3D g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[i+1]; + t2 =3D e0(h) + Maj(h,a,b); c+=3Dt1; g=3Dt1+t2; + t1 =3D f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[i+2]; + t2 =3D e0(g) + Maj(g,h,a); b+=3Dt1; f=3Dt1+t2; + t1 =3D e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[i+3]; + t2 =3D e0(f) + Maj(f,g,h); a+=3Dt1; e=3Dt1+t2; + t1 =3D d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[i+4]; + t2 =3D e0(e) + Maj(e,f,g); h+=3Dt1; d=3Dt1+t2; + t1 =3D c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[i+5]; + t2 =3D e0(d) + Maj(d,e,f); g+=3Dt1; c=3Dt1+t2; + t1 =3D b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[i+6]; + t2 =3D e0(c) + Maj(c,d,e); f+=3Dt1; b=3Dt1+t2; + t1 =3D a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[i+7]; + t2 =3D e0(b) + Maj(b,c,d); e+=3Dt1; a=3Dt1+t2; + } + =20 + state[0] +=3D a; state[1] +=3D b; state[2] +=3D c; state[3] +=3D d; =20 + state[4] +=3D e; state[5] +=3D f; state[6] +=3D g; state[7] +=3D h; =20 + + /* erase our data */ + a =3D b =3D c =3D d =3D e =3D f =3D g =3D h =3D t1 =3D t2 =3D 0; + memset(W, 0, 80 * sizeof(u64)); +} + +static void +sha512_init(void *ctx) +{ + struct sha512_ctx *sctx =3D ctx; + sctx->state[0] =3D H0; + sctx->state[1] =3D H1; + sctx->state[2] =3D H2; + sctx->state[3] =3D H3; + sctx->state[4] =3D H4; + sctx->state[5] =3D H5; + sctx->state[6] =3D H6; + sctx->state[7] =3D H7; + sctx->count[0] =3D sctx->count[1] =3D sctx->count[2] =3D sctx->count[3] = =3D 0; + memset(sctx->buf, 0, sizeof(sctx->buf)); +} + +static void +sha384_init(void *ctx) +{ + struct sha512_ctx *sctx =3D ctx; + sctx->state[0] =3D HP0; + sctx->state[1] =3D HP1; + sctx->state[2] =3D HP2; + sctx->state[3] =3D HP3; + sctx->state[4] =3D HP4; + sctx->state[5] =3D HP5; + sctx->state[6] =3D HP6; + sctx->state[7] =3D HP7; + sctx->count[0] =3D sctx->count[1] =3D sctx->count[2] =3D sctx->cou= nt[3] =3D 0; + memset(sctx->buf, 0, sizeof(sctx->buf)); +} + +static void +sha512_update(void *ctx, const u8 *data, unsigned int len) +{ + struct sha512_ctx *sctx =3D ctx; + + unsigned int i, index, part_len; + + /* Compute number of bytes mod 128 */ + index =3D (unsigned int)((sctx->count[0] >> 3) & 0x7F); +=09 + /* Update number of bits */ + if ((sctx->count[0] +=3D (len << 3)) < (len << 3)) { + if ((sctx->count[1] +=3D 1) < 1) + if ((sctx->count[2] +=3D 1) < 1) + sctx->count[3]++; + sctx->count[1] +=3D (len >> 29); + } +=09 + part_len =3D 128 - index; +=09 + /* Transform as many times as possible. */ + if (len >=3D part_len) { + memcpy(&sctx->buf[index], data, part_len); + sha512_transform(sctx->state, sctx->buf); + + for (i =3D part_len; i + 127 < len; i+=3D128) + sha512_transform(sctx->state, &data[i]); + + index =3D 0; + } else { + i =3D 0; + } + + /* Buffer remaining input */ + memcpy(&sctx->buf[index], &data[i], len - i); +} + +static void +sha512_final(void *ctx, u8 *hash) +{ + struct sha512_ctx *sctx =3D ctx; +=09 + const static u8 padding[128] =3D { 0x80, }; + + u32 t; + u64 t2; + u8 bits[128]; + unsigned int index, pad_len; + int i, j; + + index =3D pad_len =3D t =3D i =3D j =3D 0; + t2 =3D 0; + + /* Save number of bits */ + t =3D sctx->count[0]; + bits[15] =3D t; t>>=3D8; + bits[14] =3D t; t>>=3D8; + bits[13] =3D t; t>>=3D8; + bits[12] =3D t;=20 + t =3D sctx->count[1]; + bits[11] =3D t; t>>=3D8; + bits[10] =3D t; t>>=3D8; + bits[9 ] =3D t; t>>=3D8; + bits[8 ] =3D t;=20 + t =3D sctx->count[2]; + bits[7 ] =3D t; t>>=3D8; + bits[6 ] =3D t; t>>=3D8; + bits[5 ] =3D t; t>>=3D8; + bits[4 ] =3D t;=20 + t =3D sctx->count[3]; + bits[3 ] =3D t; t>>=3D8; + bits[2 ] =3D t; t>>=3D8; + bits[1 ] =3D t; t>>=3D8; + bits[0 ] =3D t;=20 + + /* Pad out to 112 mod 128. */ + index =3D (sctx->count[0] >> 3) & 0x7f; + pad_len =3D (index < 112) ? (112 - index) : ((128+112) - index); + sha512_update(sctx, padding, pad_len); + + /* Append length (before padding) */ + sha512_update(sctx, bits, 16); + + /* Store state in digest */ + for (i =3D j =3D 0; i < 8; i++, j +=3D 8) { + t2 =3D sctx->state[i]; + hash[j+7] =3D (char)t2 & 0xff; t2>>=3D8; + hash[j+6] =3D (char)t2 & 0xff; t2>>=3D8; + hash[j+5] =3D (char)t2 & 0xff; t2>>=3D8; + hash[j+4] =3D (char)t2 & 0xff; t2>>=3D8; + hash[j+3] =3D (char)t2 & 0xff; t2>>=3D8; + hash[j+2] =3D (char)t2 & 0xff; t2>>=3D8; + hash[j+1] =3D (char)t2 & 0xff; t2>>=3D8; + hash[j ] =3D (char)t2 & 0xff; + } +=09 + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(struct sha512_ctx)); +} + +static void sha384_final(void *ctx, u8 *hash) +{ + struct sha512_ctx *sctx =3D ctx; + u8 D[64]; + + sha512_final(sctx, D); + + memcpy(hash, D, 48); + memset(D, 0, 64); +} + +static struct crypto_alg sha512 =3D { + .cra_name =3D "sha512", + .cra_flags =3D CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize =3D SHA512_HMAC_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct sha512_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(sha512.cra_list), + .cra_u =3D { .digest =3D { + .dia_digestsize =3D SHA512_DIGEST_SIZE, + .dia_init =3D sha512_init, + .dia_update =3D sha512_update, + .dia_final =3D sha512_final } + } +}; + +static struct crypto_alg sha384 =3D { + .cra_name =3D "sha384", + .cra_flags =3D CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize =3D SHA384_HMAC_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct sha512_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(sha384.cra_list), + .cra_u =3D { .digest =3D { + .dia_digestsize =3D SHA384_DIGEST_SIZE, + .dia_init =3D sha384_init, + .dia_update =3D sha512_update, + .dia_final =3D sha384_final } + } +}; + +static int __init init(void) +{ + int ret =3D 0; + + if ((ret =3D crypto_register_alg(&sha384)) < 0) + goto out; + if ((ret =3D crypto_register_alg(&sha512)) < 0) + crypto_unregister_alg(&sha384); +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&sha384); + crypto_unregister_alg(&sha512); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms"); diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/tcrypt.c Thu May 8 10:41:38 2003 @@ -0,0 +1,2418 @@ +/*=20 + * Quick & dirty crypto testing module. + * + * This will only exist until we have a better testing mechanism + * (e.g. a char device). + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 Jean-Francois Dive + *=20 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tcrypt.h" + +/* + * Need to kmalloc() memory for testing kmap(). + */ +#define TVMEMSIZE 4096 +#define XBUFSIZE 32768 + +/* + * Indexes into the xbuf to simulate cross-page access. + */ +#define IDX1 37 +#define IDX2 32400 +#define IDX3 1 +#define IDX4 8193 +#define IDX5 22222 +#define IDX6 17101 +#define IDX7 27333 +#define IDX8 3000 + +static int mode =3D 0; +static char *xbuf; +static char *tvmem; + +static char *check[] =3D { + "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", + "twofish", "serpent", "sha384", "sha512", "md4", "aes", "deflate", + NULL +}; + +static void +hexdump(unsigned char *buf, unsigned int len) +{ + while (len--) + printk("%02x", *buf++); + + printk("\n"); +} + +static void +test_md5(void) +{ + char *p; + unsigned int i; + struct scatterlist sg[2]; + char result[128]; + struct crypto_tfm *tfm; + struct md5_testvec *md5_tv; + unsigned int tsize; + + printk("\ntesting md5\n"); + + tsize =3D sizeof (md5_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, md5_tv_template, tsize); + md5_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("md5", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for md5\n"); + return; + } + + for (i =3D 0; i < MD5_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D md5_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(md5_tv[i].plaintext); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, sg, 1); + crypto_digest_final(tfm, result); + + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, md5_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + printk("\ntesting md5 across pages\n"); + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + memcpy(&xbuf[IDX1], "abcdefghijklm", 13); + memcpy(&xbuf[IDX2], "nopqrstuvwxyz", 13); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 13; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 13; + + memset(result, 0, sizeof (result)); + crypto_digest_digest(tfm, sg, 2, result); + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + + printk("%s\n", + memcmp(result, md5_tv[4].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); + crypto_free_tfm(tfm); +} + +#ifdef CONFIG_CRYPTO_HMAC +static void +test_hmac_md5(void) +{ + char *p; + unsigned int i, klen; + struct scatterlist sg[2]; + char result[128]; + struct crypto_tfm *tfm; + struct hmac_md5_testvec *hmac_md5_tv; + unsigned int tsize; + + tfm =3D crypto_alloc_tfm("md5", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for md5\n"); + return; + } + + printk("\ntesting hmac_md5\n"); +=09 + tsize =3D sizeof (hmac_md5_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + + memcpy(tvmem, hmac_md5_tv_template, tsize); + hmac_md5_tv =3D (void *) tvmem; + + for (i =3D 0; i < HMAC_MD5_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D hmac_md5_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(hmac_md5_tv[i].plaintext); + + klen =3D strlen(hmac_md5_tv[i].key); + crypto_hmac(tfm, hmac_md5_tv[i].key, &klen, sg, 1, result); + + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, hmac_md5_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + printk("\ntesting hmac_md5 across pages\n"); + + memset(xbuf, 0, sizeof (xbuf)); + + memcpy(&xbuf[IDX1], "what do ya want ", 16); + memcpy(&xbuf[IDX2], "for nothing?", 12); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 16; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 12; + + memset(result, 0, sizeof (result)); + klen =3D strlen(hmac_md5_tv[7].key); + crypto_hmac(tfm, hmac_md5_tv[7].key, &klen, sg, 2, result); + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + + printk("%s\n", + memcmp(result, hmac_md5_tv[7].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); +out: + crypto_free_tfm(tfm); +} + +static void +test_hmac_sha1(void) +{ + char *p; + unsigned int i, klen; + struct crypto_tfm *tfm; + struct hmac_sha1_testvec *hmac_sha1_tv; + struct scatterlist sg[2]; + unsigned int tsize; + char result[SHA1_DIGEST_SIZE]; + + tfm =3D crypto_alloc_tfm("sha1", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for sha1\n"); + return; + } + + printk("\ntesting hmac_sha1\n"); + + tsize =3D sizeof (hmac_sha1_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + + memcpy(tvmem, hmac_sha1_tv_template, tsize); + hmac_sha1_tv =3D (void *) tvmem; + + for (i =3D 0; i < HMAC_SHA1_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D hmac_sha1_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(hmac_sha1_tv[i].plaintext); + + klen =3D strlen(hmac_sha1_tv[i].key); + =09 + crypto_hmac(tfm, hmac_sha1_tv[i].key, &klen, sg, 1, result); + + hexdump(result, sizeof (result)); + printk("%s\n", + memcmp(result, hmac_sha1_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + printk("\ntesting hmac_sha1 across pages\n"); + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + memcpy(&xbuf[IDX1], "what do ya want ", 16); + memcpy(&xbuf[IDX2], "for nothing?", 12); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 16; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 12; + + memset(result, 0, sizeof (result)); + klen =3D strlen(hmac_sha1_tv[7].key); + crypto_hmac(tfm, hmac_sha1_tv[7].key, &klen, sg, 2, result); + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + + printk("%s\n", + memcmp(result, hmac_sha1_tv[7].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); +out: + crypto_free_tfm(tfm); +} + +static void +test_hmac_sha256(void) +{ + char *p; + unsigned int i, klen; + struct crypto_tfm *tfm; + struct hmac_sha256_testvec *hmac_sha256_tv; + struct scatterlist sg[2]; + unsigned int tsize; + char result[SHA256_DIGEST_SIZE]; + + tfm =3D crypto_alloc_tfm("sha256", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for sha256\n"); + return; + } + + printk("\ntesting hmac_sha256\n"); + + tsize =3D sizeof (hmac_sha256_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + + memcpy(tvmem, hmac_sha256_tv_template, tsize); + hmac_sha256_tv =3D (void *) tvmem; + + for (i =3D 0; i < HMAC_SHA256_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D hmac_sha256_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(hmac_sha256_tv[i].plaintext); + + klen =3D strlen(hmac_sha256_tv[i].key); +=09 + hexdump(hmac_sha256_tv[i].key, strlen(hmac_sha256_tv[i].key)); + crypto_hmac(tfm, hmac_sha256_tv[i].key, &klen, sg, 1, result); + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, hmac_sha256_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); + } + +out: + crypto_free_tfm(tfm); +} + +#endif /* CONFIG_CRYPTO_HMAC */ + +static void +test_md4(void) +{ + char *p; + unsigned int i; + struct scatterlist sg[1]; + char result[128]; + struct crypto_tfm *tfm; + struct md4_testvec *md4_tv; + unsigned int tsize; + + printk("\ntesting md4\n"); + + tsize =3D sizeof (md4_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, md4_tv_template, tsize); + md4_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("md4", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for md4\n"); + return; + } + + for (i =3D 0; i < MD4_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D md4_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(md4_tv[i].plaintext); + + crypto_digest_digest(tfm, sg, 1, result); + + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, md4_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + crypto_free_tfm(tfm); +} + +static void +test_sha1(void) +{ + char *p; + unsigned int i; + struct crypto_tfm *tfm; + struct sha1_testvec *sha1_tv; + struct scatterlist sg[2]; + unsigned int tsize; + char result[SHA1_DIGEST_SIZE]; + + printk("\ntesting sha1\n"); + + tsize =3D sizeof (sha1_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, sha1_tv_template, tsize); + sha1_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("sha1", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for sha1\n"); + return; + } + + for (i =3D 0; i < SHA1_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D sha1_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(sha1_tv[i].plaintext); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, sg, 1); + crypto_digest_final(tfm, result); + + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, sha1_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + printk("\ntesting sha1 across pages\n"); + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + memcpy(&xbuf[IDX1], "abcdbcdecdefdefgefghfghighij", 28); + memcpy(&xbuf[IDX2], "hijkijkljklmklmnlmnomnopnopq", 28); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 28; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 28; + + memset(result, 0, sizeof (result)); + crypto_digest_digest(tfm, sg, 2, result); + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, sha1_tv[1].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); + crypto_free_tfm(tfm); +} + +static void +test_sha256(void) +{ + char *p; + unsigned int i; + struct crypto_tfm *tfm; + struct sha256_testvec *sha256_tv; + struct scatterlist sg[2]; + unsigned int tsize; + char result[SHA256_DIGEST_SIZE]; + + printk("\ntesting sha256\n"); + + tsize =3D sizeof (sha256_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, sha256_tv_template, tsize); + sha256_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("sha256", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for sha256\n"); + return; + } + + for (i =3D 0; i < SHA256_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D sha256_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(sha256_tv[i].plaintext); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, sg, 1); + crypto_digest_final(tfm, result); + + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, sha256_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + printk("\ntesting sha256 across pages\n"); + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + memcpy(&xbuf[IDX1], "abcdbcdecdefdefgefghfghighij", 28); + memcpy(&xbuf[IDX2], "hijkijkljklmklmnlmnomnopnopq", 28); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 28; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 28; + + memset(result, 0, sizeof (result)); + crypto_digest_digest(tfm, sg, 2, result); + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, sha256_tv[1].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); + =20 + crypto_free_tfm(tfm); +} + +static void +test_sha384(void) +{ + char *p; + unsigned int i; + struct crypto_tfm *tfm; + struct sha384_testvec *sha384_tv; + struct scatterlist sg[2]; + unsigned int tsize; + char result[SHA384_DIGEST_SIZE]; + + printk("\ntesting sha384\n"); + + tsize =3D sizeof (sha384_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, sha384_tv_template, tsize); + sha384_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("sha384", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for sha384\n"); + return; + } + + for (i =3D 0; i < SHA384_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D sha384_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(sha384_tv[i].plaintext); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, sg, 1); + crypto_digest_final(tfm, result); + + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, sha384_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + crypto_free_tfm(tfm); +} + +static void +test_sha512(void) +{ + char *p; + unsigned int i; + struct crypto_tfm *tfm; + struct sha512_testvec *sha512_tv; + struct scatterlist sg[2]; + unsigned int tsize; + char result[SHA512_DIGEST_SIZE]; + + printk("\ntesting sha512\n"); + + tsize =3D sizeof (sha512_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, sha512_tv_template, tsize); + sha512_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("sha512", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for sha512\n"); + return; + } + + for (i =3D 0; i < SHA512_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p =3D sha512_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D strlen(sha512_tv[i].plaintext); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, sg, 1); + crypto_digest_final(tfm, result); + + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + printk("%s\n", + memcmp(result, sha512_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + crypto_free_tfm(tfm); +} + +void +test_des(void) +{ + unsigned int ret, i, len; + unsigned int tsize; + char *p, *q; + struct crypto_tfm *tfm; + char *key; + char res[8]; + struct des_tv *des_tv; + struct scatterlist sg[8]; + + printk("\ntesting des encryption\n"); + + tsize =3D sizeof (des_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, des_enc_tv_template, tsize); + des_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("des", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for des (default ecb)\n"); + return; + } + + for (i =3D 0; i < DES_ENC_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + + key =3D des_tv[i].key; + tfm->crt_flags |=3D CRYPTO_TFM_REQ_WEAK_KEY; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!des_tv[i].fail) + goto out; + } + + len =3D des_tv[i].len; + + p =3D des_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D len; + ret =3D crypto_cipher_encrypt(tfm, sg, sg, len); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, len); + + printk("%s\n", + memcmp(q, des_tv[i].result, len) ? "fail" : "pass"); + + } + + printk("\ntesting des ecb encryption across pages\n"); + + i =3D 5; + key =3D des_tv[i].key; + tfm->crt_flags =3D 0; + + hexdump(key, 8); + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + memcpy(&xbuf[IDX1], des_tv[i].plaintext, 8); + memcpy(&xbuf[IDX2], des_tv[i].plaintext + 8, 8); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 8; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 8; + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, 16); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 8); + printk("%s\n", memcmp(q, des_tv[i].result, 8) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 8); + printk("%s\n", memcmp(q, des_tv[i].result + 8, 8) ? "fail" : "pass"); + + printk("\ntesting des ecb encryption chunking scenario A\n"); + + /* + * Scenario A: + *=20 + * F1 F2 F3 + * [8 + 6] [2 + 8] [8] + * ^^^^^^ ^ + * a b c + * + * Chunking should begin at a, then end with b, and + * continue encrypting at an offset of 2 until c. + * + */ + i =3D 7; + + key =3D des_tv[i].key; + tfm->crt_flags =3D 0; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + /* Frag 1: 8 + 6 */ + memcpy(&xbuf[IDX3], des_tv[i].plaintext, 14); + + /* Frag 2: 2 + 8 */ + memcpy(&xbuf[IDX4], des_tv[i].plaintext + 14, 10); + + /* Frag 3: 8 */ + memcpy(&xbuf[IDX5], des_tv[i].plaintext + 24, 8); + + p =3D &xbuf[IDX3]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 14; + + p =3D &xbuf[IDX4]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 10; + + p =3D &xbuf[IDX5]; + sg[2].page =3D virt_to_page(p); + sg[2].offset =3D ((long) p & ~PAGE_MASK); + sg[2].length =3D 8; + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, 32); + + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 14); + printk("%s\n", memcmp(q, des_tv[i].result, 14) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 10); + printk("%s\n", memcmp(q, des_tv[i].result + 14, 10) ? "fail" : "pass"); + + printk("page 3\n"); + q =3D kmap(sg[2].page) + sg[2].offset; + hexdump(q, 8); + printk("%s\n", memcmp(q, des_tv[i].result + 24, 8) ? "fail" : "pass"); + + printk("\ntesting des ecb encryption chunking scenario B\n"); + + /* + * Scenario B: + *=20 + * F1 F2 F3 F4 + * [2] [1] [3] [2 + 8 + 8] + */ + i =3D 7; + + key =3D des_tv[i].key; + tfm->crt_flags =3D 0; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + /* Frag 1: 2 */ + memcpy(&xbuf[IDX3], des_tv[i].plaintext, 2); + + /* Frag 2: 1 */ + memcpy(&xbuf[IDX4], des_tv[i].plaintext + 2, 1); + + /* Frag 3: 3 */ + memcpy(&xbuf[IDX5], des_tv[i].plaintext + 3, 3); + + /* Frag 4: 2 + 8 + 8 */ + memcpy(&xbuf[IDX6], des_tv[i].plaintext + 6, 18); + + p =3D &xbuf[IDX3]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 2; + + p =3D &xbuf[IDX4]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 1; + + p =3D &xbuf[IDX5]; + sg[2].page =3D virt_to_page(p); + sg[2].offset =3D ((long) p & ~PAGE_MASK); + sg[2].length =3D 3; + + p =3D &xbuf[IDX6]; + sg[3].page =3D virt_to_page(p); + sg[3].offset =3D ((long) p & ~PAGE_MASK); + sg[3].length =3D 18; + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, 24); + + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 2); + printk("%s\n", memcmp(q, des_tv[i].result, 2) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 1); + printk("%s\n", memcmp(q, des_tv[i].result + 2, 1) ? "fail" : "pass"); + + printk("page 3\n"); + q =3D kmap(sg[2].page) + sg[2].offset; + hexdump(q, 3); + printk("%s\n", memcmp(q, des_tv[i].result + 3, 3) ? "fail" : "pass"); + + printk("page 4\n"); + q =3D kmap(sg[3].page) + sg[3].offset; + hexdump(q, 18); + printk("%s\n", memcmp(q, des_tv[i].result + 6, 18) ? "fail" : "pass"); + + printk("\ntesting des ecb encryption chunking scenario C\n"); + + /* + * Scenario B: + *=20 + * F1 F2 F3 F4 F5 + * [2] [2] [2] [2] [8] + */ + i =3D 7; + + key =3D des_tv[i].key; + tfm->crt_flags =3D 0; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + /* Frag 1: 2 */ + memcpy(&xbuf[IDX3], des_tv[i].plaintext, 2); + + /* Frag 2: 2 */ + memcpy(&xbuf[IDX4], des_tv[i].plaintext + 2, 2); + + /* Frag 3: 2 */ + memcpy(&xbuf[IDX5], des_tv[i].plaintext + 4, 2); + + /* Frag 4: 2 */ + memcpy(&xbuf[IDX6], des_tv[i].plaintext + 6, 2); + + /* Frag 5: 8 */ + memcpy(&xbuf[IDX7], des_tv[i].plaintext + 8, 8); + + p =3D &xbuf[IDX3]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 2; + + p =3D &xbuf[IDX4]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 2; + + p =3D &xbuf[IDX5]; + sg[2].page =3D virt_to_page(p); + sg[2].offset =3D ((long) p & ~PAGE_MASK); + sg[2].length =3D 2; + + p =3D &xbuf[IDX6]; + sg[3].page =3D virt_to_page(p); + sg[3].offset =3D ((long) p & ~PAGE_MASK); + sg[3].length =3D 2; + + p =3D &xbuf[IDX7]; + sg[4].page =3D virt_to_page(p); + sg[4].offset =3D ((long) p & ~PAGE_MASK); + sg[4].length =3D 8; + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, 16); + + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 2); + printk("%s\n", memcmp(q, des_tv[i].result, 2) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 2); + printk("%s\n", memcmp(q, des_tv[i].result + 2, 2) ? "fail" : "pass"); + + printk("page 3\n"); + q =3D kmap(sg[2].page) + sg[2].offset; + hexdump(q, 2); + printk("%s\n", memcmp(q, des_tv[i].result + 4, 2) ? "fail" : "pass"); + + printk("page 4\n"); + q =3D kmap(sg[3].page) + sg[3].offset; + hexdump(q, 2); + printk("%s\n", memcmp(q, des_tv[i].result + 6, 2) ? "fail" : "pass"); + + printk("page 5\n"); + q =3D kmap(sg[4].page) + sg[4].offset; + hexdump(q, 8); + printk("%s\n", memcmp(q, des_tv[i].result + 8, 8) ? "fail" : "pass"); + + printk("\ntesting des ecb encryption chunking scenario D\n"); + + /* + * Scenario D, torture test, one byte per frag. + */ + i =3D 7; + key =3D des_tv[i].key; + tfm->crt_flags =3D 0; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + xbuf[IDX1] =3D des_tv[i].plaintext[0]; + xbuf[IDX2] =3D des_tv[i].plaintext[1]; + xbuf[IDX3] =3D des_tv[i].plaintext[2]; + xbuf[IDX4] =3D des_tv[i].plaintext[3]; + xbuf[IDX5] =3D des_tv[i].plaintext[4]; + xbuf[IDX6] =3D des_tv[i].plaintext[5]; + xbuf[IDX7] =3D des_tv[i].plaintext[6]; + xbuf[IDX8] =3D des_tv[i].plaintext[7]; + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 1; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 1; + + p =3D &xbuf[IDX3]; + sg[2].page =3D virt_to_page(p); + sg[2].offset =3D ((long) p & ~PAGE_MASK); + sg[2].length =3D 1; + + p =3D &xbuf[IDX4]; + sg[3].page =3D virt_to_page(p); + sg[3].offset =3D ((long) p & ~PAGE_MASK); + sg[3].length =3D 1; + + p =3D &xbuf[IDX5]; + sg[4].page =3D virt_to_page(p); + sg[4].offset =3D ((long) p & ~PAGE_MASK); + sg[4].length =3D 1; + + p =3D &xbuf[IDX6]; + sg[5].page =3D virt_to_page(p); + sg[5].offset =3D ((long) p & ~PAGE_MASK); + sg[5].length =3D 1; + + p =3D &xbuf[IDX7]; + sg[6].page =3D virt_to_page(p); + sg[6].offset =3D ((long) p & ~PAGE_MASK); + sg[6].length =3D 1; + + p =3D &xbuf[IDX8]; + sg[7].page =3D virt_to_page(p); + sg[7].offset =3D ((long) p & ~PAGE_MASK); + sg[7].length =3D 1; + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, 8); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + for (i =3D 0; i < 8; i++) + res[i] =3D *(char *) (kmap(sg[i].page) + sg[i].offset); + + hexdump(res, 8); + printk("%s\n", memcmp(res, des_tv[7].result, 8) ? "fail" : "pass"); + + printk("\ntesting des decryption\n"); + + tsize =3D sizeof (des_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + memcpy(tvmem, des_dec_tv_template, tsize); + des_tv =3D (void *) tvmem; + + for (i =3D 0; i < DES_DEC_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + + key =3D des_tv[i].key; + + tfm->crt_flags =3D 0; + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + len =3D des_tv[i].len; + + p =3D des_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D len; + + ret =3D crypto_cipher_decrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("des_decrypt() failed flags=3D%x\n", + tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, len); + + printk("%s\n", + memcmp(q, des_tv[i].result, len) ? "fail" : "pass"); + + } + + printk("\ntesting des ecb decryption across pages\n"); + + i =3D 6; + + key =3D des_tv[i].key; + tfm->crt_flags =3D 0; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + memcpy(&xbuf[IDX1], des_tv[i].plaintext, 8); + memcpy(&xbuf[IDX2], des_tv[i].plaintext + 8, 8); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 8; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 8; + + ret =3D crypto_cipher_decrypt(tfm, sg, sg, 16); + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 8); + printk("%s\n", memcmp(q, des_tv[i].result, 8) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 8); + printk("%s\n", memcmp(q, des_tv[i].result + 8, 8) ? "fail" : "pass"); + + /* + * Scenario E: + *=20 + * F1 F2 F3 + * [3] [5 + 7] [1] + * + */ + printk("\ntesting des ecb decryption chunking scenario E\n"); + i =3D 2; + + key =3D des_tv[i].key; + tfm->crt_flags =3D 0; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + memcpy(&xbuf[IDX1], des_tv[i].plaintext, 3); + memcpy(&xbuf[IDX2], des_tv[i].plaintext + 3, 12); + memcpy(&xbuf[IDX3], des_tv[i].plaintext + 15, 1); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 3; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 12; + + p =3D &xbuf[IDX3]; + sg[2].page =3D virt_to_page(p); + sg[2].offset =3D ((long) p & ~PAGE_MASK); + sg[2].length =3D 1; + + ret =3D crypto_cipher_decrypt(tfm, sg, sg, 16); + + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 3); + printk("%s\n", memcmp(q, des_tv[i].result, 3) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 12); + printk("%s\n", memcmp(q, des_tv[i].result + 3, 12) ? "fail" : "pass"); + + printk("page 3\n"); + q =3D kmap(sg[2].page) + sg[2].offset; + hexdump(q, 1); + printk("%s\n", memcmp(q, des_tv[i].result + 15, 1) ? "fail" : "pass"); + + crypto_free_tfm(tfm); + + tfm =3D crypto_alloc_tfm("des", CRYPTO_TFM_MODE_CBC); + if (tfm =3D=3D NULL) { + printk("failed to load transform for des cbc\n"); + return; + } + + printk("\ntesting des cbc encryption\n"); + + tsize =3D sizeof (des_cbc_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + memcpy(tvmem, des_cbc_enc_tv_template, tsize); + des_tv =3D (void *) tvmem; + + crypto_cipher_set_iv(tfm, des_tv[i].iv, crypto_tfm_alg_ivsize(tfm)); + crypto_cipher_get_iv(tfm, res, crypto_tfm_alg_ivsize(tfm)); +=09 + if (memcmp(res, des_tv[i].iv, sizeof(res))) { + printk("crypto_cipher_[set|get]_iv() failed\n"); + goto out; + } +=09 + for (i =3D 0; i < DES_CBC_ENC_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + + key =3D des_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + len =3D des_tv[i].len; + p =3D des_tv[i].plaintext; + + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D len; + + crypto_cipher_set_iv(tfm, des_tv[i].iv, + crypto_tfm_alg_ivsize(tfm)); + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, len); + if (ret) { + printk("des_cbc_encrypt() failed flags=3D%x\n", + tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, len); + + printk("%s\n", + memcmp(q, des_tv[i].result, len) ? "fail" : "pass"); + } + + crypto_free_tfm(tfm); + + /* + * Scenario F: + *=20 + * F1 F2 =20 + * [8 + 5] [3 + 8] + * + */ + printk("\ntesting des cbc encryption chunking scenario F\n"); + i =3D 4; + + tfm =3D crypto_alloc_tfm("des", CRYPTO_TFM_MODE_CBC); + if (tfm =3D=3D NULL) { + printk("failed to load transform for CRYPTO_ALG_DES_CCB\n"); + return; + } + + tfm->crt_flags =3D 0; + key =3D des_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + memcpy(&xbuf[IDX1], des_tv[i].plaintext, 13); + memcpy(&xbuf[IDX2], des_tv[i].plaintext + 13, 11); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 13; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 11; + + crypto_cipher_set_iv(tfm, des_tv[i].iv, crypto_tfm_alg_ivsize(tfm)); + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, 24); + if (ret) { + printk("des_cbc_decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 13); + printk("%s\n", memcmp(q, des_tv[i].result, 13) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 11); + printk("%s\n", memcmp(q, des_tv[i].result + 13, 11) ? "fail" : "pass"); + + tsize =3D sizeof (des_cbc_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + memcpy(tvmem, des_cbc_dec_tv_template, tsize); + des_tv =3D (void *) tvmem; + + printk("\ntesting des cbc decryption\n"); + + for (i =3D 0; i < DES_CBC_DEC_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + + tfm->crt_flags =3D 0; + key =3D des_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + len =3D des_tv[i].len; + p =3D des_tv[i].plaintext; + + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D len; + + crypto_cipher_set_iv(tfm, des_tv[i].iv, + crypto_tfm_alg_blocksize(tfm)); + + ret =3D crypto_cipher_decrypt(tfm, sg, sg, len); + if (ret) { + printk("des_cbc_decrypt() failed flags=3D%x\n", + tfm->crt_flags); + goto out; + } + + hexdump(tfm->crt_cipher.cit_iv, 8); + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, len); + + printk("%s\n", + memcmp(q, des_tv[i].result, len) ? "fail" : "pass"); + } + + /* + * Scenario G: + *=20 + * F1 F2 =20 + * [4] [4] + * + */ + printk("\ntesting des cbc decryption chunking scenario G\n"); + i =3D 3; + + tfm->crt_flags =3D 0; + key =3D des_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, 8); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + memcpy(&xbuf[IDX1], des_tv[i].plaintext, 4); + memcpy(&xbuf[IDX2], des_tv[i].plaintext + 4, 4); + + p =3D &xbuf[IDX1]; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D 4; + + p =3D &xbuf[IDX2]; + sg[1].page =3D virt_to_page(p); + sg[1].offset =3D ((long) p & ~PAGE_MASK); + sg[1].length =3D 4; + + crypto_cipher_set_iv(tfm, des_tv[i].iv, crypto_tfm_alg_ivsize(tfm)); + + ret =3D crypto_cipher_decrypt(tfm, sg, sg, 8); + if (ret) { + printk("des_cbc_decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + printk("page 1\n"); + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, 4); + printk("%s\n", memcmp(q, des_tv[i].result, 4) ? "fail" : "pass"); + + printk("page 2\n"); + q =3D kmap(sg[1].page) + sg[1].offset; + hexdump(q, 4); + printk("%s\n", memcmp(q, des_tv[i].result + 4, 4) ? "fail" : "pass"); + + out: + crypto_free_tfm(tfm); +} + +void +test_des3_ede(void) +{ + unsigned int ret, i, len; + unsigned int tsize; + char *p, *q; + struct crypto_tfm *tfm; + char *key; + /*char res[8]; */ + struct des_tv *des_tv; + struct scatterlist sg[8]; + + printk("\ntesting des3 ede encryption\n"); + + tsize =3D sizeof (des3_ede_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, des3_ede_enc_tv_template, tsize); + des_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("des3_ede", CRYPTO_TFM_MODE_ECB); + if (tfm =3D=3D NULL) { + printk("failed to load transform for 3des ecb\n"); + return; + } + + for (i =3D 0; i < DES3_EDE_ENC_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + + key =3D des_tv[i].key; + ret =3D crypto_cipher_setkey(tfm, key, 24); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!des_tv[i].fail) + goto out; + } + + len =3D des_tv[i].len; + + p =3D des_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D len; + ret =3D crypto_cipher_encrypt(tfm, sg, sg, len); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, len); + + printk("%s\n", + memcmp(q, des_tv[i].result, len) ? "fail" : "pass"); + } + + printk("\ntesting des3 ede decryption\n"); + + tsize =3D sizeof (des3_ede_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, des3_ede_dec_tv_template, tsize); + des_tv =3D (void *) tvmem; + + for (i =3D 0; i < DES3_EDE_DEC_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + + key =3D des_tv[i].key; + ret =3D crypto_cipher_setkey(tfm, key, 24); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!des_tv[i].fail) + goto out; + } + + len =3D des_tv[i].len; + + p =3D des_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D len; + ret =3D crypto_cipher_decrypt(tfm, sg, sg, len); + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, len); + + printk("%s\n", + memcmp(q, des_tv[i].result, len) ? "fail" : "pass"); + } + + out: + crypto_free_tfm(tfm); +} + +void +test_blowfish(void) +{ + unsigned int ret, i; + unsigned int tsize; + char *p, *q; + struct crypto_tfm *tfm; + char *key; + struct bf_tv *bf_tv; + struct scatterlist sg[1]; + + printk("\ntesting blowfish encryption\n"); + + tsize =3D sizeof (bf_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, bf_enc_tv_template, tsize); + bf_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("blowfish", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for blowfish (default ecb)\n"); + return; + } + + for (i =3D 0; i < BF_ENC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, bf_tv[i].keylen * 8); + key =3D bf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, bf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!bf_tv[i].fail) + goto out; + } + + p =3D bf_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D bf_tv[i].plen; + ret =3D crypto_cipher_encrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, bf_tv[i].rlen); + + printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen) ? + "fail" : "pass"); + } + + printk("\ntesting blowfish decryption\n"); + + tsize =3D sizeof (bf_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, bf_dec_tv_template, tsize); + bf_tv =3D (void *) tvmem; + + for (i =3D 0; i < BF_DEC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, bf_tv[i].keylen * 8); + key =3D bf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, bf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!bf_tv[i].fail) + goto out; + } + + p =3D bf_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D bf_tv[i].plen; + ret =3D crypto_cipher_decrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, bf_tv[i].rlen); + + printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen) ? + "fail" : "pass"); + } +=09 + crypto_free_tfm(tfm); +=09 + tfm =3D crypto_alloc_tfm("blowfish", CRYPTO_TFM_MODE_CBC); + if (tfm =3D=3D NULL) { + printk("failed to load transform for blowfish cbc\n"); + return; + } + + printk("\ntesting blowfish cbc encryption\n"); + + tsize =3D sizeof (bf_cbc_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + memcpy(tvmem, bf_cbc_enc_tv_template, tsize); + bf_tv =3D (void *) tvmem; + + for (i =3D 0; i < BF_CBC_ENC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, bf_tv[i].keylen * 8); + + key =3D bf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, bf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + p =3D bf_tv[i].plaintext; + + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D bf_tv[i].plen; + + crypto_cipher_set_iv(tfm, bf_tv[i].iv, + crypto_tfm_alg_ivsize(tfm)); + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("blowfish_cbc_encrypt() failed flags=3D%x\n", + tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, bf_tv[i].rlen); + + printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen) + ? "fail" : "pass"); + } + + printk("\ntesting blowfish cbc decryption\n"); + + tsize =3D sizeof (bf_cbc_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + memcpy(tvmem, bf_cbc_dec_tv_template, tsize); + bf_tv =3D (void *) tvmem; + + for (i =3D 0; i < BF_CBC_ENC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, bf_tv[i].keylen * 8); + key =3D bf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, bf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + p =3D bf_tv[i].plaintext; + + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D bf_tv[i].plen; + + crypto_cipher_set_iv(tfm, bf_tv[i].iv, + crypto_tfm_alg_ivsize(tfm)); + + ret =3D crypto_cipher_decrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("blowfish_cbc_decrypt() failed flags=3D%x\n", + tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, bf_tv[i].rlen); + + printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen) + ? "fail" : "pass"); + } + +out: + crypto_free_tfm(tfm); +} + + +void +test_twofish(void) +{ + unsigned int ret, i; + unsigned int tsize; + char *p, *q; + struct crypto_tfm *tfm; + char *key; + struct tf_tv *tf_tv; + struct scatterlist sg[1]; + + printk("\ntesting twofish encryption\n"); + + tsize =3D sizeof (tf_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, tf_enc_tv_template, tsize); + tf_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("twofish", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for blowfish (default ecb)\n"); + return; + } + + for (i =3D 0; i < TF_ENC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, tf_tv[i].keylen * 8); + key =3D tf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, tf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!tf_tv[i].fail) + goto out; + } + + p =3D tf_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D tf_tv[i].plen; + ret =3D crypto_cipher_encrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, tf_tv[i].rlen); + + printk("%s\n", memcmp(q, tf_tv[i].result, tf_tv[i].rlen) ? + "fail" : "pass"); + } + + printk("\ntesting twofish decryption\n"); + + tsize =3D sizeof (tf_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, tf_dec_tv_template, tsize); + tf_tv =3D (void *) tvmem; + + for (i =3D 0; i < TF_DEC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, tf_tv[i].keylen * 8); + key =3D tf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, tf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!tf_tv[i].fail) + goto out; + } + + p =3D tf_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D tf_tv[i].plen; + ret =3D crypto_cipher_decrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, tf_tv[i].rlen); + + printk("%s\n", memcmp(q, tf_tv[i].result, tf_tv[i].rlen) ? + "fail" : "pass"); + } + + crypto_free_tfm(tfm); +=09 + tfm =3D crypto_alloc_tfm("twofish", CRYPTO_TFM_MODE_CBC); + if (tfm =3D=3D NULL) { + printk("failed to load transform for twofish cbc\n"); + return; + } + + printk("\ntesting twofish cbc encryption\n"); + + tsize =3D sizeof (tf_cbc_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + memcpy(tvmem, tf_cbc_enc_tv_template, tsize); + tf_tv =3D (void *) tvmem; + + for (i =3D 0; i < TF_CBC_ENC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, tf_tv[i].keylen * 8); + + key =3D tf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, tf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + p =3D tf_tv[i].plaintext; + + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D tf_tv[i].plen; + + crypto_cipher_set_iv(tfm, tf_tv[i].iv, + crypto_tfm_alg_ivsize(tfm)); + + ret =3D crypto_cipher_encrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("blowfish_cbc_encrypt() failed flags=3D%x\n", + tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, tf_tv[i].rlen); + + printk("%s\n", memcmp(q, tf_tv[i].result, tf_tv[i].rlen) + ? "fail" : "pass"); + } + + printk("\ntesting twofish cbc decryption\n"); + + tsize =3D sizeof (tf_cbc_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + memcpy(tvmem, tf_cbc_dec_tv_template, tsize); + tf_tv =3D (void *) tvmem; + + for (i =3D 0; i < TF_CBC_DEC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, tf_tv[i].keylen * 8); + + key =3D tf_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, tf_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + p =3D tf_tv[i].plaintext; + + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D tf_tv[i].plen; + + crypto_cipher_set_iv(tfm, tf_tv[i].iv, + crypto_tfm_alg_ivsize(tfm)); + + ret =3D crypto_cipher_decrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("blowfish_cbc_decrypt() failed flags=3D%x\n", + tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, tf_tv[i].rlen); + + printk("%s\n", memcmp(q, tf_tv[i].result, tf_tv[i].rlen) + ? "fail" : "pass"); + } + +out:=09 + crypto_free_tfm(tfm); +} + +void +test_serpent(void) +{ + unsigned int ret, i, tsize; + u8 *p, *q, *key; + struct crypto_tfm *tfm; + struct serpent_tv *serp_tv; + struct scatterlist sg[1]; + + printk("\ntesting serpent encryption\n"); + + tfm =3D crypto_alloc_tfm("serpent", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for serpent (default ecb)\n"); + return; + } + + tsize =3D sizeof (serpent_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, serpent_enc_tv_template, tsize); + serp_tv =3D (void *) tvmem; + for (i =3D 0; i < SERPENT_ENC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", i + 1, serp_tv[i].keylen * 8); + key =3D serp_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, serp_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!serp_tv[i].fail) + goto out; + } + + p =3D serp_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D sizeof(serp_tv[i].plaintext); + ret =3D crypto_cipher_encrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, sizeof(serp_tv[i].result)); + + printk("%s\n", memcmp(q, serp_tv[i].result, + sizeof(serp_tv[i].result)) ? "fail" : "pass"); + } + + printk("\ntesting serpent decryption\n"); + + tsize =3D sizeof (serpent_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, serpent_dec_tv_template, tsize); + serp_tv =3D (void *) tvmem; + for (i =3D 0; i < SERPENT_DEC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", i + 1, serp_tv[i].keylen * 8); + key =3D serp_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, serp_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!serp_tv[i].fail) + goto out; + } + + p =3D serp_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D sizeof(serp_tv[i].plaintext); + ret =3D crypto_cipher_decrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, sizeof(serp_tv[i].result)); + + printk("%s\n", memcmp(q, serp_tv[i].result, + sizeof(serp_tv[i].result)) ? "fail" : "pass"); + } + +out: + crypto_free_tfm(tfm); +} + +void +test_aes(void) +{ + unsigned int ret, i; + unsigned int tsize; + char *p, *q; + struct crypto_tfm *tfm; + char *key; + struct aes_tv *aes_tv; + struct scatterlist sg[1]; + + printk("\ntesting aes encryption\n"); + + tsize =3D sizeof (aes_enc_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, aes_enc_tv_template, tsize); + aes_tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("aes", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for aes (default ecb)\n"); + return; + } + + for (i =3D 0; i < AES_ENC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, aes_tv[i].keylen * 8); + key =3D aes_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, aes_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!aes_tv[i].fail) + goto out; + } + + p =3D aes_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D aes_tv[i].plen; + ret =3D crypto_cipher_encrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("encrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, aes_tv[i].rlen); + + printk("%s\n", memcmp(q, aes_tv[i].result, aes_tv[i].rlen) ? + "fail" : "pass"); + } +=09 + printk("\ntesting aes decryption\n"); + + tsize =3D sizeof (aes_dec_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, aes_dec_tv_template, tsize); + aes_tv =3D (void *) tvmem; + + for (i =3D 0; i < AES_DEC_TEST_VECTORS; i++) { + printk("test %u (%d bit key):\n", + i + 1, aes_tv[i].keylen * 8); + key =3D aes_tv[i].key; + + ret =3D crypto_cipher_setkey(tfm, key, aes_tv[i].keylen); + if (ret) { + printk("setkey() failed flags=3D%x\n", tfm->crt_flags); + + if (!aes_tv[i].fail) + goto out; + } + + p =3D aes_tv[i].plaintext; + sg[0].page =3D virt_to_page(p); + sg[0].offset =3D ((long) p & ~PAGE_MASK); + sg[0].length =3D aes_tv[i].plen; + ret =3D crypto_cipher_decrypt(tfm, sg, sg, sg[0].length); + if (ret) { + printk("decrypt() failed flags=3D%x\n", tfm->crt_flags); + goto out; + } + + q =3D kmap(sg[0].page) + sg[0].offset; + hexdump(q, aes_tv[i].rlen); + + printk("%s\n", memcmp(q, aes_tv[i].result, aes_tv[i].rlen) ? + "fail" : "pass"); + } + +out: + crypto_free_tfm(tfm); +} + +static void +test_deflate(void) +{ + unsigned int i; + char result[COMP_BUF_SIZE]; + struct crypto_tfm *tfm; + struct comp_testvec *tv; + unsigned int tsize; + + printk("\ntesting deflate compression\n"); + + tsize =3D sizeof (deflate_comp_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, deflate_comp_tv_template, tsize); + tv =3D (void *) tvmem; + + tfm =3D crypto_alloc_tfm("deflate", 0); + if (tfm =3D=3D NULL) { + printk("failed to load transform for deflate\n"); + return; + } + + for (i =3D 0; i < DEFLATE_COMP_TEST_VECTORS; i++) { + int ilen, ret, dlen =3D COMP_BUF_SIZE; + =09 + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + ilen =3D tv[i].inlen; + ret =3D crypto_comp_compress(tfm, tv[i].input, + ilen, result, &dlen); + if (ret) { + printk("fail: ret=3D%d\n", ret); + continue; + } + hexdump(result, dlen); + printk("%s (ratio %d:%d)\n", + memcmp(result, tv[i].output, dlen) ? "fail" : "pass", + ilen, dlen); + } + + printk("\ntesting deflate decompression\n"); + + tsize =3D sizeof (deflate_decomp_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + + memcpy(tvmem, deflate_decomp_tv_template, tsize); + tv =3D (void *) tvmem; + + for (i =3D 0; i < DEFLATE_DECOMP_TEST_VECTORS; i++) { + int ilen, ret, dlen =3D COMP_BUF_SIZE; + =09 + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + ilen =3D tv[i].inlen; + ret =3D crypto_comp_decompress(tfm, tv[i].input, + ilen, result, &dlen); + if (ret) { + printk("fail: ret=3D%d\n", ret); + continue; + } + hexdump(result, dlen); + printk("%s (ratio %d:%d)\n", + memcmp(result, tv[i].output, dlen) ? "fail" : "pass", + ilen, dlen); + } +out: + crypto_free_tfm(tfm); +} + +static void +test_available(void) +{ + char **name =3D check; +=09 + while (*name) { + printk("alg %s ", *name); + printk((crypto_alg_available(*name, 0)) ? + "found\n" : "not found\n"); + name++; + }=09 +} + +static void +do_test(void) +{ + switch (mode) { + + case 0: + test_md5(); + test_sha1(); + test_des(); + test_des3_ede(); + test_md4(); + test_sha256(); + test_blowfish(); + test_twofish(); + test_serpent(); + test_aes(); + test_sha384(); + test_sha512(); + test_deflate(); +#ifdef CONFIG_CRYPTO_HMAC + test_hmac_md5(); + test_hmac_sha1(); + test_hmac_sha256(); +#endif =09 + break; + + case 1: + test_md5(); + break; + + case 2: + test_sha1(); + break; + + case 3: + test_des(); + break; + + case 4: + test_des3_ede(); + break; + + case 5: + test_md4(); + break; + =09 + case 6: + test_sha256(); + break; +=09 + case 7: + test_blowfish(); + break; + + case 8: + test_twofish(); + break; + + case 9: + test_serpent(); + break; + + case 10: + test_aes(); + break; + + case 11: + test_sha384(); + break; + =09 + case 12: + test_sha512(); + break; + + case 13: + test_deflate(); + break; + +#ifdef CONFIG_CRYPTO_HMAC + case 100: + test_hmac_md5(); + break; + =09 + case 101: + test_hmac_sha1(); + break; +=09 + case 102: + test_hmac_sha256(); + break; + +#endif + + case 1000: + test_available(); + break; + =09 + default: + /* useful for debugging */ + printk("not testing anything\n"); + break; + } +} + +static int __init +init(void) +{ + tvmem =3D kmalloc(TVMEMSIZE, GFP_KERNEL); + if (tvmem =3D=3D NULL) + return -ENOMEM; + + xbuf =3D kmalloc(XBUFSIZE, GFP_KERNEL); + if (xbuf =3D=3D NULL) { + kfree(tvmem); + return -ENOMEM; + } + + do_test(); + + kfree(xbuf); + kfree(tvmem); + return 0; +} + +module_init(init); + +MODULE_PARM(mode, "i"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Quick & dirty crypto testing module"); +MODULE_AUTHOR("James Morris "); diff -Nru a/crypto/tcrypt.h b/crypto/tcrypt.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/tcrypt.h Thu May 8 10:41:38 2003 @@ -0,0 +1,1785 @@ +/*=20 + * Quick & dirty crypto testing module. + * + * This will only exist until we have a better testing mechanism + * (e.g. a char device). + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 Jean-Francois Dive + *=20 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#ifndef _CRYPTO_TCRYPT_H +#define _CRYPTO_TCRYPT_H + +#define MD5_DIGEST_SIZE 16 +#define MD4_DIGEST_SIZE 16 +#define SHA1_DIGEST_SIZE 20 +#define SHA256_DIGEST_SIZE 32 +#define SHA384_DIGEST_SIZE 48 +#define SHA512_DIGEST_SIZE 64 + +/* + * MD4 test vectors from RFC1320 + */ +#define MD4_TEST_VECTORS 7 + +struct md4_testvec { + char plaintext[128]; + char digest[MD4_DIGEST_SIZE]; +} md4_tv_template[] =3D { + { "", + { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, + 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 } + }, +=09 + { "a", + { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, + 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 } + }, + + { "abc", + { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, + 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d } + }, +=09 + { "message digest", + { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, + 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b } + }, +=09 + { "abcdefghijklmnopqrstuvwxyz", + { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, + 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 } + }, + =09 + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, + 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 } + }, +=09 + { "123456789012345678901234567890123456789012345678901234567890123" + "45678901234567890", + { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, + 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 } + }, +}; + +/* + * MD5 test vectors from RFC1321 + */ +#define MD5_TEST_VECTORS 7 + +struct md5_testvec { + char plaintext[128]; + char digest[MD5_DIGEST_SIZE]; +} md5_tv_template[] =3D { + { "", + { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, + 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } }, + =09 + { "a", + { 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, + 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } }, + =20 + { "abc", + { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, + 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },=20 + =20 + { "message digest", + { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, + 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, + =20 + { "abcdefghijklmnopqrstuvwxyz", + { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, + 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } }, + =20 + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, + 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } }, + =20 + { "12345678901234567890123456789012345678901234567890123456789012" + "345678901234567890", + { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, + 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } } +}; + +#ifdef CONFIG_CRYPTO_HMAC +/* + * HMAC-MD5 test vectors from RFC2202 + * (These need to be fixed to not use strlen). + */ +#define HMAC_MD5_TEST_VECTORS 7 + +struct hmac_md5_testvec { + char key[128]; + char plaintext[128]; + char digest[MD5_DIGEST_SIZE]; +}; + +struct hmac_md5_testvec hmac_md5_tv_template[] =3D +{ +=09 + { + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x00}, + =20 + "Hi There", + =09 + { 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, + 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d } + }, + =20 + { + { 'J', 'e', 'f', 'e', 0 }, + =09 + "what do ya want for nothing?", + =09 + { 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, + 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 } + }, +=09 + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00 }, + =20 + { 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0x00 }, + =20 + { 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, + 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 } + }, +=09 + { + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,=20 + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x00 }, + =20 + {=20 + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0x00 }, + =20 + { 0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea, + 0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79 } + }, +=09 + { + { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00 }, + =20 + "Test With Truncation", + =09 + { 0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00, + 0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c } + }, +=09 + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00 }, + =20 + "Test Using Larger Than Block-Size Key - Hash Key First", + =09 + { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f, + 0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd } + }, +=09 + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00 }, + =09 + "Test Using Larger Than Block-Size Key and Larger Than One " + "Block-Size Data", + =09 + { 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, + 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e } + }, +=09 + /* cross page test, need to retain key */ +=09 + { + { 'J', 'e', 'f', 'e', 0 }, + =09 + "what do ya want for nothing?", + =09 + { 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, + 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 } + }, +=09 +}; + +=09 +/* + * HMAC-SHA1 test vectors from RFC2202 + */ + +#define HMAC_SHA1_TEST_VECTORS 7 + +struct hmac_sha1_testvec { + char key[128]; + char plaintext[128]; + char digest[SHA1_DIGEST_SIZE]; +} hmac_sha1_tv_template[] =3D { +=09 + { + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x00}, + =20 + "Hi There", + + { 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, + 0xe2, 0x8b, 0xc0, 0xb6, 0xfb ,0x37, 0x8c, 0x8e, 0xf1, + 0x46, 0xbe, 0x00 } + }, + =20 + { + { 'J', 'e', 'f', 'e', 0 }, + =09 + "what do ya want for nothing?", + + { 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, 0xd2, 0x74,=20 + 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a, 0x7c, 0x79 } + + }, +=09 + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,=20 + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00}, + + =20 + { 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0x00 }, + =20 + { 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd, 0x91, 0xa3,=20 + 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f, 0x63, 0xf1, 0x75, 0xd3 } + + }, +=09 + { + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,=20 + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x00 }, + =20 + {=20 + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0x00 }, + =20 + { 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6, 0xbc, 0x84,=20 + 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c, 0x2d, 0x72, 0x35, 0xda } + + }, +=09 + { + { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x00 }, + =20 + "Test With Truncation", + =09 + { 0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, 0xe7, 0xf2,=20 + 0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a, 0x5a, 0x04 } + + }, +=09 + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00 }, + =20 + "Test Using Larger Than Block-Size Key - Hash Key First", + =09 + { 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, 0x95, 0x70,=20 + 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, 0xed, 0x40, 0x21, 0x12 } + + }, +=09 + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00 }, + =09 + "Test Using Larger Than Block-Size Key and Larger Than One " + "Block-Size Data", + =09 + { 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d, 0x6b,=20 + 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91 } + }, +=09 + /* cross page test */ + { + { 'J', 'e', 'f', 'e', 0 }, + =09 + "what do ya want for nothing?", + + { 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, 0xd2, 0x74,=20 + 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a, 0x7c, 0x79 } + + }, + +}; + +/* + * HMAC-SHA256 test vectors from + * draft-ietf-ipsec-ciph-sha-256-01.txt + */ +#define HMAC_SHA256_TEST_VECTORS 10 + +struct hmac_sha256_testvec { + char key[128]; + char plaintext[128]; + char digest[SHA256_DIGEST_SIZE]; +} hmac_sha256_tv_template[] =3D { + + { + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x00 }, + =20 +=09 + { "abc" }, + =09 + { 0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a, + 0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a, + 0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66, + 0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81 }, + + }, +=09 + { + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x00 }, + =09 + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + =09 + { 0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08, + 0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae, + 0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49, + 0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30 } + }, + + { + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x00 }, + =09 + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + =09 + { 0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34, + 0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab, + 0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5, + 0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3 } + }, + + { + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x00 }, + =09 + { "Hi There" }, + =09 + { 0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6, + 0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5, + 0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c, + 0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7 } + }, + + { + { "Jefe" }, + =09 + { "what do ya want for nothing?" }, + =09 + { 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, + 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, + 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 } + }, + + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00 }, + =09 + { 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0x00 }, + =09 + { 0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea, + 0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62, + 0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc, + 0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0 } + }, + + { + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x00 }, + =09 + { 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0x00 }, + =09 + { 0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74, + 0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55, + 0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85, + 0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17 } + }, + + { + { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00 }, + =09 + { "Test With Truncation" }, + =09 + { 0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b, + 0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17, + 0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27, + 0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42 } + }, +=09 + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00 }, + =09 + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + =09 + { 0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09, + 0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb, + 0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e, + 0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f } + }, + + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00 }, + =09 + { "Test Using Larger Than Block-Size Key and Larger Than " + "One Block-Size Data" }, + =09 + { 0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3, + 0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8, + 0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc, + 0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6 } + }, +}; + + +#endif /* CONFIG_CRYPTO_HMAC */ + +/* + * SHA1 test vectors from from FIPS PUB 180-1 + */ +#define SHA1_TEST_VECTORS 2 + +struct sha1_testvec { + char plaintext[128]; + char digest[SHA1_DIGEST_SIZE]; +} sha1_tv_template[] =3D { + { "abc", + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,=20 + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C ,0x9C, 0xD0, 0xD8, 0x9D } + }, + =09 + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E ,0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 } + } +}; + +/* + * SHA256 test vectors from from NIST + */ +#define SHA256_TEST_VECTORS 2 + +struct sha256_testvec { + char plaintext[128]; + char digest[SHA256_DIGEST_SIZE]; +} sha256_tv_template[] =3D { + { "abc", + { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } + }, + =09 + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } + }, +}; + +/* + * SHA384 test vectors from from NIST and kerneli + */ +#define SHA384_TEST_VECTORS 4 + +struct sha384_testvec { + char plaintext[128]; + char digest[SHA384_DIGEST_SIZE]; +} sha384_tv_template[] =3D { + + { "abc", + { 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, + 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07, + 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, + 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, + 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23, + 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 } + }, +=09 + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x33, 0x91, 0xfd, 0xdd, 0xfc, 0x8d, 0xc7, 0x39, + 0x37, 0x07, 0xa6, 0x5b, 0x1b, 0x47, 0x09, 0x39, + 0x7c, 0xf8, 0xb1, 0xd1, 0x62, 0xaf, 0x05, 0xab, + 0xfe, 0x8f, 0x45, 0x0d, 0xe5, 0xf3, 0x6b, 0xc6, + 0xb0, 0x45, 0x5a, 0x85, 0x20, 0xbc, 0x4e, 0x6f, + 0x5f, 0xe9, 0x5b, 0x1f, 0xe3, 0xc8, 0x45, 0x2b } + }, +=09 + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8, + 0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47, + 0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2, + 0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12, + 0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9, + 0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39 } + }, +=09 + { "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd" + "efghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + { 0x3d, 0x20, 0x89, 0x73, 0xab, 0x35, 0x08, 0xdb, + 0xbd, 0x7e, 0x2c, 0x28, 0x62, 0xba, 0x29, 0x0a, + 0xd3, 0x01, 0x0e, 0x49, 0x78, 0xc1, 0x98, 0xdc, + 0x4d, 0x8f, 0xd0, 0x14, 0xe5, 0x82, 0x82, 0x3a, + 0x89, 0xe1, 0x6f, 0x9b, 0x2a, 0x7b, 0xbc, 0x1a, + 0xc9, 0x38, 0xe2, 0xd1, 0x99, 0xe8, 0xbe, 0xa4 } + }, +}; + +/* + * SHA512 test vectors from from NIST and kerneli + */ +#define SHA512_TEST_VECTORS 4 + +struct sha512_testvec { + char plaintext[128]; + char digest[SHA512_DIGEST_SIZE]; +} sha512_tv_template[] =3D { + + { "abc", + { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f } + }, +=09 + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x20, 0x4a, 0x8f, 0xc6, 0xdd, 0xa8, 0x2f, 0x0a, + 0x0c, 0xed, 0x7b, 0xeb, 0x8e, 0x08, 0xa4, 0x16, + 0x57, 0xc1, 0x6e, 0xf4, 0x68, 0xb2, 0x28, 0xa8, + 0x27, 0x9b, 0xe3, 0x31, 0xa7, 0x03, 0xc3, 0x35, + 0x96, 0xfd, 0x15, 0xc1, 0x3b, 0x1b, 0x07, 0xf9, + 0xaa, 0x1d, 0x3b, 0xea, 0x57, 0x78, 0x9c, 0xa0, + 0x31, 0xad, 0x85, 0xc7, 0xa7, 0x1d, 0xd7, 0x03, + 0x54, 0xec, 0x63, 0x12, 0x38, 0xca, 0x34, 0x45 } + }, +=09 + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 } + }, +=09 + { "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd" + "efghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + { 0x93, 0x0d, 0x0c, 0xef, 0xcb, 0x30, 0xff, 0x11, + 0x33, 0xb6, 0x89, 0x81, 0x21, 0xf1, 0xcf, 0x3d, + 0x27, 0x57, 0x8a, 0xfc, 0xaf, 0xe8, 0x67, 0x7c, + 0x52, 0x57, 0xcf, 0x06, 0x99, 0x11, 0xf7, 0x5d, + 0x8f, 0x58, 0x31, 0xb5, 0x6e, 0xbf, 0xda, 0x67, + 0xb2, 0x78, 0xe6, 0x6d, 0xff, 0x8b, 0x84, 0xfe, + 0x2b, 0x28, 0x70, 0xf7, 0x42, 0xa5, 0x80, 0xd8, + 0xed, 0xb4, 0x19, 0x87, 0x23, 0x28, 0x50, 0xc9 + } + }, +}; + +/* + * DES test vectors. + */ +#define DES_ENC_TEST_VECTORS 5 +#define DES_DEC_TEST_VECTORS 2 +#define DES_CBC_ENC_TEST_VECTORS 4 +#define DES_CBC_DEC_TEST_VECTORS 3 +#define DES3_EDE_ENC_TEST_VECTORS 3 +#define DES3_EDE_DEC_TEST_VECTORS 3 + +struct des_tv { + unsigned int len; + int fail; + char key[24]; + char iv[8]; + char plaintext[128]; + char result[128]; +}; + +struct des_tv des_enc_tv_template[] =3D { + + /* From Applied Cryptography */ + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0 }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7 }, + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d } + }, +=09 + /* Same key, different plaintext block */ + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0 }, + { 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 }, + { 0xf7, 0x9c, 0x89, 0x2a, 0x33, 0x8f, 0x4a, 0x8b } + }, +=09 + /* Sbox test from NBS */ + { + 8, 0, + =09 + { 0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57 }, + { 0 }, + { 0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42 }, + { 0x69, 0x0F, 0x5B, 0x0D, 0x9A, 0x26, 0x93, 0x9B } + }, +=09 + /* Three blocks */ + { + 24, 0, + =09 + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + =09 + { 0 }, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, + 0xca, 0xfe, 0xba, 0xbe, 0xfe, 0xed, 0xbe, 0xef }, + + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d, + 0xf7, 0x9c, 0x89, 0x2a, 0x33, 0x8f, 0x4a, 0x8b, + 0xb4, 0x99, 0x26, 0xf7, 0x1f, 0xe1, 0xd4, 0x90 }, =20 + }, +=09 + /* Weak key */ + { + 8, 1, + =09 + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0 }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7 }, + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d } + }, +=09 + /* Two blocks -- for testing encryption across pages */ + { + 16, 0, + =09 + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + =09 + { 0 }, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 }, + + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d, + 0xf7, 0x9c, 0x89, 0x2a, 0x33, 0x8f, 0x4a, 0x8b } + }, + + /* Two blocks -- for testing decryption across pages */ + { + 16, 0, + =09 + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + =09 + { 0 }, + =09 + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d, + 0xf7, 0x9c, 0x89, 0x2a, 0x33, 0x8f, 0x4a, 0x8b }, + =20 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 }, + }, +=09 + /* Four blocks -- for testing encryption with chunking */ + { + 24, 0, + =09 + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + =09 + { 0 }, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, + 0xca, 0xfe, 0xba, 0xbe, 0xfe, 0xed, 0xbe, 0xef, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 }, + + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d, + 0xf7, 0x9c, 0x89, 0x2a, 0x33, 0x8f, 0x4a, 0x8b, + 0xb4, 0x99, 0x26, 0xf7, 0x1f, 0xe1, 0xd4, 0x90, + 0xf7, 0x9c, 0x89, 0x2a, 0x33, 0x8f, 0x4a, 0x8b }, + }, +=09 +}; + +struct des_tv des_dec_tv_template[] =3D { + + /* From Applied Cryptography */ + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0 }, + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7 }, + }, +=09 + /* Sbox test from NBS */ + { + 8, 0, + + { 0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57 }, + { 0 }, + { 0x69, 0x0F, 0x5B, 0x0D, 0x9A, 0x26, 0x93, 0x9B }, + { 0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42 } + }, +=09 + /* Two blocks, for chunking test */ + { + 16, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0 }, + =09 + { 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d, + 0x69, 0x0F, 0x5B, 0x0D, 0x9A, 0x26, 0x93, 0x9B }, + =20 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7, + 0xa3, 0x99, 0x7b, 0xca, 0xaf, 0x69, 0xa0, 0xf5 } + }, + +}; + +struct des_tv des_cbc_enc_tv_template[] =3D { + /* From OpenSSL */ + { + 24, 0, + =09 + {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, + =09 + { 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20,=20 + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,=20 + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20,=20 + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x31, 0x00, 0x00 }, + =20 + { 0xcc, 0xd1, 0x73, 0xff, 0xab, 0x20, 0x39, 0xf4,=20 + 0xac, 0xd8, 0xae, 0xfd, 0xdf, 0xd8, 0xa1, 0xeb,=20 + 0x46, 0x8e, 0x91, 0x15, 0x78, 0x88, 0xba, 0x68,=20 + 0x1d, 0x26, 0x93, 0x97, 0xf7, 0xfe, 0x62, 0xb4 } + }, + + /* FIPS Pub 81 */ + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }, + { 0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 }, + { 0xe5, 0xc7, 0xcd, 0xde, 0x87, 0x2b, 0xf2, 0x7c }, + =09 + }, +=09 + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0xe5, 0xc7, 0xcd, 0xde, 0x87, 0x2b, 0xf2, 0x7c }, + { 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20 }, + { 0x43, 0xe9, 0x34, 0x00, 0x8c, 0x38, 0x9c, 0x0f }, + }, +=09 + {=09 + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0x43, 0xe9, 0x34, 0x00, 0x8c, 0x38, 0x9c, 0x0f }, + { 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20 }, + { 0x68, 0x37, 0x88, 0x49, 0x9a, 0x7c, 0x05, 0xf6 }, + }, +=09 + /* Copy of openssl vector for chunk testing */ +=09 + /* From OpenSSL */ + { + 24, 0, + =09 + {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, + =09 + { 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20,=20 + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,=20 + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20,=20 + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x31, 0x00, 0x00 }, + =20 + { 0xcc, 0xd1, 0x73, 0xff, 0xab, 0x20, 0x39, 0xf4,=20 + 0xac, 0xd8, 0xae, 0xfd, 0xdf, 0xd8, 0xa1, 0xeb,=20 + 0x46, 0x8e, 0x91, 0x15, 0x78, 0x88, 0xba, 0x68,=20 + 0x1d, 0x26, 0x93, 0x97, 0xf7, 0xfe, 0x62, 0xb4 } + }, + +=09 +}; + +struct des_tv des_cbc_dec_tv_template[] =3D { + + /* FIPS Pub 81 */ + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }, + { 0xe5, 0xc7, 0xcd, 0xde, 0x87, 0x2b, 0xf2, 0x7c }, + { 0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 }, + }, +=09 + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0xe5, 0xc7, 0xcd, 0xde, 0x87, 0x2b, 0xf2, 0x7c }, + { 0x43, 0xe9, 0x34, 0x00, 0x8c, 0x38, 0x9c, 0x0f }, + { 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20 },=20 + }, +=09 + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0x43, 0xe9, 0x34, 0x00, 0x8c, 0x38, 0x9c, 0x0f }, + { 0x68, 0x37, 0x88, 0x49, 0x9a, 0x7c, 0x05, 0xf6 },=20 + { 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20 }, + }, +=09 + /* Copy of above, for chunk testing */ +=09 + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + { 0x43, 0xe9, 0x34, 0x00, 0x8c, 0x38, 0x9c, 0x0f }, + { 0x68, 0x37, 0x88, 0x49, 0x9a, 0x7c, 0x05, 0xf6 },=20 + { 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20 }, + }, +}; + +/* + * We really need some more test vectors, especially for DES3 CBC. + */ +struct des_tv des3_ede_enc_tv_template[] =3D { + + /* These are from openssl */ + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}, + =20 + { 0 }, + =09 + { 0x73, 0x6F, 0x6D, 0x65, 0x64, 0x61, 0x74, 0x61 }, + =09 + { 0x18, 0xd7, 0x48, 0xe5, 0x63, 0x62, 0x05, 0x72 }, + }, +=09 + { + 8, 0, + =09 + { 0x03,0x52,0x02,0x07,0x67,0x20,0x82,0x17, + 0x86,0x02,0x87,0x66,0x59,0x08,0x21,0x98, + 0x64,0x05,0x6A,0xBD,0xFE,0xA9,0x34,0x57 }, + =20 + { 0 }, + =09 + { 0x73,0x71,0x75,0x69,0x67,0x67,0x6C,0x65 }, + =09 + { 0xc0,0x7d,0x2a,0x0f,0xa5,0x66,0xfa,0x30 } + }, +=09 + + { + 8, 0, + =09 + { 0x10,0x46,0x10,0x34,0x89,0x98,0x80,0x20, + 0x91,0x07,0xD0,0x15,0x89,0x19,0x01,0x01, + 0x19,0x07,0x92,0x10,0x98,0x1A,0x01,0x01 }, + =20 + { 0 }, + =20 + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + =09 + { 0xe1,0xef,0x62,0xc3,0x32,0xfe,0x82,0x5b }=09 + }, +}; + +struct des_tv des3_ede_dec_tv_template[] =3D { + + /* These are from openssl */ + { + 8, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}, + =20 + { 0 }, + =09 + =09 + { 0x18, 0xd7, 0x48, 0xe5, 0x63, 0x62, 0x05, 0x72 }, + =09 + { 0x73, 0x6F, 0x6D, 0x65, 0x64, 0x61, 0x74, 0x61 }, + }, +=09 + { + 8, 0, + =09 + { 0x03,0x52,0x02,0x07,0x67,0x20,0x82,0x17, + 0x86,0x02,0x87,0x66,0x59,0x08,0x21,0x98, + 0x64,0x05,0x6A,0xBD,0xFE,0xA9,0x34,0x57 }, + =20 + { 0 }, + =09 + { 0xc0,0x7d,0x2a,0x0f,0xa5,0x66,0xfa,0x30 }, + =09 + { 0x73,0x71,0x75,0x69,0x67,0x67,0x6C,0x65 }, + =09 + }, +=09 + + { + 8, 0, + =09 + { 0x10,0x46,0x10,0x34,0x89,0x98,0x80,0x20, + 0x91,0x07,0xD0,0x15,0x89,0x19,0x01,0x01, + 0x19,0x07,0x92,0x10,0x98,0x1A,0x01,0x01 }, + =20 + { 0 }, + =20 + { 0xe1,0xef,0x62,0xc3,0x32,0xfe,0x82,0x5b }, + =09 + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + }, +}; + +/* + * Blowfish test vectors. + */ +#define BF_ENC_TEST_VECTORS 6 +#define BF_DEC_TEST_VECTORS 6 +#define BF_CBC_ENC_TEST_VECTORS 1 +#define BF_CBC_DEC_TEST_VECTORS 1 + +struct bf_tv { + unsigned int keylen; + unsigned int plen; + unsigned int rlen; + int fail; + char key[56]; + char iv[8]; + char plaintext[32]; + char result[32]; +}; + +struct bf_tv bf_enc_tv_template[] =3D { + + /* DES test vectors from OpenSSL */ + { + 8, 8, 8, 0, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + { 0 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78 }, + }, +=09 + { + 8, 8, 8, 0, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E, }, + { 0 }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE }, + }, +=09 + { + 8, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, }, + { 0 }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0xE8, 0x7A, 0x24, 0x4E, 0x2C, 0xC8, 0x5E, 0x82 } + }, +=09 + /* Vary the keylength... */ +=09 + { + 16, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, + 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F }, + { 0 }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x93, 0x14, 0x28, 0x87, 0xEE, 0x3B, 0xE1, 0x5C } + }, +=09 + { + 21, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, + 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F, + 0x00, 0x11, 0x22, 0x33, 0x44 }, + { 0 }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0xE6, 0xF5, 0x1E, 0xD7, 0x9B, 0x9D, 0xB2, 0x1F } + }, +=09 + /* Generated with bf488 */ + { + 56, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, + 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F,=20 + 0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76,=20 + 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E,=20 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0 }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53 } + } +=09 +}; + +struct bf_tv bf_dec_tv_template[] =3D { + + /* DES test vectors from OpenSSL */ + { + 8, 8, 8, 0, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + { 0 }, + { 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, +=09 + { + 8, 8, 8, 0, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E, }, + { 0 }, + { 0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF } + }, +=09 + { + 8, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, }, + { 0 }, + { 0xE8, 0x7A, 0x24, 0x4E, 0x2C, 0xC8, 0x5E, 0x82 }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 } + }, +=09 + /* Vary the keylength... */ +=09 + { + 16, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, + 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F }, + { 0 }, + { 0x93, 0x14, 0x28, 0x87, 0xEE, 0x3B, 0xE1, 0x5C }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 } + }, +=09 + { + 21, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, + 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F, + 0x00, 0x11, 0x22, 0x33, 0x44 }, + { 0 }, + { 0xE6, 0xF5, 0x1E, 0xD7, 0x9B, 0x9D, 0xB2, 0x1F }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 } + }, +=09 + /* Generated with bf488, using OpenSSL, Libgcrypt and Nettle */ + { + 56, 8, 8, 0, + { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, + 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F,=20 + 0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76,=20 + 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E,=20 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0 }, + { 0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53 }, + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 } + } +}; + +struct bf_tv bf_cbc_enc_tv_template[] =3D { + + /* From OpenSSL */ + { + 16, 32, 32, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 }, + =20 + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }, + =09 + { 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 }, + =20 + { 0x6B, 0x77, 0xB4, 0xD6, 0x30, 0x06, 0xDE, 0xE6, + 0x05, 0xB1, 0x56, 0xE2, 0x74, 0x03, 0x97, 0x93, + 0x58, 0xDE, 0xB9, 0xE7, 0x15, 0x46, 0x16, 0xD9, + 0x59, 0xF1, 0x65, 0x2B, 0xD5, 0xFF, 0x92, 0xCC } + }, +}; + +struct bf_tv bf_cbc_dec_tv_template[] =3D { + + /* From OpenSSL */ + { + 16, 32, 32, 0, + =09 + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 }, + =20 + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }, + =09 + { 0x6B, 0x77, 0xB4, 0xD6, 0x30, 0x06, 0xDE, 0xE6, + 0x05, 0xB1, 0x56, 0xE2, 0x74, 0x03, 0x97, 0x93, + 0x58, 0xDE, 0xB9, 0xE7, 0x15, 0x46, 0x16, 0xD9, + 0x59, 0xF1, 0x65, 0x2B, 0xD5, 0xFF, 0x92, 0xCC }, + =20 + { 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 } + }, +}; + +/* + * Twofish test vectors. + */ +#define TF_ENC_TEST_VECTORS 3 +#define TF_DEC_TEST_VECTORS 3 +#define TF_CBC_ENC_TEST_VECTORS 4 +#define TF_CBC_DEC_TEST_VECTORS 4 + +struct tf_tv { + unsigned int keylen; + unsigned int plen; + unsigned int rlen; + int fail; + char key[32]; + char iv[16]; + char plaintext[48]; + char result[48]; +}; + +struct tf_tv tf_enc_tv_template[] =3D { + { + 16, 16, 16, 0, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, + 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A } + }, + { + 24, 16, 16, 0, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xCF, 0xD1, 0xD2, 0xE5, 0xA9, 0xBE, 0x9C, 0xDF, + 0x50, 0x1F, 0x13, 0xB8, 0x92, 0xBD, 0x22, 0x48 } + }, + {=09 + 32, 16, 16, 0, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, + { 0 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8, + 0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20 } + }, +}; + +struct tf_tv tf_dec_tv_template[] =3D { + { + 16, 16, 16, 0, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0 }, + { 0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, + 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, =20 + }, + { + 24, 16, 16, 0, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0 }, + { 0xCF, 0xD1, 0xD2, 0xE5, 0xA9, 0xBE, 0x9C, 0xDF, + 0x50, 0x1F, 0x13, 0xB8, 0x92, 0xBD, 0x22, 0x48 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + }, + {=09 + 32, 16, 16, 0, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, + { 0 }, + { 0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8, + 0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + }, +}; + +struct tf_tv tf_cbc_enc_tv_template[] =3D { + /* Generated with Nettle */ + { + 16, 16, 16, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, + 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a }, + }, +=09 + { + 16, 16, 16, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, + 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd4, 0x91, 0xdb, 0x16, 0xe7, 0xb1, 0xc3, 0x9e, + 0x86, 0xcb, 0x08, 0x6b, 0x78, 0x9f, 0x54, 0x19 }, + }, +=09 + { + 16, 16, 16, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd4, 0x91, 0xdb, 0x16, 0xe7, 0xb1, 0xc3, 0x9e, + 0x86, 0xcb, 0x08, 0x6b, 0x78, 0x9f, 0x54, 0x19 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x05, 0xef, 0x8c, 0x61, 0xa8, 0x11, 0x58, 0x26, + 0x34, 0xba, 0x5c, 0xb7, 0x10, 0x6a, 0xa6, 0x41 }, + }, +=09 + { + 16, 48, 48, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, + 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a, + 0xd4, 0x91, 0xdb, 0x16, 0xe7, 0xb1, 0xc3, 0x9e, + 0x86, 0xcb, 0x08, 0x6b, 0x78, 0x9f, 0x54, 0x19, + 0x05, 0xef, 0x8c, 0x61, 0xa8, 0x11, 0x58, 0x26, + 0x34, 0xba, 0x5c, 0xb7, 0x10, 0x6a, 0xa6, 0x41 }, + }, +}; + +struct tf_tv tf_cbc_dec_tv_template[] =3D { + /* Reverse of the first four above */ + { + 16, 16, 16, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, + 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a }, =20 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + }, +=09 + { + 16, 16, 16, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, + 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a }, + { 0xd4, 0x91, 0xdb, 0x16, 0xe7, 0xb1, 0xc3, 0x9e, + 0x86, 0xcb, 0x08, 0x6b, 0x78, 0x9f, 0x54, 0x19 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, =20 + }, +=09 + { + 16, 16, 16, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd4, 0x91, 0xdb, 0x16, 0xe7, 0xb1, 0xc3, 0x9e, + 0x86, 0xcb, 0x08, 0x6b, 0x78, 0x9f, 0x54, 0x19 }, + { 0x05, 0xef, 0x8c, 0x61, 0xa8, 0x11, 0x58, 0x26, + 0x34, 0xba, 0x5c, 0xb7, 0x10, 0x6a, 0xa6, 0x41 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, =20 + }, +=09 + { + 16, 48, 48, 0, + =09 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, + 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a, + 0xd4, 0x91, 0xdb, 0x16, 0xe7, 0xb1, 0xc3, 0x9e, + 0x86, 0xcb, 0x08, 0x6b, 0x78, 0x9f, 0x54, 0x19, + 0x05, 0xef, 0x8c, 0x61, 0xa8, 0x11, 0x58, 0x26, + 0x34, 0xba, 0x5c, 0xb7, 0x10, 0x6a, 0xa6, 0x41 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + }, +}; + +/* + * Serpent test vectors. These are backwards because Serpent writes + * octect sequences in right-to-left mode. + */ +#define SERPENT_ENC_TEST_VECTORS 4 +#define SERPENT_DEC_TEST_VECTORS 4 + +struct serpent_tv { + unsigned int keylen, fail; + u8 key[32], plaintext[16], result[16]; +}; + +struct serpent_tv serpent_enc_tv_template[] =3D=20 +{ + { + 0, 0, + { 0 }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x12, 0x07, 0xfc, 0xce, 0x9b, 0xd0, 0xd6, 0x47, + 0x6a, 0xe9, 0x8f, 0xbe, 0xd1, 0x43, 0xa0, 0xe2 } + }, + { + 16, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x4c, 0x7d, 0x8a, 0x32, 0x80, 0x72, 0xa2, 0x2c, + 0x82, 0x3e, 0x4a, 0x1f, 0x3a, 0xcd, 0xa1, 0x6d } + }, + { + 32, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0xde, 0x26, 0x9f, 0xf8, 0x33, 0xe4, 0x32, 0xb8, + 0x5b, 0x2e, 0x88, 0xd2, 0x70, 0x1c, 0xe7, 0x5c } + }, + { + 16, 0, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xdd, 0xd2, 0x6b, 0x98, 0xa5, 0xff, 0xd8, 0x2c, + 0x05, 0x34, 0x5a, 0x9d, 0xad, 0xbf, 0xaf, 0x49} + } +}; + +struct serpent_tv serpent_dec_tv_template[] =3D=20 +{ + { + 0, 0, + { 0 }, + { 0x12, 0x07, 0xfc, 0xce, 0x9b, 0xd0, 0xd6, 0x47, + 0x6a, 0xe9, 0x8f, 0xbe, 0xd1, 0x43, 0xa0, 0xe2 }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + + }, + { + 16, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x4c, 0x7d, 0x8a, 0x32, 0x80, 0x72, 0xa2, 0x2c, + 0x82, 0x3e, 0x4a, 0x1f, 0x3a, 0xcd, 0xa1, 0x6d }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + }, + { + 32, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + + { 0xde, 0x26, 0x9f, 0xf8, 0x33, 0xe4, 0x32, 0xb8, + 0x5b, 0x2e, 0x88, 0xd2, 0x70, 0x1c, 0xe7, 0x5c }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + }, + { + 16, 0, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, + { 0xdd, 0xd2, 0x6b, 0x98, 0xa5, 0xff, 0xd8, 0x2c, + 0x05, 0x34, 0x5a, 0x9d, 0xad, 0xbf, 0xaf, 0x49}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, =20 + } +}; + +/* + * AES test vectors. + */ +#define AES_ENC_TEST_VECTORS 3 +#define AES_DEC_TEST_VECTORS 3 + +struct aes_tv { + unsigned int keylen; + unsigned int plen; + unsigned int rlen; + int fail; + char key[32]; + char iv[8]; + char plaintext[16]; + char result[16]; +}; + +struct aes_tv aes_enc_tv_template[] =3D {=20 + /* From FIPS-197 */ + { + 16, 16, 16, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,=20 + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }, + }, + { + 24, 16, 16, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }, + { 0 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,=20 + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, + 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }, + }, + { + 32, 16, 16, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + { 0 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,=20 + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, + 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }, + }, +}; + +struct aes_tv aes_dec_tv_template[] =3D {=20 + /* From FIPS-197 */ + { + 16, 16, 16, 0, + =09 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,=20 + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0 }, + { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + }, +=09 + { + 24, 16, 16, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }, + { 0 }, + { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, + 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,=20 + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, =20 + }, + { + 32, 16, 16, 0, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + { 0 }, + { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, + 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,=20 + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + }, +}; + +/* + * Compression stuff. + */ +#define COMP_BUF_SIZE 512 + +struct comp_testvec { + int inlen, outlen; + char input[COMP_BUF_SIZE]; + char output[COMP_BUF_SIZE]; +}; + +/* + * Deflate test vectors (null-terminated strings). + * Params: winbits=3D11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL. + */ +#define DEFLATE_COMP_TEST_VECTORS 2 +#define DEFLATE_DECOMP_TEST_VECTORS 2 + +struct comp_testvec deflate_comp_tv_template[] =3D { + { + 70, 38, + =20 + "Join us now and share the software " + "Join us now and share the software ", + + { 0xf3, 0xca, 0xcf, 0xcc, 0x53, 0x28, 0x2d, 0x56, + 0xc8, 0xcb, 0x2f, 0x57, 0x48, 0xcc, 0x4b, 0x51, + 0x28, 0xce, 0x48, 0x2c, 0x4a, 0x55, 0x28, 0xc9, + 0x48, 0x55, 0x28, 0xce, 0x4f, 0x2b, 0x29, 0x07, + 0x71, 0xbc, 0x08, 0x2b, 0x01, 0x00=20 + }, + }, + =20 + { + 191, 122, + =20 + "This document describes a compression method based on the DEFLATE" + "compression algorithm. This document defines the application of " + "the DEFLATE algorithm to the IP Payload Compression Protocol.", + =20 + { 0x5d, 0x8d, 0x31, 0x0e, 0xc2, 0x30, 0x10, 0x04, + 0xbf, 0xb2, 0x2f, 0xc8, 0x1f, 0x10, 0x04, 0x09, + 0x89, 0xc2, 0x85, 0x3f, 0x70, 0xb1, 0x2f, 0xf8, + 0x24, 0xdb, 0x67, 0xd9, 0x47, 0xc1, 0xef, 0x49, + 0x68, 0x12, 0x51, 0xae, 0x76, 0x67, 0xd6, 0x27, + 0x19, 0x88, 0x1a, 0xde, 0x85, 0xab, 0x21, 0xf2, + 0x08, 0x5d, 0x16, 0x1e, 0x20, 0x04, 0x2d, 0xad, + 0xf3, 0x18, 0xa2, 0x15, 0x85, 0x2d, 0x69, 0xc4, + 0x42, 0x83, 0x23, 0xb6, 0x6c, 0x89, 0x71, 0x9b, + 0xef, 0xcf, 0x8b, 0x9f, 0xcf, 0x33, 0xca, 0x2f, + 0xed, 0x62, 0xa9, 0x4c, 0x80, 0xff, 0x13, 0xaf, + 0x52, 0x37, 0xed, 0x0e, 0x52, 0x6b, 0x59, 0x02, + 0xd9, 0x4e, 0xe8, 0x7a, 0x76, 0x1d, 0x02, 0x98, + 0xfe, 0x8a, 0x87, 0x83, 0xa3, 0x4f, 0x56, 0x8a, + 0xb8, 0x9e, 0x8e, 0x5c, 0x57, 0xd3, 0xa0, 0x79, + 0xfa, 0x02 }, + }, +}; + +struct comp_testvec deflate_decomp_tv_template[] =3D { + { + 122, 191, + =20 + { 0x5d, 0x8d, 0x31, 0x0e, 0xc2, 0x30, 0x10, 0x04, + 0xbf, 0xb2, 0x2f, 0xc8, 0x1f, 0x10, 0x04, 0x09, + 0x89, 0xc2, 0x85, 0x3f, 0x70, 0xb1, 0x2f, 0xf8, + 0x24, 0xdb, 0x67, 0xd9, 0x47, 0xc1, 0xef, 0x49, + 0x68, 0x12, 0x51, 0xae, 0x76, 0x67, 0xd6, 0x27, + 0x19, 0x88, 0x1a, 0xde, 0x85, 0xab, 0x21, 0xf2, + 0x08, 0x5d, 0x16, 0x1e, 0x20, 0x04, 0x2d, 0xad, + 0xf3, 0x18, 0xa2, 0x15, 0x85, 0x2d, 0x69, 0xc4, + 0x42, 0x83, 0x23, 0xb6, 0x6c, 0x89, 0x71, 0x9b, + 0xef, 0xcf, 0x8b, 0x9f, 0xcf, 0x33, 0xca, 0x2f, + 0xed, 0x62, 0xa9, 0x4c, 0x80, 0xff, 0x13, 0xaf, + 0x52, 0x37, 0xed, 0x0e, 0x52, 0x6b, 0x59, 0x02, + 0xd9, 0x4e, 0xe8, 0x7a, 0x76, 0x1d, 0x02, 0x98, + 0xfe, 0x8a, 0x87, 0x83, 0xa3, 0x4f, 0x56, 0x8a, + 0xb8, 0x9e, 0x8e, 0x5c, 0x57, 0xd3, 0xa0, 0x79, + 0xfa, 0x02 }, + =20 + "This document describes a compression method based on the DEFLATE" + "compression algorithm. This document defines the application of " + "the DEFLATE algorithm to the IP Payload Compression Protocol.", + }, +=09 + { + 38, 70, + =20 + { 0xf3, 0xca, 0xcf, 0xcc, 0x53, 0x28, 0x2d, 0x56, + 0xc8, 0xcb, 0x2f, 0x57, 0x48, 0xcc, 0x4b, 0x51, + 0x28, 0xce, 0x48, 0x2c, 0x4a, 0x55, 0x28, 0xc9, + 0x48, 0x55, 0x28, 0xce, 0x4f, 0x2b, 0x29, 0x07, + 0x71, 0xbc, 0x08, 0x2b, 0x01, 0x00 + }, + =20 + "Join us now and share the software " + "Join us now and share the software ", + }, +}; + +#endif /* _CRYPTO_TCRYPT_H */ diff -Nru a/crypto/twofish.c b/crypto/twofish.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/twofish.c Thu May 8 10:41:38 2003 @@ -0,0 +1,900 @@ +/* + * Twofish for CryptoAPI + * + * Originaly Twofish for GPG + * By Matthew Skala , July 26, 1998 + * 256-bit key length added March 20, 1999 + * Some modifications to reduce the text size by Werner Koch, April, 1998 + * Ported to the kerneli patch by Marc Mutz + * Ported to CryptoAPI by Colin Slater + * + * The original author has disclaimed all copyright interest in this + * code and thus put it in the public domain. The subsequent authors=20 + * have put this under the GNU General Public License. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *=20 + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * This code is a "clean room" implementation, written from the paper + * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey, + * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available + * through http://www.counterpane.com/twofish.html + * + * For background information on multiplication in finite fields, used for + * the matrix operations in the key schedule, see the book _Contemporary + * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the + * Third Edition. + */ +#include +#include +#include +#include +#include + + +/* The large precomputed tables for the Twofish cipher (twofish.c) + * Taken from the same source as twofish.c + * Marc Mutz + */ + +/* These two tables are the q0 and q1 permutations, exactly as described i= n + * the Twofish paper. */ + +static const u8 q0[256] =3D { + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, + 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, + 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, + 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, + 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, + 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, + 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, + 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, + 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, + 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, + 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, + 0x4A, 0x5E, 0xC1, 0xE0 +}; + +static const u8 q1[256] =3D { + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, + 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, + 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, + 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, + 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, + 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, + 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, + 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, + 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, + 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, + 0x55, 0x09, 0xBE, 0x91 +}; + +/* These MDS tables are actually tables of MDS composed with q0 and q1, + * because it is only ever used that way and we can save some time by + * precomputing. Of course the main saving comes from precomputing the + * GF(2^8) multiplication involved in the MDS matrix multiply; by looking + * things up in these tables we reduce the matrix multiply to four lookups + * and three XORs. Semi-formally, the definition of these tables is: + * mds[0][i] =3D MDS (q1[i] 0 0 0)^T mds[1][i] =3D MDS (0 q0[i] 0 0)^T + * mds[2][i] =3D MDS (0 0 q1[i] 0)^T mds[3][i] =3D MDS (0 0 0 q0[i])^T + * where ^T means "transpose", the matrix multiply is performed in GF(2^8) + * represented as GF(2)[x]/v(x) where v(x)=3Dx^8+x^6+x^5+x^3+1 as describe= d + * by Schneier et al, and I'm casually glossing over the byte/word + * conversion issues. */ + +static const u32 mds[4][256] =3D { + {0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B= , + 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B= , + 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32= , + 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1= , + 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA= , + 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B= , + 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1= , + 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5= , + 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490= , + 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154= , + 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0= , + 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796= , + 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228= , + 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7= , + 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3= , + 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8= , + 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477= , + 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF= , + 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C= , + 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9= , + 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA= , + 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D= , + 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72= , + 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E= , + 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76= , + 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321= , + 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39= , + 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01= , + 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D= , + 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E= , + 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5= , + 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64= , + 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7= , + 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544= , + 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E= , + 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E= , + 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A= , + 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B= , + 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2= , + 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9= , + 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504= , + 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756= , + 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91}, + + {0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252= , + 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A= , + 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020= , + 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141= , + 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444= , + 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424= , + 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A= , + 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757= , + 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383= , + 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A= , + 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9= , + 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656= , + 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1= , + 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898= , + 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414= , + 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3= , + 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1= , + 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989= , + 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5= , + 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282= , + 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E= , + 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E= , + 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202= , + 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC= , + 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565= , + 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A= , + 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808= , + 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272= , + 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A= , + 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969= , + 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505= , + 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5= , + 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D= , + 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343= , + 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF= , + 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3= , + 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F= , + 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646= , + 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6= , + 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF= , + 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A= , + 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7= , + 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8}, + + {0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B= , + 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F= , + 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A= , + 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783= , + 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70= , + 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3= , + 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB= , + 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA= , + 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4= , + 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41= , + 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C= , + 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07= , + 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622= , + 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18= , + 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035= , + 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96= , + 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84= , + 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E= , + 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F= , + 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD= , + 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558= , + 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40= , + 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA= , + 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85= , + 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF= , + 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773= , + 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D= , + 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B= , + 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C= , + 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19= , + 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086= , + 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D= , + 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74= , + 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755= , + 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691= , + 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D= , + 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4= , + 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53= , + 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E= , + 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9= , + 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705= , + 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7= , + 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF}, + + {0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98= , + 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866= , + 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643= , + 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77= , + 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9= , + 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C= , + 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3= , + 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216= , + 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F= , + 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25= , + 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF= , + 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7= , + 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4= , + 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E= , + 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA= , + 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C= , + 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12= , + 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A= , + 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D= , + 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE= , + 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A= , + 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C= , + 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B= , + 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4= , + 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B= , + 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3= , + 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE= , + 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB= , + 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85= , + 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA= , + 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E= , + 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8= , + 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33= , + 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC= , + 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718= , + 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA= , + 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8= , + 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872= , + 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882= , + 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D= , + 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10= , + 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6= , + 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8} +}; + +/* The exp_to_poly and poly_to_exp tables are used to perform efficient + * operations in GF(2^8) represented as GF(2)[x]/w(x) where + * w(x)=3Dx^8+x^6+x^3+x^2+1. We care about doing that because it's part o= f the + * definition of the RS matrix in the key schedule. Elements of that fiel= d + * are polynomials of degree not greater than 7 and all coefficients 0 or = 1, + * which can be represented naturally by bytes (just substitute x=3D2). I= n that + * form, GF(2^8) addition is the same as bitwise XOR, but GF(2^8) + * multiplication is inefficient without hardware support. To multiply + * faster, I make use of the fact x is a generator for the nonzero element= s, + * so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n = for + * some n in 0..254. Note that that caret is exponentiation in GF(2^8), + * *not* polynomial notation. So if I want to compute pq where p and q ar= e + * in GF(2^8), I can just say: + * 1. if p=3D0 or q=3D0 then pq=3D0 + * 2. otherwise, find m and n such that p=3Dx^m and q=3Dx^n + * 3. pq=3D(x^m)(x^n)=3Dx^(m+n), so add m and n and find pq + * The translations in steps 2 and 3 are looked up in the tables + * poly_to_exp (for step 2) and exp_to_poly (for step 3). To see this + * in action, look at the CALC_S macro. As additional wrinkles, note that + * one of my operands is always a constant, so the poly_to_exp lookup on i= t + * is done in advance; I included the original values in the comments so + * readers can have some chance of recognizing that this *is* the RS matri= x + * from the Twofish paper. I've only included the table entries I actuall= y + * need; I never do a lookup on a variable input of zero and the biggest + * exponents I'll ever see are 254 (variable) and 237 (constant), so they'= ll + * never sum to more than 491. I'm repeating part of the exp_to_poly table + * so that I don't have to do mod-255 reduction in the exponent arithmetic= . + * Since I know my constant operands are never zero, I only have to worry + * about zero values in the variable operand, and I do it with a simple + * conditional branch. I know conditionals are expensive, but I couldn't + * see a non-horrible way of avoiding them, and I did manage to group the + * statements so that each if covers four group multiplications. */ + +static const u8 poly_to_exp[255] =3D { + 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19, + 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A, + 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C, + 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B, + 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47, + 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D, + 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8, + 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C, + 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83, + 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48, + 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26, + 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E, + 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3, + 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9, + 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A, + 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D, + 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75, + 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84, + 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64, + 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49, + 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF, + 0x85, 0xC8, 0xA1 +}; + +static const u8 exp_to_poly[492] =3D { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2, + 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6, + 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A, + 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63, + 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C, + 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07, + 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88, + 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12, + 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7, + 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C, + 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8, + 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25, + 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A, + 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE, + 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC, + 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E, + 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92, + 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89, + 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB, + 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1, + 0x8F, 0x53, 0xA6, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, + 0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, + 0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, + 0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, + 0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, + 0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, + 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, + 0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, + 0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, + 0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, + 0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, + 0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, + 0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, + 0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, + 0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, + 0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, + 0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, + 0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, + 0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, + 0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB +}; + + +/* The table constants are indices of + * S-box entries, preprocessed through q0 and q1. */ +static const u8 calc_sb_tbl[512] =3D { + 0xA9, 0x75, 0x67, 0xF3, 0xB3, 0xC6, 0xE8, 0xF4, + 0x04, 0xDB, 0xFD, 0x7B, 0xA3, 0xFB, 0x76, 0xC8, + 0x9A, 0x4A, 0x92, 0xD3, 0x80, 0xE6, 0x78, 0x6B, + 0xE4, 0x45, 0xDD, 0x7D, 0xD1, 0xE8, 0x38, 0x4B, + 0x0D, 0xD6, 0xC6, 0x32, 0x35, 0xD8, 0x98, 0xFD, + 0x18, 0x37, 0xF7, 0x71, 0xEC, 0xF1, 0x6C, 0xE1, + 0x43, 0x30, 0x75, 0x0F, 0x37, 0xF8, 0x26, 0x1B, + 0xFA, 0x87, 0x13, 0xFA, 0x94, 0x06, 0x48, 0x3F, + 0xF2, 0x5E, 0xD0, 0xBA, 0x8B, 0xAE, 0x30, 0x5B, + 0x84, 0x8A, 0x54, 0x00, 0xDF, 0xBC, 0x23, 0x9D, + 0x19, 0x6D, 0x5B, 0xC1, 0x3D, 0xB1, 0x59, 0x0E, + 0xF3, 0x80, 0xAE, 0x5D, 0xA2, 0xD2, 0x82, 0xD5, + 0x63, 0xA0, 0x01, 0x84, 0x83, 0x07, 0x2E, 0x14, + 0xD9, 0xB5, 0x51, 0x90, 0x9B, 0x2C, 0x7C, 0xA3, + 0xA6, 0xB2, 0xEB, 0x73, 0xA5, 0x4C, 0xBE, 0x54, + 0x16, 0x92, 0x0C, 0x74, 0xE3, 0x36, 0x61, 0x51, + 0xC0, 0x38, 0x8C, 0xB0, 0x3A, 0xBD, 0xF5, 0x5A, + 0x73, 0xFC, 0x2C, 0x60, 0x25, 0x62, 0x0B, 0x96, + 0xBB, 0x6C, 0x4E, 0x42, 0x89, 0xF7, 0x6B, 0x10, + 0x53, 0x7C, 0x6A, 0x28, 0xB4, 0x27, 0xF1, 0x8C, + 0xE1, 0x13, 0xE6, 0x95, 0xBD, 0x9C, 0x45, 0xC7, + 0xE2, 0x24, 0xF4, 0x46, 0xB6, 0x3B, 0x66, 0x70, + 0xCC, 0xCA, 0x95, 0xE3, 0x03, 0x85, 0x56, 0xCB, + 0xD4, 0x11, 0x1C, 0xD0, 0x1E, 0x93, 0xD7, 0xB8, + 0xFB, 0xA6, 0xC3, 0x83, 0x8E, 0x20, 0xB5, 0xFF, + 0xE9, 0x9F, 0xCF, 0x77, 0xBF, 0xC3, 0xBA, 0xCC, + 0xEA, 0x03, 0x77, 0x6F, 0x39, 0x08, 0xAF, 0xBF, + 0x33, 0x40, 0xC9, 0xE7, 0x62, 0x2B, 0x71, 0xE2, + 0x81, 0x79, 0x79, 0x0C, 0x09, 0xAA, 0xAD, 0x82, + 0x24, 0x41, 0xCD, 0x3A, 0xF9, 0xEA, 0xD8, 0xB9, + 0xE5, 0xE4, 0xC5, 0x9A, 0xB9, 0xA4, 0x4D, 0x97, + 0x44, 0x7E, 0x08, 0xDA, 0x86, 0x7A, 0xE7, 0x17, + 0xA1, 0x66, 0x1D, 0x94, 0xAA, 0xA1, 0xED, 0x1D, + 0x06, 0x3D, 0x70, 0xF0, 0xB2, 0xDE, 0xD2, 0xB3, + 0x41, 0x0B, 0x7B, 0x72, 0xA0, 0xA7, 0x11, 0x1C, + 0x31, 0xEF, 0xC2, 0xD1, 0x27, 0x53, 0x90, 0x3E, + 0x20, 0x8F, 0xF6, 0x33, 0x60, 0x26, 0xFF, 0x5F, + 0x96, 0xEC, 0x5C, 0x76, 0xB1, 0x2A, 0xAB, 0x49, + 0x9E, 0x81, 0x9C, 0x88, 0x52, 0xEE, 0x1B, 0x21, + 0x5F, 0xC4, 0x93, 0x1A, 0x0A, 0xEB, 0xEF, 0xD9, + 0x91, 0xC5, 0x85, 0x39, 0x49, 0x99, 0xEE, 0xCD, + 0x2D, 0xAD, 0x4F, 0x31, 0x8F, 0x8B, 0x3B, 0x01, + 0x47, 0x18, 0x87, 0x23, 0x6D, 0xDD, 0x46, 0x1F, + 0xD6, 0x4E, 0x3E, 0x2D, 0x69, 0xF9, 0x64, 0x48, + 0x2A, 0x4F, 0xCE, 0xF2, 0xCB, 0x65, 0x2F, 0x8E, + 0xFC, 0x78, 0x97, 0x5C, 0x05, 0x58, 0x7A, 0x19, + 0xAC, 0x8D, 0x7F, 0xE5, 0xD5, 0x98, 0x1A, 0x57, + 0x4B, 0x67, 0x0E, 0x7F, 0xA7, 0x05, 0x5A, 0x64, + 0x28, 0xAF, 0x14, 0x63, 0x3F, 0xB6, 0x29, 0xFE, + 0x88, 0xF5, 0x3C, 0xB7, 0x4C, 0x3C, 0x02, 0xA5, + 0xB8, 0xCE, 0xDA, 0xE9, 0xB0, 0x68, 0x17, 0x44, + 0x55, 0xE0, 0x1F, 0x4D, 0x8A, 0x43, 0x7D, 0x69, + 0x57, 0x29, 0xC7, 0x2E, 0x8D, 0xAC, 0x74, 0x15, + 0xB7, 0x59, 0xC4, 0xA8, 0x9F, 0x0A, 0x72, 0x9E, + 0x7E, 0x6E, 0x15, 0x47, 0x22, 0xDF, 0x12, 0x34, + 0x58, 0x35, 0x07, 0x6A, 0x99, 0xCF, 0x34, 0xDC, + 0x6E, 0x22, 0x50, 0xC9, 0xDE, 0xC0, 0x68, 0x9B, + 0x65, 0x89, 0xBC, 0xD4, 0xDB, 0xED, 0xF8, 0xAB, + 0xC8, 0x12, 0xA8, 0xA2, 0x2B, 0x0D, 0x40, 0x52, + 0xDC, 0xBB, 0xFE, 0x02, 0x32, 0x2F, 0xA4, 0xA9, + 0xCA, 0xD7, 0x10, 0x61, 0x21, 0x1E, 0xF0, 0xB4, + 0xD3, 0x50, 0x5D, 0x04, 0x0F, 0xF6, 0x00, 0xC2, + 0x6F, 0x16, 0x9D, 0x25, 0x36, 0x86, 0x42, 0x56, + 0x4A, 0x55, 0x5E, 0x09, 0xC1, 0xBE, 0xE0, 0x91 +}; + +/* Macro to perform one column of the RS matrix multiplication. The + * parameters a, b, c, and d are the four bytes of output; i is the index + * of the key bytes, and w, x, y, and z, are the column of constants from + * the RS matrix, preprocessed through the poly_to_exp table. */ + +#define CALC_S(a, b, c, d, i, w, x, y, z) \ + if (key[i]) { \ + tmp =3D poly_to_exp[key[i] - 1]; \ + (a) ^=3D exp_to_poly[tmp + (w)]; \ + (b) ^=3D exp_to_poly[tmp + (x)]; \ + (c) ^=3D exp_to_poly[tmp + (y)]; \ + (d) ^=3D exp_to_poly[tmp + (z)]; \ + } + +/* Macros to calculate the key-dependent S-boxes for a 128-bit key using + * the S vector from CALC_S. CALC_SB_2 computes a single entry in all + * four S-boxes, where i is the index of the entry to compute, and a and b + * are the index numbers preprocessed through the q0 and q1 tables + * respectively. */ + +#define CALC_SB_2(i, a, b) \ + ctx->s[0][i] =3D mds[0][q0[(a) ^ sa] ^ se]; \ + ctx->s[1][i] =3D mds[1][q0[(b) ^ sb] ^ sf]; \ + ctx->s[2][i] =3D mds[2][q1[(a) ^ sc] ^ sg]; \ + ctx->s[3][i] =3D mds[3][q1[(b) ^ sd] ^ sh] + +/* Macro exactly like CALC_SB_2, but for 192-bit keys. */ + +#define CALC_SB192_2(i, a, b) \ + ctx->s[0][i] =3D mds[0][q0[q0[(b) ^ sa] ^ se] ^ si]; \ + ctx->s[1][i] =3D mds[1][q0[q1[(b) ^ sb] ^ sf] ^ sj]; \ + ctx->s[2][i] =3D mds[2][q1[q0[(a) ^ sc] ^ sg] ^ sk]; \ + ctx->s[3][i] =3D mds[3][q1[q1[(a) ^ sd] ^ sh] ^ sl]; + +/* Macro exactly like CALC_SB_2, but for 256-bit keys. */ + +#define CALC_SB256_2(i, a, b) \ + ctx->s[0][i] =3D mds[0][q0[q0[q1[(b) ^ sa] ^ se] ^ si] ^ sm]; \ + ctx->s[1][i] =3D mds[1][q0[q1[q1[(a) ^ sb] ^ sf] ^ sj] ^ sn]; \ + ctx->s[2][i] =3D mds[2][q1[q0[q0[(a) ^ sc] ^ sg] ^ sk] ^ so]; \ + ctx->s[3][i] =3D mds[3][q1[q1[q0[(b) ^ sd] ^ sh] ^ sl] ^ sp]; + +/* Macros to calculate the whitening and round subkeys. CALC_K_2 computes= the + * last two stages of the h() function for a given index (either 2i or 2i+= 1). + * a, b, c, and d are the four bytes going into the last two stages. For + * 128-bit keys, this is the entire h() function and a and c are the index + * preprocessed through q0 and q1 respectively; for longer keys they are t= he + * output of previous stages. j is the index of the first key byte to use= . + * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_= K_2 + * twice, doing the Psuedo-Hadamard Transform, and doing the necessary + * rotations. Its parameters are: a, the array to write the results into, + * j, the index of the first output entry, k and l, the preprocessed indic= es + * for index 2i, and m and n, the preprocessed indices for index 2i+1. + * CALC_K192_2 expands CALC_K_2 to handle 192-bit keys, by doing an + * additional lookup-and-XOR stage. The parameters a, b, c and d are the + * four bytes going into the last three stages. For 192-bit keys, c =3D d + * are the index preprocessed through q0, and a =3D b are the index + * preprocessed through q1; j is the index of the first key byte to use. + * CALC_K192 is identical to CALC_K but for using the CALC_K192_2 macro + * instead of CALC_K_2. + * CALC_K256_2 expands CALC_K192_2 to handle 256-bit keys, by doing an + * additional lookup-and-XOR stage. The parameters a and b are the index + * preprocessed through q0 and q1 respectively; j is the index of the firs= t + * key byte to use. CALC_K256 is identical to CALC_K but for using the + * CALC_K256_2 macro instead of CALC_K_2. */ + +#define CALC_K_2(a, b, c, d, j) \ + mds[0][q0[a ^ key[(j) + 8]] ^ key[j]] \ + ^ mds[1][q0[b ^ key[(j) + 9]] ^ key[(j) + 1]] \ + ^ mds[2][q1[c ^ key[(j) + 10]] ^ key[(j) + 2]] \ + ^ mds[3][q1[d ^ key[(j) + 11]] ^ key[(j) + 3]] + +#define CALC_K(a, j, k, l, m, n) \ + x =3D CALC_K_2 (k, l, k, l, 0); \ + y =3D CALC_K_2 (m, n, m, n, 4); \ + y =3D (y << 8) + (y >> 24); \ + x +=3D y; y +=3D x; ctx->a[j] =3D x; \ + ctx->a[(j) + 1] =3D (y << 9) + (y >> 23) + +#define CALC_K192_2(a, b, c, d, j) \ + CALC_K_2 (q0[a ^ key[(j) + 16]], \ + q1[b ^ key[(j) + 17]], \ + q0[c ^ key[(j) + 18]], \ + q1[d ^ key[(j) + 19]], j) + +#define CALC_K192(a, j, k, l, m, n) \ + x =3D CALC_K192_2 (l, l, k, k, 0); \ + y =3D CALC_K192_2 (n, n, m, m, 4); \ + y =3D (y << 8) + (y >> 24); \ + x +=3D y; y +=3D x; ctx->a[j] =3D x; \ + ctx->a[(j) + 1] =3D (y << 9) + (y >> 23) + +#define CALC_K256_2(a, b, j) \ + CALC_K192_2 (q1[b ^ key[(j) + 24]], \ + q1[a ^ key[(j) + 25]], \ + q0[a ^ key[(j) + 26]], \ + q0[b ^ key[(j) + 27]], j) + +#define CALC_K256(a, j, k, l, m, n) \ + x =3D CALC_K256_2 (k, l, 0); \ + y =3D CALC_K256_2 (m, n, 4); \ + y =3D (y << 8) + (y >> 24); \ + x +=3D y; y +=3D x; ctx->a[j] =3D x; \ + ctx->a[(j) + 1] =3D (y << 9) + (y >> 23) + + +/* Macros to compute the g() function in the encryption and decryption + * rounds. G1 is the straight g() function; G2 includes the 8-bit + * rotation for the high 32-bit word. */ + +#define G1(a) \ + (ctx->s[0][(a) & 0xFF]) ^ (ctx->s[1][((a) >> 8) & 0xFF]) \ + ^ (ctx->s[2][((a) >> 16) & 0xFF]) ^ (ctx->s[3][(a) >> 24]) + +#define G2(b) \ + (ctx->s[1][(b) & 0xFF]) ^ (ctx->s[2][((b) >> 8) & 0xFF]) \ + ^ (ctx->s[3][((b) >> 16) & 0xFF]) ^ (ctx->s[0][(b) >> 24]) + +/* Encryption and decryption Feistel rounds. Each one calls the two g() + * macros, does the PHT, and performs the XOR and the appropriate bit + * rotations. The parameters are the round number (used to select subkeys= ), + * and the four 32-bit chunks of the text. */ + +#define ENCROUND(n, a, b, c, d) \ + x =3D G1 (a); y =3D G2 (b); \ + x +=3D y; y +=3D x + ctx->k[2 * (n) + 1]; \ + (c) ^=3D x + ctx->k[2 * (n)]; \ + (c) =3D ((c) >> 1) + ((c) << 31); \ + (d) =3D (((d) << 1)+((d) >> 31)) ^ y + +#define DECROUND(n, a, b, c, d) \ + x =3D G1 (a); y =3D G2 (b); \ + x +=3D y; y +=3D x; \ + (d) ^=3D y + ctx->k[2 * (n) + 1]; \ + (d) =3D ((d) >> 1) + ((d) << 31); \ + (c) =3D (((c) << 1)+((c) >> 31)); \ + (c) ^=3D (x + ctx->k[2 * (n)]) + +/* Encryption and decryption cycles; each one is simply two Feistel rounds + * with the 32-bit chunks re-ordered to simulate the "swap" */ + +#define ENCCYCLE(n) \ + ENCROUND (2 * (n), a, b, c, d); \ + ENCROUND (2 * (n) + 1, c, d, a, b) + +#define DECCYCLE(n) \ + DECROUND (2 * (n) + 1, c, d, a, b); \ + DECROUND (2 * (n), a, b, c, d) + +/* Macros to convert the input and output bytes into 32-bit words, + * and simultaneously perform the whitening step. INPACK packs word + * number n into the variable named by x, using whitening subkey number m. + * OUTUNPACK unpacks word number n from the variable named by x, using + * whitening subkey number m. */ + +#define INPACK(n, x, m) \ + x =3D in[4 * (n)] ^ (in[4 * (n) + 1] << 8) \ + ^ (in[4 * (n) + 2] << 16) ^ (in[4 * (n) + 3] << 24) ^ ctx->w[m] + +#define OUTUNPACK(n, x, m) \ + x ^=3D ctx->w[m]; \ + out[4 * (n)] =3D x; out[4 * (n) + 1] =3D x >> 8; \ + out[4 * (n) + 2] =3D x >> 16; out[4 * (n) + 3] =3D x >> 24 + +#define TF_MIN_KEY_SIZE 16 +#define TF_MAX_KEY_SIZE 32 +#define TF_BLOCK_SIZE 16 + +/* Structure for an expanded Twofish key. s contains the key-dependent + * S-boxes composed with the MDS matrix; w contains the eight "whitening" + * subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. No= te + * that k[i] corresponds to what the Twofish paper calls K[i+8]. */ +struct twofish_ctx { + u32 s[4][256], w[8], k[32]; +}; + +/* Perform the key setup. */ +static int twofish_setkey(void *cx, const u8 *key, + unsigned int key_len, u32 *flags) +{ +=09 + struct twofish_ctx *ctx =3D cx; + + int i, j, k; + + /* Temporaries for CALC_K. */ + u32 x, y; + + /* The S vector used to key the S-boxes, split up into individual bytes. + * 128-bit keys use only sa through sh; 256-bit use all of them. */ + u8 sa =3D 0, sb =3D 0, sc =3D 0, sd =3D 0, se =3D 0, sf =3D 0, sg =3D 0, = sh =3D 0; + u8 si =3D 0, sj =3D 0, sk =3D 0, sl =3D 0, sm =3D 0, sn =3D 0, so =3D 0, = sp =3D 0; + + /* Temporary for CALC_S. */ + u8 tmp; + + /* Check key length. */ + if (key_len !=3D 16 && key_len !=3D 24 && key_len !=3D 32) + return -EINVAL; /* unsupported key length */ + + /* Compute the first two words of the S vector. The magic numbers are + * the entries of the RS matrix, preprocessed through poly_to_exp. The + * numbers in the comments are the original (polynomial form) matrix + * entries. */ + CALC_S (sa, sb, sc, sd, 0, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */ + CALC_S (sa, sb, sc, sd, 1, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */ + CALC_S (sa, sb, sc, sd, 2, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */ + CALC_S (sa, sb, sc, sd, 3, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */ + CALC_S (sa, sb, sc, sd, 4, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */ + CALC_S (sa, sb, sc, sd, 5, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */ + CALC_S (sa, sb, sc, sd, 6, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */ + CALC_S (sa, sb, sc, sd, 7, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */ + CALC_S (se, sf, sg, sh, 8, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */ + CALC_S (se, sf, sg, sh, 9, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */ + CALC_S (se, sf, sg, sh, 10, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */ + CALC_S (se, sf, sg, sh, 11, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */ + CALC_S (se, sf, sg, sh, 12, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */ + CALC_S (se, sf, sg, sh, 13, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */ + CALC_S (se, sf, sg, sh, 14, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */ + CALC_S (se, sf, sg, sh, 15, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */ + + if (key_len =3D=3D 24 || key_len =3D=3D 32) { /* 192- or 256-bit key */ + /* Calculate the third word of the S vector */ + CALC_S (si, sj, sk, sl, 16, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */ + CALC_S (si, sj, sk, sl, 17, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */ + CALC_S (si, sj, sk, sl, 18, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */ + CALC_S (si, sj, sk, sl, 19, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */ + CALC_S (si, sj, sk, sl, 20, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */ + CALC_S (si, sj, sk, sl, 21, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */ + CALC_S (si, sj, sk, sl, 22, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */ + CALC_S (si, sj, sk, sl, 23, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */ + } + + if (key_len =3D=3D 32) { /* 256-bit key */ + /* Calculate the fourth word of the S vector */ + CALC_S (sm, sn, so, sp, 24, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */ + CALC_S (sm, sn, so, sp, 25, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */ + CALC_S (sm, sn, so, sp, 26, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */ + CALC_S (sm, sn, so, sp, 27, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */ + CALC_S (sm, sn, so, sp, 28, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */ + CALC_S (sm, sn, so, sp, 29, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */ + CALC_S (sm, sn, so, sp, 30, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */ + CALC_S (sm, sn, so, sp, 31, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */ + + /* Compute the S-boxes. */ + for ( i =3D j =3D 0, k =3D 1; i < 256; i++, j +=3D 2, k +=3D 2 ) { + CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] ); + } + + /* Calculate whitening and round subkeys. The constants are + * indices of subkeys, preprocessed through q0 and q1. */ + CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3); + CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4); + CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B); + CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8); + CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3); + CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B); + CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D); + CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B); + CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32); + CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD); + CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71); + CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1); + CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F); + CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B); + CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA); + CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F); + CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA); + CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B); + CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00); + CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D); + } else if (key_len =3D=3D 24) { /* 192-bit key */ + /* Compute the S-boxes. */ + for ( i =3D j =3D 0, k =3D 1; i < 256; i++, j +=3D 2, k +=3D 2 ) { + CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] ); + } + + /* Calculate whitening and round subkeys. The constants are + * indices of subkeys, preprocessed through q0 and q1. */ + CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3); + CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4); + CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B); + CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8); + CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3); + CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B); + CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D); + CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B); + CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32); + CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD); + CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71); + CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1); + CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F); + CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B); + CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA); + CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F); + CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA); + CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B); + CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00); + CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D); + } else { /* 128-bit key */ + /* Compute the S-boxes. */ + for ( i =3D j =3D 0, k =3D 1; i < 256; i++, j +=3D 2, k +=3D 2 ) { + CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] ); + } + + /* Calculate whitening and round subkeys. The constants are + * indices of subkeys, preprocessed through q0 and q1. */ + CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3); + CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4); + CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B); + CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8); + CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3); + CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B); + CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D); + CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B); + CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32); + CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD); + CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71); + CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1); + CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F); + CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B); + CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA); + CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F); + CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA); + CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B); + CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00); + CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D); + } + + return 0; +} + +/* Encrypt one block. in and out may be the same. */ +static void twofish_encrypt(void *cx, u8 *out, const u8 *in) +{ + struct twofish_ctx *ctx =3D cx; + + /* The four 32-bit chunks of the text. */ + u32 a, b, c, d; +=09 + /* Temporaries used by the round function. */ + u32 x, y; + + /* Input whitening and packing. */ + INPACK (0, a, 0); + INPACK (1, b, 1); + INPACK (2, c, 2); + INPACK (3, d, 3); +=09 + /* Encryption Feistel cycles. */ + ENCCYCLE (0); + ENCCYCLE (1); + ENCCYCLE (2); + ENCCYCLE (3); + ENCCYCLE (4); + ENCCYCLE (5); + ENCCYCLE (6); + ENCCYCLE (7); +=09 + /* Output whitening and unpacking. */ + OUTUNPACK (0, c, 4); + OUTUNPACK (1, d, 5); + OUTUNPACK (2, a, 6); + OUTUNPACK (3, b, 7); +=09 +} + +/* Decrypt one block. in and out may be the same. */ +static void twofish_decrypt(void *cx, u8 *out, const u8 *in) +{ + struct twofish_ctx *ctx =3D cx; + =20 + /* The four 32-bit chunks of the text. */ + u32 a, b, c, d; +=09 + /* Temporaries used by the round function. */ + u32 x, y; +=09 + /* Input whitening and packing. */ + INPACK (0, c, 4); + INPACK (1, d, 5); + INPACK (2, a, 6); + INPACK (3, b, 7); +=09 + /* Encryption Feistel cycles. */ + DECCYCLE (7); + DECCYCLE (6); + DECCYCLE (5); + DECCYCLE (4); + DECCYCLE (3); + DECCYCLE (2); + DECCYCLE (1); + DECCYCLE (0); + + /* Output whitening and unpacking. */ + OUTUNPACK (0, a, 0); + OUTUNPACK (1, b, 1); + OUTUNPACK (2, c, 2); + OUTUNPACK (3, d, 3); + +} + +static struct crypto_alg alg =3D { + .cra_name =3D "twofish", + .cra_flags =3D CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize =3D TF_BLOCK_SIZE, + .cra_ctxsize =3D sizeof(struct twofish_ctx), + .cra_module =3D THIS_MODULE, + .cra_list =3D LIST_HEAD_INIT(alg.cra_list), + .cra_u =3D { .cipher =3D { + .cia_min_keysize =3D TF_MIN_KEY_SIZE, + .cia_max_keysize =3D TF_MAX_KEY_SIZE, + .cia_ivsize =3D TF_BLOCK_SIZE, + .cia_setkey =3D twofish_setkey, + .cia_encrypt =3D twofish_encrypt, + .cia_decrypt =3D twofish_decrypt } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION ("Twofish Cipher Algorithm"); diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c --- a/drivers/net/3c59x.c Thu May 8 10:41:36 2003 +++ b/drivers/net/3c59x.c Thu May 8 10:41:36 2003 @@ -1997,7 +1997,7 @@ if (skb->ip_summed !=3D CHECKSUM_HW) vp->tx_ring[entry].status =3D cpu_to_le32(skb->len | TxIntrUploaded); else - vp->tx_ring[entry].status =3D cpu_to_le32(skb->len | TxIntrUploaded | A= ddTCPChksum); + vp->tx_ring[entry].status =3D cpu_to_le32(skb->len | TxIntrUploaded | A= ddTCPChksum | AddUDPChksum); =20 if (!skb_shinfo(skb)->nr_frags) { vp->tx_ring[entry].frag[0].addr =3D cpu_to_le32(pci_map_single(vp->pdev,= skb->data, diff -Nru a/include/asm-i386/kmap_types.h b/include/asm-i386/kmap_types.h --- a/include/asm-i386/kmap_types.h Thu May 8 10:41:37 2003 +++ b/include/asm-i386/kmap_types.h Thu May 8 10:41:37 2003 @@ -8,6 +8,8 @@ KM_USER0, KM_USER1, KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, KM_TYPE_NR }; =20 diff -Nru a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h --- a/include/asm-ppc/kmap_types.h Thu May 8 10:41:36 2003 +++ b/include/asm-ppc/kmap_types.h Thu May 8 10:41:36 2003 @@ -9,6 +9,8 @@ KM_USER0, KM_USER1, KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, KM_TYPE_NR }; =20 diff -Nru a/include/asm-sparc/kmap_types.h b/include/asm-sparc/kmap_types.h --- a/include/asm-sparc/kmap_types.h Thu May 8 10:41:37 2003 +++ b/include/asm-sparc/kmap_types.h Thu May 8 10:41:37 2003 @@ -8,6 +8,8 @@ KM_USER0, KM_USER1, KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, KM_TYPE_NR }; =20 diff -Nru a/include/asm-sparc64/kmap_types.h b/include/asm-sparc64/kmap_typ= es.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-sparc64/kmap_types.h Thu May 8 10:41:38 2003 @@ -0,0 +1,20 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +/* Dummy header just to define km_type. None of this + * is actually used on sparc64. -DaveM + */ + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; + +#endif diff -Nru a/include/asm-x86_64/kmap_types.h b/include/asm-x86_64/kmap_types= .h --- a/include/asm-x86_64/kmap_types.h Thu May 8 10:41:38 2003 +++ b/include/asm-x86_64/kmap_types.h Thu May 8 10:41:38 2003 @@ -7,6 +7,8 @@ KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, KM_TYPE_NR }; =20 diff -Nru a/include/linux/crypto.h b/include/linux/crypto.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/crypto.h Thu May 8 10:41:38 2003 @@ -0,0 +1,379 @@ +/* + * Scatterlist Cryptographic API. + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * + * Portions derived from Cryptoapi, by Alexander Kjeldaas + * and Nettle, by Niels M=F6ller. + *=20 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + */ +#ifndef _LINUX_CRYPTO_H +#define _LINUX_CRYPTO_H + +#include +#include +#include +#include +#include +#include + +/* + * Algorithm masks and types. + */ +#define CRYPTO_ALG_TYPE_MASK 0x000000ff +#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 +#define CRYPTO_ALG_TYPE_DIGEST 0x00000002 +#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 + +/* + * Transform masks and values (for crt_flags). + */ +#define CRYPTO_TFM_MODE_MASK 0x000000ff +#define CRYPTO_TFM_REQ_MASK 0x000fff00 +#define CRYPTO_TFM_RES_MASK 0xfff00000 + +#define CRYPTO_TFM_MODE_ECB 0x00000001 +#define CRYPTO_TFM_MODE_CBC 0x00000002 +#define CRYPTO_TFM_MODE_CFB 0x00000004 +#define CRYPTO_TFM_MODE_CTR 0x00000008 + +#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 +#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 +#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 +#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 +#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 +#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 + +/* + * Miscellaneous stuff. + */ +#define CRYPTO_UNSPEC 0 +#define CRYPTO_MAX_ALG_NAME 64 + +struct scatterlist; + +/* + * Algorithms: modular crypto algorithm implementations, managed + * via crypto_register_alg() and crypto_unregister_alg(). + */ +struct cipher_alg { + unsigned int cia_min_keysize; + unsigned int cia_max_keysize; + unsigned int cia_ivsize; + int (*cia_setkey)(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags); + void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); + void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); +}; + +struct digest_alg { + unsigned int dia_digestsize; + void (*dia_init)(void *ctx); + void (*dia_update)(void *ctx, const u8 *data, unsigned int len); + void (*dia_final)(void *ctx, u8 *out); +}; + +struct compress_alg { + int (*coa_init)(void *ctx); + void (*coa_exit)(void *ctx); + int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define cra_cipher cra_u.cipher +#define cra_digest cra_u.digest +#define cra_compress cra_u.compress + +struct crypto_alg { + struct list_head cra_list; + u32 cra_flags; + unsigned int cra_blocksize; + unsigned int cra_ctxsize; + const char cra_name[CRYPTO_MAX_ALG_NAME]; + + union { + struct cipher_alg cipher; + struct digest_alg digest; + struct compress_alg compress; + } cra_u; +=09 + struct module *cra_module; +}; + +/* + * Algorithm registration interface. + */ +int crypto_register_alg(struct crypto_alg *alg); +int crypto_unregister_alg(struct crypto_alg *alg); + +/* + * Algorithm query interface. + */ +int crypto_alg_available(const char *name, u32 flags); + +/* + * Transforms: user-instantiated objects which encapsulate algorithms + * and core processing logic. Managed via crypto_alloc_tfm() and + * crypto_free_tfm(), as well as the various helpers below. + */ +struct crypto_tfm; + +struct cipher_tfm { + void *cit_iv; + u32 cit_mode; + int (*cit_setkey)(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen); + int (*cit_encrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_encrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + int (*cit_decrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_decrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + void (*cit_xor_block)(u8 *dst, const u8 *src); +}; + +struct digest_tfm { + void (*dit_init)(struct crypto_tfm *tfm); + void (*dit_update)(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); + void (*dit_final)(struct crypto_tfm *tfm, u8 *out); + void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, + unsigned int nsg, u8 *out); +#ifdef CONFIG_CRYPTO_HMAC + void *dit_hmac_block; +#endif +}; + +struct compress_tfm { + int (*cot_compress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*cot_decompress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define crt_cipher crt_u.cipher +#define crt_digest crt_u.digest +#define crt_compress crt_u.compress + +struct crypto_tfm { + + u32 crt_flags; +=09 + union { + struct cipher_tfm cipher; + struct digest_tfm digest; + struct compress_tfm compress; + } crt_u; +=09 + struct crypto_alg *__crt_alg; +}; + +/*=20 + * Transform user interface. + */ +=20 +/* + * crypto_alloc_tfm() will first attempt to locate an already loaded algor= ithm. + * If that fails and the kernel supports dynamically loadable modules, it + * will then attempt to load a module of the same name or alias. A refcou= nt + * is grabbed on the algorithm which is then associated with the new trans= form. + * + * crypto_free_tfm() frees up the transform and any associated resources, + * then drops the refcount on the associated algorithm. + */ +struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); +void crypto_free_tfm(struct crypto_tfm *tfm); + +/* + * Transform helpers which query the underlying algorithm. + */ +static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_name; +} + +static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg =3D tfm->__crt_alg; +=09 + if (alg->cra_module) + return alg->cra_module->name; + else + return NULL; +} + +static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; +} + +static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *t= fm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_min_keysize; +} + +static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *t= fm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_max_keysize; +} + +static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_ivsize; +} + +static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm= ) +{ + return tfm->__crt_alg->cra_blocksize; +} + +static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tf= m) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_DIGEST); + return tfm->__crt_alg->cra_digest.dia_digestsize; +} + +/* + * API wrappers. + */ +static inline void crypto_digest_init(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_init(tfm); +} + +static inline void crypto_digest_update(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_update(tfm, sg, nsg); +} + +static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_final(tfm, out); +} + +static inline void crypto_digest_digest(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_digest(tfm, sg, nsg, out); +} + +static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_setkey(tfm, key, keylen); +} + +static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); +} =20 + +static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode =3D=3D CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); +} =20 + +static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); +} + +static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode =3D=3D CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); +} + +static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, + const u8 *src, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + memcpy(tfm->crt_cipher.cit_iv, src, len); +} + +static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, + u8 *dst, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_CIPHER); + memcpy(dst, tfm->crt_cipher.cit_iv, len); +} + +static inline int crypto_comp_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); +} + +static inline int crypto_comp_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) !=3D CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); +} + +/* + * HMAC support. + */ +#ifdef CONFIG_CRYPTO_HMAC +void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keyle= n); +void crypto_hmac_update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); +void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, + unsigned int *keylen, u8 *out); +void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, + struct scatterlist *sg, unsigned int nsg, u8 *out); +#endif /* CONFIG_CRYPTO_HMAC */ + +#endif /* _LINUX_CRYPTO_H */ + diff -Nru a/include/linux/in.h b/include/linux/in.h --- a/include/linux/in.h Thu May 8 10:41:37 2003 +++ b/include/linux/in.h Thu May 8 10:41:37 2003 @@ -41,6 +41,7 @@ IPPROTO_ESP =3D 50, /* Encapsulation Security Payload protoco= l */ IPPROTO_AH =3D 51, /* Authentication Header protocol *= / IPPROTO_COMP =3D 108, /* Compression Header protocol */ + IPPROTO_SCTP =3D 132, /* Stream Control Transport Protocol */ =20 IPPROTO_RAW =3D 255, /* Raw IP packets */ IPPROTO_MAX @@ -67,6 +68,8 @@ #define IP_RECVTOS 13 #define IP_MTU 14 #define IP_FREEBIND 15 +#define IP_IPSEC_POLICY 16 +#define IP_XFRM_POLICY 17 =20 /* BSD compatibility */ #define IP_RECVRETOPTS IP_RETOPTS diff -Nru a/include/linux/in6.h b/include/linux/in6.h --- a/include/linux/in6.h Thu May 8 10:41:37 2003 +++ b/include/linux/in6.h Thu May 8 10:41:37 2003 @@ -180,5 +180,8 @@ #define IPV6_FLOWLABEL_MGR 32 #define IPV6_FLOWINFO_SEND 33 =20 +#define IPV6_IPSEC_POLICY 34 +#define IPV6_XFRM_POLICY 35 + =20 #endif diff -Nru a/include/linux/inetdevice.h b/include/linux/inetdevice.h --- a/include/linux/inetdevice.h Thu May 8 10:41:36 2003 +++ b/include/linux/inetdevice.h Thu May 8 10:41:36 2003 @@ -19,6 +19,8 @@ int tag; int arp_filter; int medium_id; + int no_xfrm; + int no_policy; void *sysctl; }; =20 diff -Nru a/include/linux/ip.h b/include/linux/ip.h --- a/include/linux/ip.h Thu May 8 10:41:37 2003 +++ b/include/linux/ip.h Thu May 8 10:41:37 2003 @@ -18,8 +18,6 @@ #define _LINUX_IP_H #include =20 -/* SOL_IP socket options */ - #define IPTOS_TOS_MASK 0x1E #define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK) #define IPTOS_LOWDELAY 0x10 @@ -67,14 +65,6 @@ #define MAXTTL 255 #define IPDEFTTL 64 =20 -/* struct timestamp, struct route and MAX_ROUTES are removed. - - REASONS: it is clear that nobody used them because: - - MAX_ROUTES value was wrong. - - "struct route" was wrong. - - "struct timestamp" had fatally misaligned bitfields and was completel= y unusable. - */ - #define IPOPT_OPTVAL 0 #define IPOPT_OLEN 1 #define IPOPT_OFFSET 2 @@ -133,6 +123,21 @@ __u32 saddr; __u32 daddr; /*The options start here. */ +}; + +struct ip_auth_hdr { + __u8 nexthdr; + __u8 hdrlen; /* This one is measured in 32 bit units! */ + __u16 reserved; + __u32 spi; + __u32 seq_no; /* Sequence number */ + __u8 auth_data[0]; /* Variable len but >=3D4. Mind the 64 bit alignment!= */ +}; + +struct ip_esp_hdr { + __u32 spi; + __u32 seq_no; /* Sequence number */ + __u8 enc_data[0]; /* Variable len but >=3D8. Mind the 64 bit alignment! = */ }; =20 #endif /* _LINUX_IP_H */ diff -Nru a/include/linux/ipsec.h b/include/linux/ipsec.h --- a/include/linux/ipsec.h Thu May 8 10:41:36 2003 +++ b/include/linux/ipsec.h Thu May 8 10:41:36 2003 @@ -1,69 +1,46 @@ -/* - * Definitions for the SECurity layer - * - * Author: - * Robert Muchsel - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -=20 #ifndef _LINUX_IPSEC_H #define _LINUX_IPSEC_H =20 -#include -#include -#include -#include - -/* Values for the set/getsockopt calls */ - -/* These defines are compatible with NRL IPv6, however their semantics - is different */ - -#define IPSEC_LEVEL_NONE -1 /* send plaintext, accept any */ -#define IPSEC_LEVEL_DEFAULT 0 /* encrypt/authenticate if possible */ - /* the default MUST be 0, because a */ - /* socket is initialized with 0's */ -#define IPSEC_LEVEL_USE 1 /* use outbound, don't require inbound */ -#define IPSEC_LEVEL_REQUIRE 2 /* require both directions */ -#define IPSEC_LEVEL_UNIQUE 2 /* for compatibility only */ - -#ifdef __KERNEL__ - -/* skb bit flags set on packet input processing */ - -#define RCV_SEC 0x0f /* options on receive */ -#define RCV_AUTH 0x01 /* was authenticated */ -#define RCV_CRYPT 0x02 /* was encrypted */ -#define RCV_TUNNEL 0x04 /* was tunneled */ -#define SND_SEC 0xf0 /* options on send, these are */ -#define SND_AUTH 0x10 /* currently unused */ -#define SND_CRYPT 0x20 -#define SND_TUNNEL 0x40 - -/* - * FIXME: ignores network encryption for now.. - */ -=20 -#ifdef CONFIG_NET_SECURITY -static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb= ) -{ - return ((sk->authentication < IPSEC_LEVEL_REQUIRE) || - (skb->security & RCV_AUTH)) && - ((sk->encryption < IPSEC_LEVEL_REQUIRE) || - (skb->security & RCV_CRYPT)); -} - -#else - -static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb= ) -{ - return 1; -} -#endif /* CONFIG */ +/* The definitions, required to talk to KAME racoon IKE. */ + +#include + +#define IPSEC_PORT_ANY 0 +#define IPSEC_ULPROTO_ANY 255 +#define IPSEC_PROTO_ANY 255 + +enum { + IPSEC_MODE_ANY =3D 0, /* We do not support this for SA */ + IPSEC_MODE_TRANSPORT =3D 1, + IPSEC_MODE_TUNNEL =3D 2 +}; + +enum { + IPSEC_DIR_ANY =3D 0, + IPSEC_DIR_INBOUND =3D 1, + IPSEC_DIR_OUTBOUND =3D 2, + IPSEC_DIR_FWD =3D 3, /* It is our own */ + IPSEC_DIR_MAX =3D 4, + IPSEC_DIR_INVALID =3D 5 +}; + +enum { + IPSEC_POLICY_DISCARD =3D 0, + IPSEC_POLICY_NONE =3D 1, + IPSEC_POLICY_IPSEC =3D 2, + IPSEC_POLICY_ENTRUST =3D 3, + IPSEC_POLICY_BYPASS =3D 4 +}; + +enum { + IPSEC_LEVEL_DEFAULT =3D 0, + IPSEC_LEVEL_USE =3D 1, + IPSEC_LEVEL_REQUIRE =3D 2, + IPSEC_LEVEL_UNIQUE =3D 3 +}; + +#define IPSEC_MANUAL_REQID_MAX 0x3fff + +#define IPSEC_REPLAYWSIZE 32 =20 -#endif /* __KERNEL__ */ #endif /* _LINUX_IPSEC_H */ diff -Nru a/include/linux/ipv6.h b/include/linux/ipv6.h --- a/include/linux/ipv6.h Thu May 8 10:41:37 2003 +++ b/include/linux/ipv6.h Thu May 8 10:41:37 2003 @@ -73,6 +73,21 @@ #define rt0_type rt_hdr.type; }; =20 +struct ipv6_auth_hdr { + __u8 nexthdr; + __u8 hdrlen; /* This one is measured in 32 bit units! */ + __u16 reserved; + __u32 spi; + __u32 seq_no; /* Sequence number */ + __u8 auth_data[0]; /* Length variable but >=3D4. Mind the 64 bit ali= gnment! */ +}; + +struct ipv6_esp_hdr { + __u32 spi; + __u32 seq_no; /* Sequence number */ + __u8 enc_data[0]; /* Length variable but >=3D8. Mind the 64 bit ali= gnment! */ +}; + /* * IPv6 fixed header * diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Thu May 8 10:41:37 2003 +++ b/include/linux/netdevice.h Thu May 8 10:41:37 2003 @@ -89,6 +89,11 @@ #define MAX_HEADER (LL_MAX_HEADER + 48) #endif =20 +/* Reserve 16byte aligned hard_header_len, but at least 16. + * Alternative is: dev->hard_header_len ? (dev->hard_header_len + 15)&~15 = : 0 + */ +#define LL_RESERVED_SPACE(dev) (((dev)->hard_header_len&~15) + 16) + /* * Network device statistics. Akin to the 2.0 ether stats but * with byte counters. @@ -478,6 +483,7 @@ extern int dev_queue_xmit(struct sk_buff *skb); extern int register_netdevice(struct net_device *dev); extern int unregister_netdevice(struct net_device *dev); +extern void synchronize_net(void); extern int register_netdevice_notifier(struct notifier_block *nb); extern int unregister_netdevice_notifier(struct notifier_block *nb); extern int dev_new_index(void); diff -Nru a/include/linux/netlink.h b/include/linux/netlink.h --- a/include/linux/netlink.h Thu May 8 10:41:37 2003 +++ b/include/linux/netlink.h Thu May 8 10:41:37 2003 @@ -7,6 +7,7 @@ #define NETLINK_FIREWALL 3 /* Firewalling hook */ #define NETLINK_TCPDIAG 4 /* TCP socket monitoring */ #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ +#define NETLINK_XFRM 6 /* ipsec */ #define NETLINK_ARPD 8 #define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */ #define NETLINK_IP6_FW 13 @@ -86,6 +87,8 @@ =20 #ifdef __KERNEL__ =20 +#include + struct netlink_skb_parms { struct ucred creds; /* Skb credentials */ @@ -107,8 +110,8 @@ extern struct sock *netlink_kernel_create(int unit, void (*input)(struct s= ock *sk, int len)); extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int = err); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pi= d, int nonblock); -extern void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32= pid, - __u32 group, int allocation); +extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 = pid, + __u32 group, int allocation); extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int = code); extern int netlink_register_notifier(struct notifier_block *nb); extern int netlink_unregister_notifier(struct notifier_block *nb); diff -Nru a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/pfkeyv2.h Thu May 8 10:41:38 2003 @@ -0,0 +1,329 @@ +/* PF_KEY user interface, this is defined by rfc2367 so + * do not make arbitrary modifications or else this header + * file will not be compliant. + */ + +#ifndef _LINUX_PFKEY2_H +#define _LINUX_PFKEY2_H + +#include + +#define PF_KEY_V2 2 +#define PFKEYV2_REVISION 199806L + +struct sadb_msg { + uint8_t sadb_msg_version; + uint8_t sadb_msg_type; + uint8_t sadb_msg_errno; + uint8_t sadb_msg_satype; + uint16_t sadb_msg_len; + uint16_t sadb_msg_reserved; + uint32_t sadb_msg_seq; + uint32_t sadb_msg_pid; +} __attribute__((packed)); +/* sizeof(struct sadb_msg) =3D=3D 16 */ + +struct sadb_ext { + uint16_t sadb_ext_len; + uint16_t sadb_ext_type; +} __attribute__((packed)); +/* sizeof(struct sadb_ext) =3D=3D 4 */ + +struct sadb_sa { + uint16_t sadb_sa_len; + uint16_t sadb_sa_exttype; + uint32_t sadb_sa_spi; + uint8_t sadb_sa_replay; + uint8_t sadb_sa_state; + uint8_t sadb_sa_auth; + uint8_t sadb_sa_encrypt; + uint32_t sadb_sa_flags; +} __attribute__((packed)); +/* sizeof(struct sadb_sa) =3D=3D 16 */ + +struct sadb_lifetime { + uint16_t sadb_lifetime_len; + uint16_t sadb_lifetime_exttype; + uint32_t sadb_lifetime_allocations; + uint64_t sadb_lifetime_bytes; + uint64_t sadb_lifetime_addtime; + uint64_t sadb_lifetime_usetime; +} __attribute__((packed)); +/* sizeof(struct sadb_lifetime) =3D=3D 32 */ + +struct sadb_address { + uint16_t sadb_address_len; + uint16_t sadb_address_exttype; + uint8_t sadb_address_proto; + uint8_t sadb_address_prefixlen; + uint16_t sadb_address_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_address) =3D=3D 8 */ + +struct sadb_key { + uint16_t sadb_key_len; + uint16_t sadb_key_exttype; + uint16_t sadb_key_bits; + uint16_t sadb_key_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_key) =3D=3D 8 */ + +struct sadb_ident { + uint16_t sadb_ident_len; + uint16_t sadb_ident_exttype; + uint16_t sadb_ident_type; + uint16_t sadb_ident_reserved; + uint64_t sadb_ident_id; +} __attribute__((packed)); +/* sizeof(struct sadb_ident) =3D=3D 16 */ + +struct sadb_sens { + uint16_t sadb_sens_len; + uint16_t sadb_sens_exttype; + uint32_t sadb_sens_dpd; + uint8_t sadb_sens_sens_level; + uint8_t sadb_sens_sens_len; + uint8_t sadb_sens_integ_level; + uint8_t sadb_sens_integ_len; + uint32_t sadb_sens_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_sens) =3D=3D 16 */ + +/* followed by: + uint64_t sadb_sens_bitmap[sens_len]; + uint64_t sadb_integ_bitmap[integ_len]; */ + +struct sadb_prop { + uint16_t sadb_prop_len; + uint16_t sadb_prop_exttype; + uint8_t sadb_prop_replay; + uint8_t sadb_prop_reserved[3]; +} __attribute__((packed)); +/* sizeof(struct sadb_prop) =3D=3D 8 */ + +/* followed by: + struct sadb_comb sadb_combs[(sadb_prop_len + + sizeof(uint64_t) - sizeof(struct sadb_prop)) / + sizeof(strut sadb_comb)]; */ + +struct sadb_comb { + uint8_t sadb_comb_auth; + uint8_t sadb_comb_encrypt; + uint16_t sadb_comb_flags; + uint16_t sadb_comb_auth_minbits; + uint16_t sadb_comb_auth_maxbits; + uint16_t sadb_comb_encrypt_minbits; + uint16_t sadb_comb_encrypt_maxbits; + uint32_t sadb_comb_reserved; + uint32_t sadb_comb_soft_allocations; + uint32_t sadb_comb_hard_allocations; + uint64_t sadb_comb_soft_bytes; + uint64_t sadb_comb_hard_bytes; + uint64_t sadb_comb_soft_addtime; + uint64_t sadb_comb_hard_addtime; + uint64_t sadb_comb_soft_usetime; + uint64_t sadb_comb_hard_usetime; +} __attribute__((packed)); +/* sizeof(struct sadb_comb) =3D=3D 72 */ + +struct sadb_supported { + uint16_t sadb_supported_len; + uint16_t sadb_supported_exttype; + uint32_t sadb_supported_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_supported) =3D=3D 8 */ + +/* followed by: + struct sadb_alg sadb_algs[(sadb_supported_len + + sizeof(uint64_t) - sizeof(struct sadb_supported)) / + sizeof(struct sadb_alg)]; */ + +struct sadb_alg { + uint8_t sadb_alg_id; + uint8_t sadb_alg_ivlen; + uint16_t sadb_alg_minbits; + uint16_t sadb_alg_maxbits; + uint16_t sadb_alg_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_alg) =3D=3D 8 */ + +struct sadb_spirange { + uint16_t sadb_spirange_len; + uint16_t sadb_spirange_exttype; + uint32_t sadb_spirange_min; + uint32_t sadb_spirange_max; + uint32_t sadb_spirange_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_spirange) =3D=3D 16 */ + +struct sadb_x_kmprivate { + uint16_t sadb_x_kmprivate_len; + uint16_t sadb_x_kmprivate_exttype; + u_int32_t sadb_x_kmprivate_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_x_kmprivate) =3D=3D 8 */ + +struct sadb_x_sa2 { + uint16_t sadb_x_sa2_len; + uint16_t sadb_x_sa2_exttype; + uint8_t sadb_x_sa2_mode; + uint8_t sadb_x_sa2_reserved1; + uint16_t sadb_x_sa2_reserved2; + uint32_t sadb_x_sa2_sequence; + uint32_t sadb_x_sa2_reqid; +} __attribute__((packed)); +/* sizeof(struct sadb_x_sa2) =3D=3D 16 */ + +struct sadb_x_policy { + uint16_t sadb_x_policy_len; + uint16_t sadb_x_policy_exttype; + uint16_t sadb_x_policy_type; + uint8_t sadb_x_policy_dir; + uint8_t sadb_x_policy_reserved; + uint32_t sadb_x_policy_id; + uint32_t sadb_x_policy_reserved2; +} __attribute__((packed)); +/* sizeof(struct sadb_x_policy) =3D=3D 16 */ + +struct sadb_x_ipsecrequest { + uint16_t sadb_x_ipsecrequest_len; + uint16_t sadb_x_ipsecrequest_proto; + uint8_t sadb_x_ipsecrequest_mode; + uint8_t sadb_x_ipsecrequest_level; + uint16_t sadb_x_ipsecrequest_reqid; +} __attribute__((packed)); +/* sizeof(struct sadb_x_ipsecrequest) =3D=3D 16 */ + +/* This defines the TYPE of Nat Traversal in use. Currently only one + * type of NAT-T is supported, draft-ietf-ipsec-udp-encaps-06 + */ +struct sadb_x_nat_t_type { + uint16_t sadb_x_nat_t_type_len; + uint16_t sadb_x_nat_t_type_exttype; + uint8_t sadb_x_nat_t_type_type; + uint8_t sadb_x_nat_t_type_reserved[3]; +} __attribute__((packed)); +/* sizeof(struct sadb_x_nat_t_type) =3D=3D 8 */ + +/* Pass a NAT Traversal port (Source or Dest port) */ +struct sadb_x_nat_t_port { + uint16_t sadb_x_nat_t_port_len; + uint16_t sadb_x_nat_t_port_exttype; + uint16_t sadb_x_nat_t_port_port; + uint16_t sadb_x_nat_t_port_reserved; +} __attribute__((packed)); +/* sizeof(struct sadb_x_nat_t_port) =3D=3D 8 */ + +/* Message types */ +#define SADB_RESERVED 0 +#define SADB_GETSPI 1 +#define SADB_UPDATE 2 +#define SADB_ADD 3 +#define SADB_DELETE 4 +#define SADB_GET 5 +#define SADB_ACQUIRE 6 +#define SADB_REGISTER 7 +#define SADB_EXPIRE 8 +#define SADB_FLUSH 9 +#define SADB_DUMP 10 +#define SADB_X_PROMISC 11 +#define SADB_X_PCHANGE 12 +#define SADB_X_SPDUPDATE 13 +#define SADB_X_SPDADD 14 +#define SADB_X_SPDDELETE 15 +#define SADB_X_SPDGET 16 +#define SADB_X_SPDACQUIRE 17 +#define SADB_X_SPDDUMP 18 +#define SADB_X_SPDFLUSH 19 +#define SADB_X_SPDSETIDX 20 +#define SADB_X_SPDEXPIRE 21 +#define SADB_X_SPDDELETE2 22 +#define SADB_X_NAT_T_NEW_MAPPING 23 +#define SADB_MAX 23 + +/* Security Association flags */ +#define SADB_SAFLAGS_PFS 1 + +/* Security Association states */ +#define SADB_SASTATE_LARVAL 0 +#define SADB_SASTATE_MATURE 1 +#define SADB_SASTATE_DYING 2 +#define SADB_SASTATE_DEAD 3 +#define SADB_SASTATE_MAX 3 + +/* Security Association types */ +#define SADB_SATYPE_UNSPEC 0 +#define SADB_SATYPE_AH 2 +#define SADB_SATYPE_ESP 3 +#define SADB_SATYPE_RSVP 5 +#define SADB_SATYPE_OSPFV2 6 +#define SADB_SATYPE_RIPV2 7 +#define SADB_SATYPE_MIP 8 +#define SADB_X_SATYPE_IPCOMP 9 +#define SADB_SATYPE_MAX 9 + +/* Authentication algorithms */ +#define SADB_AALG_NONE 0 +#define SADB_AALG_MD5HMAC 2 +#define SADB_AALG_SHA1HMAC 3 +#define SADB_X_AALG_SHA2_256HMAC 5 +#define SADB_X_AALG_SHA2_384HMAC 6 +#define SADB_X_AALG_SHA2_512HMAC 7 +#define SADB_X_AALG_RIPEMD160HMAC 8 +#define SADB_X_AALG_NULL 251 /* kame */ +#define SADB_AALG_MAX 251 + +/* Encryption algorithms */ +#define SADB_EALG_NONE 0 +#define SADB_EALG_DESCBC 1 +#define SADB_EALG_3DESCBC 2 +#define SADB_X_EALG_CASTCBC 6 +#define SADB_X_EALG_BLOWFISHCBC 7 +#define SADB_EALG_NULL 11 +#define SADB_X_EALG_AESCBC 12 +#define SADB_EALG_MAX 12 + +/* Compression algorithms */ +#define SADB_X_CALG_NONE 0 +#define SADB_X_CALG_OUI 1 +#define SADB_X_CALG_DEFLATE 2 +#define SADB_X_CALG_LZS 3 +#define SADB_X_CALG_LZJH 4 +#define SADB_X_CALG_MAX 4 + +/* Extension Header values */ +#define SADB_EXT_RESERVED 0 +#define SADB_EXT_SA 1 +#define SADB_EXT_LIFETIME_CURRENT 2 +#define SADB_EXT_LIFETIME_HARD 3 +#define SADB_EXT_LIFETIME_SOFT 4 +#define SADB_EXT_ADDRESS_SRC 5 +#define SADB_EXT_ADDRESS_DST 6 +#define SADB_EXT_ADDRESS_PROXY 7 +#define SADB_EXT_KEY_AUTH 8 +#define SADB_EXT_KEY_ENCRYPT 9 +#define SADB_EXT_IDENTITY_SRC 10 +#define SADB_EXT_IDENTITY_DST 11 +#define SADB_EXT_SENSITIVITY 12 +#define SADB_EXT_PROPOSAL 13 +#define SADB_EXT_SUPPORTED_AUTH 14 +#define SADB_EXT_SUPPORTED_ENCRYPT 15 +#define SADB_EXT_SPIRANGE 16 +#define SADB_X_EXT_KMPRIVATE 17 +#define SADB_X_EXT_POLICY 18 +#define SADB_X_EXT_SA2 19 +/* The next four entries are for setting up NAT Traversal */ +#define SADB_X_EXT_NAT_T_TYPE 20 +#define SADB_X_EXT_NAT_T_SPORT 21 +#define SADB_X_EXT_NAT_T_DPORT 22 +#define SADB_X_EXT_NAT_T_OA 23 +#define SADB_EXT_MAX 23 + +/* Identity Extension values */ +#define SADB_IDENTTYPE_RESERVED 0 +#define SADB_IDENTTYPE_PREFIX 1 +#define SADB_IDENTTYPE_FQDN 2 +#define SADB_IDENTTYPE_USERFQDN 3 +#define SADB_IDENTTYPE_MAX 3 + +#endif /* !(_LINUX_PFKEY2_H) */ diff -Nru a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h --- a/include/linux/rtnetlink.h Thu May 8 10:41:37 2003 +++ b/include/linux/rtnetlink.h Thu May 8 10:41:37 2003 @@ -198,10 +198,11 @@ RTA_MULTIPATH, RTA_PROTOINFO, RTA_FLOW, - RTA_CACHEINFO + RTA_CACHEINFO, + RTA_SESSION, }; =20 -#define RTA_MAX RTA_CACHEINFO +#define RTA_MAX RTA_SESSION =20 #define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(st= ruct rtmsg)))) #define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg)) @@ -284,6 +285,25 @@ =20 #define RTAX_MAX RTAX_REORDERING =20 +struct rta_session +{ + __u8 proto; + + union { + struct { + __u16 sport; + __u16 dport; + } ports; + + struct { + __u8 type; + __u8 code; + __u16 ident; + } icmpt; + + __u32 spi; + } u; +}; =20 =20 /********************************************************* @@ -559,7 +579,7 @@ extern struct rtnetlink_link * rtnetlink_links[NPROTO]; extern int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callb= ack *cb); extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int ech= o); -extern int rtnetlink_put_metrics(struct sk_buff *skb, unsigned *metrics); +extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); =20 extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, con= st void *data); =20 diff -Nru a/include/linux/skbuff.h b/include/linux/skbuff.h --- a/include/linux/skbuff.h Thu May 8 10:41:36 2003 +++ b/include/linux/skbuff.h Thu May 8 10:41:36 2003 @@ -165,7 +165,8 @@ unsigned char *raw; } mac; =20 - struct dst_entry *dst; + struct dst_entry *dst; + struct sec_path *sp; =20 /*=20 * This is the control buffer. It is free to use for every @@ -178,7 +179,7 @@ unsigned int len; /* Length of actual data */ unsigned int data_len; unsigned int csum; /* Checksum */ - unsigned char __unused, /* Dead field, may be reused */ + unsigned char local_df, cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type, /* Packet class */ ip_summed; /* Driver fed us an IP checksum */ @@ -755,6 +756,15 @@ static inline unsigned int skb_headlen(const struct sk_buff *skb) { return skb->len - skb->data_len; +} + +static inline int skb_pagelen(const struct sk_buff *skb) +{ + int i, len =3D 0; + + for (i =3D (int)skb_shinfo(skb)->nr_frags - 1; i >=3D 0; i--) + len +=3D skb_shinfo(skb)->frags[i].size; + return len + skb_headlen(skb); } =20 #define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) out_of_li= ne_bug(); } while (0) diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Thu May 8 10:41:36 2003 +++ b/include/linux/sysctl.h Thu May 8 10:41:36 2003 @@ -343,6 +343,8 @@ NET_IPV4_CONF_TAG=3D12, NET_IPV4_CONF_ARPFILTER=3D13, NET_IPV4_CONF_MEDIUM_ID=3D14, + NET_IPV4_CONF_NOXFRM=3D15, + NET_IPV4_CONF_NOPOLICY=3D16, }; =20 /* /proc/sys/net/ipv6 */ diff -Nru a/include/linux/udp.h b/include/linux/udp.h --- a/include/linux/udp.h Thu May 8 10:41:37 2003 +++ b/include/linux/udp.h Thu May 8 10:41:37 2003 @@ -17,6 +17,9 @@ #ifndef _LINUX_UDP_H #define _LINUX_UDP_H =20 +#include +#include +#include =20 struct udphdr { __u16 source; @@ -25,5 +28,11 @@ __u16 check; }; =20 +/* UDP socket options */ +#define UDP_CORK 1 /* Never send partially complete segments */ +#define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */ + +/* UDP encapsulation types */ +#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */ =20 #endif /* _LINUX_UDP_H */ diff -Nru a/include/linux/xfrm.h b/include/linux/xfrm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/xfrm.h Thu May 8 10:41:38 2003 @@ -0,0 +1,217 @@ +#ifndef _LINUX_XFRM_H +#define _LINUX_XFRM_H + +#include + +/* All of the structures in this file may not change size as they are + * passed into the kernel from userspace via netlink sockets. + */ + +/* Structure to encapsulate addresses. I do not want to use + * "standard" structure. My apologies. + */ +typedef union +{ + __u32 a4; + __u32 a6[4]; +} xfrm_address_t; + +/* Ident of a specific xfrm_state. It is used on input to lookup + * the state by (spi,daddr,ah/esp) or to store information about + * spi, protocol and tunnel address on output. + */ +struct xfrm_id +{ + xfrm_address_t daddr; + __u32 spi; + __u8 proto; +}; + +/* Selector, used as selector both on policy rules (SPD) and SAs. */ + +struct xfrm_selector +{ + xfrm_address_t daddr; + xfrm_address_t saddr; + __u16 dport; + __u16 dport_mask; + __u16 sport; + __u16 sport_mask; + __u8 prefixlen_d; + __u8 prefixlen_s; + __u8 proto; + int ifindex; + uid_t user; +}; + +#define XFRM_INF (~(u64)0) + +struct xfrm_lifetime_cfg +{ + __u64 soft_byte_limit; + __u64 hard_byte_limit; + __u64 soft_packet_limit; + __u64 hard_packet_limit; + __u64 soft_add_expires_seconds; + __u64 hard_add_expires_seconds; + __u64 soft_use_expires_seconds; + __u64 hard_use_expires_seconds; +}; + +struct xfrm_lifetime_cur +{ + __u64 bytes; + __u64 packets; + __u64 add_time; + __u64 use_time; +}; + +struct xfrm_replay_state +{ + __u32 oseq; + __u32 seq; + __u32 bitmap; +}; + +struct xfrm_algo { + char alg_name[64]; + int alg_key_len; /* in bits */ + char alg_key[0]; +}; + +struct xfrm_stats { + __u32 replay_window; + __u32 replay; + __u32 integrity_failed; +}; + +enum +{ + XFRM_POLICY_IN =3D 0, + XFRM_POLICY_OUT =3D 1, + XFRM_POLICY_FWD =3D 2, + XFRM_POLICY_MAX =3D 3 +}; + +enum +{ + XFRM_SHARE_ANY, /* No limitations */ + XFRM_SHARE_SESSION, /* For this session only */ + XFRM_SHARE_USER, /* For this user only */ + XFRM_SHARE_UNIQUE /* Use once */ +}; + +/* Netlink configuration messages. */ +#define XFRM_MSG_BASE 0x10 + +#define XFRM_MSG_NEWSA (RTM_BASE + 0) +#define XFRM_MSG_DELSA (RTM_BASE + 1) +#define XFRM_MSG_GETSA (RTM_BASE + 2) + +#define XFRM_MSG_NEWPOLICY (RTM_BASE + 3) +#define XFRM_MSG_DELPOLICY (RTM_BASE + 4) +#define XFRM_MSG_GETPOLICY (RTM_BASE + 5) + +#define XFRM_MSG_ALLOCSPI (RTM_BASE + 6) +#define XFRM_MSG_ACQUIRE (RTM_BASE + 7) +#define XFRM_MSG_EXPIRE (RTM_BASE + 8) + +#define XFRM_MSG_MAX (XFRM_MSG_EXPIRE+1) + +struct xfrm_user_tmpl { + struct xfrm_id id; + xfrm_address_t saddr; + __u16 reqid; + __u8 mode; + __u8 share; + __u8 optional; + __u32 aalgos; + __u32 ealgos; + __u32 calgos; +}; + +struct xfrm_encap_tmpl { + __u16 encap_type; + __u16 encap_sport; + __u16 encap_dport; +}; + +/* Netlink message attributes. */ +enum xfrm_attr_type_t { + XFRMA_UNSPEC, + XFRMA_ALG_AUTH, /* struct xfrm_algo */ + XFRMA_ALG_CRYPT, /* struct xfrm_algo */ + XFRMA_ALG_COMP, /* struct xfrm_algo */ + XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */ + XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */ + +#define XFRMA_MAX XFRMA_TMPL +}; + +struct xfrm_usersa_info { + struct xfrm_selector sel; + struct xfrm_id id; + struct xfrm_lifetime_cfg lft; + struct xfrm_lifetime_cur curlft; + struct xfrm_stats stats; + __u32 seq; + __u16 family; + __u16 reqid; + __u8 mode; /* 0=3Dtransport,1=3Dtunnel */ + __u8 replay_window; +}; + +struct xfrm_usersa_id { + xfrm_address_t saddr; + __u32 spi; + __u16 family; + __u8 proto; +}; + +struct xfrm_userspi_info { + struct xfrm_usersa_info info; + __u32 min; + __u32 max; +}; + +struct xfrm_userpolicy_info { + struct xfrm_selector sel; + struct xfrm_lifetime_cfg lft; + struct xfrm_lifetime_cur curlft; + __u32 priority; + __u32 index; + __u16 family; + __u8 dir; + __u8 action; +#define XFRM_POLICY_ALLOW 0 +#define XFRM_POLICY_BLOCK 1 + __u8 flags; +#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */ + __u8 share; +}; + +struct xfrm_userpolicy_id { + struct xfrm_selector sel; + __u32 index; + __u8 dir; +}; + +struct xfrm_user_acquire { + struct xfrm_id id; + xfrm_address_t saddr; + struct xfrm_userpolicy_info policy; + __u32 aalgos; + __u32 ealgos; + __u32 calgos; + __u32 seq; +}; + +struct xfrm_user_expire { + struct xfrm_usersa_info state; + __u8 hard; +}; + +#define XFRMGRP_ACQUIRE 1 +#define XFRMGRP_EXPIRE 2 + +#endif /* _LINUX_XFRM_H */ diff -Nru a/include/net/ah.h b/include/net/ah.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/ah.h Thu May 8 10:41:38 2003 @@ -0,0 +1,32 @@ +#ifndef _NET_AH_H +#define _NET_AH_H + +#include + +struct ah_data +{ + u8 *key; + int key_len; + u8 *work_icv; + int icv_full_len; + int icv_trunc_len; + + void (*icv)(struct ah_data*, + struct sk_buff *skb, u8 *icv); + + struct crypto_tfm *tfm; +}; + +static inline void +ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data) +{ + struct crypto_tfm *tfm =3D ahp->tfm; + + memset(auth_data, 0, ahp->icv_trunc_len); + crypto_hmac_init(tfm, ahp->key, &ahp->key_len); + skb_icv_walk(skb, tfm, 0, skb->len, crypto_hmac_update); + crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_icv); + memcpy(auth_data, ahp->work_icv, ahp->icv_trunc_len); +} + +#endif diff -Nru a/include/net/dn_route.h b/include/net/dn_route.h --- a/include/net/dn_route.h Thu May 8 10:41:36 2003 +++ b/include/net/dn_route.h Thu May 8 10:41:36 2003 @@ -122,7 +122,7 @@ if ((dst =3D sk->dst_cache) && !dst->obsolete) { try_again: skb->dst =3D dst_clone(dst); - dst->output(skb); + dst_output(skb); return; } =20 diff -Nru a/include/net/dst.h b/include/net/dst.h --- a/include/net/dst.h Thu May 8 10:41:38 2003 +++ b/include/net/dst.h Thu May 8 10:41:38 2003 @@ -9,6 +9,7 @@ #define _NET_DST_H =20 #include +#include #include =20 /* @@ -22,6 +23,13 @@ #define DST_GC_INC (5*HZ) #define DST_GC_MAX (120*HZ) =20 +/* Each dst_entry has reference count and sits in some parent list(s). + * When it is removed from parent list, it is "freed" (dst_free). + * After this it enters dead state (dst->obsolete > 0) and if its refcnt + * is zero, it can be destroyed immediately, otherwise it is added + * to gc list and garbage collector periodically checks the refcnt. + */ + struct sk_buff; =20 struct dst_entry @@ -29,22 +37,22 @@ struct dst_entry *next; atomic_t __refcnt; /* client references */ int __use; + struct dst_entry *child; struct net_device *dev; int obsolete; int flags; #define DST_HOST 1 +#define DST_NOXFRM 2 +#define DST_NOPOLICY 4 +#define DST_NOHASH 8 unsigned long lastuse; unsigned long expires; =20 - unsigned mxlock; - unsigned pmtu; - unsigned window; - unsigned rtt; - unsigned rttvar; - unsigned ssthresh; - unsigned cwnd; - unsigned advmss; - unsigned reordering; + unsigned short header_len; /* more space at head required */ + unsigned short trailer_len; /* space to reserve at tail */ + + u32 metrics[RTAX_MAX]; + struct dst_entry *path; =20 unsigned long rate_last; /* rate limiting for ICMP */ unsigned long rate_tokens; @@ -53,6 +61,7 @@ =20 struct neighbour *neighbour; struct hh_cache *hh; + struct xfrm_state *xfrm; =20 int (*input)(struct sk_buff*); int (*output)(struct sk_buff*); @@ -75,11 +84,11 @@ =20 int (*gc)(void); struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); - struct dst_entry * (*reroute)(struct dst_entry *, - struct sk_buff *); void (*destroy)(struct dst_entry *); struct dst_entry * (*negative_advice)(struct dst_entry *); void (*link_failure)(struct sk_buff *); + void (*update_pmtu)(struct dst_entry *dst, u32 mtu); + int (*get_mss)(struct dst_entry *dst, u32 mtu); int entry_size; =20 atomic_t entries; @@ -88,6 +97,33 @@ =20 #ifdef __KERNEL__ =20 +static inline u32 +dst_metric(struct dst_entry *dst, int metric) +{ + return dst->metrics[metric-1]; +} + +static inline u32 +dst_path_metric(struct dst_entry *dst, int metric) +{ + return dst->path->metrics[metric-1]; +} + +static inline u32 +dst_pmtu(struct dst_entry *dst) +{ + u32 mtu =3D dst_path_metric(dst, RTAX_MTU); + /* Yes, _exactly_. This is paranoia. */ + barrier(); + return mtu; +} + +static inline int +dst_metric_locked(struct dst_entry *dst, int metric) +{ + return dst_metric(dst, RTAX_LOCK) & (1<__refcnt); @@ -104,22 +140,40 @@ static inline void dst_release(struct dst_entry * dst) { - if (dst) + if (dst) { + if (atomic_read(&dst->__refcnt) < 1) { + printk("BUG: dst underflow %d: %p\n", + atomic_read(&dst->__refcnt), + current_text_addr()); + } atomic_dec(&dst->__refcnt); + } +} + +/* Children define the path of the packet through the + * Linux networking. Thus, destinations are stackable. + */ + +static inline struct dst_entry *dst_pop(struct dst_entry *dst) +{ + struct dst_entry *child =3D dst_clone(dst->child); + + dst_release(dst); + return child; } =20 extern void * dst_alloc(struct dst_ops * ops); extern void __dst_free(struct dst_entry * dst); -extern void dst_destroy(struct dst_entry * dst); +extern struct dst_entry *dst_destroy(struct dst_entry * dst); =20 -static inline -void dst_free(struct dst_entry * dst) +static inline void dst_free(struct dst_entry * dst) { if (dst->obsolete > 1) return; if (!atomic_read(&dst->__refcnt)) { - dst_destroy(dst); - return; + dst =3D dst_destroy(dst); + if (!dst) + return; } __dst_free(dst); } @@ -155,8 +209,42 @@ dst->expires =3D expires; } =20 +/* Output packet to network from transport. */ +static inline int dst_output(struct sk_buff *skb) +{ + int err; + + for (;;) { + err =3D skb->dst->output(skb); + + if (likely(err =3D=3D 0)) + return err; + if (unlikely(err !=3D NET_XMIT_BYPASS)) + return err; + } +} + +/* Input packet from network to transport. */ +static inline int dst_input(struct sk_buff *skb) +{ + int err; + + for (;;) { + err =3D skb->dst->input(skb); + + if (likely(err =3D=3D 0)) + return err; + /* Oh, Jamal... Seems, I will not forgive you this mess. :-) */ + if (unlikely(err !=3D NET_XMIT_BYPASS)) + return err; + } +} + extern void dst_init(void); =20 +struct flowi; +extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, + struct sock *sk, int flags); #endif =20 #endif /* _NET_DST_H */ diff -Nru a/include/net/esp.h b/include/net/esp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/esp.h Thu May 8 10:41:38 2003 @@ -0,0 +1,54 @@ +#ifndef _NET_ESP_H +#define _NET_ESP_H + +#include + +struct esp_data +{ + /* Confidentiality */ + struct { + u8 *key; /* Key */ + int key_len; /* Key length */ + u8 *ivec; /* ivec buffer */ + /* 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 + * >=3D crypto_tfm_alg_ivsize(tfm). */ + int ivlen; + int padlen; /* 0..255 */ + struct crypto_tfm *tfm; /* crypto handle */ + } conf; + + /* Integrity. It is active when icv_full_len !=3D 0 */ + struct { + u8 *key; /* Key */ + int key_len; /* Length of the key */ + u8 *work_icv; + int icv_full_len; + int icv_trunc_len; + void (*icv)(struct esp_data*, + struct sk_buff *skb, + int offset, int len, u8 *icv); + struct crypto_tfm *tfm; + } auth; +}; + +extern int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int o= ffset, int len); +extern int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff = **trailer); +extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len); + +static inline void +esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset, + int len, u8 *auth_data) +{ + struct crypto_tfm *tfm =3D esp->auth.tfm; + char *icv =3D esp->auth.work_icv; + + memset(auth_data, 0, esp->auth.icv_trunc_len); + crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len); + skb_icv_walk(skb, tfm, offset, len, crypto_hmac_update); + crypto_hmac_final(tfm, esp->auth.key, &esp->auth.key_len, icv); + memcpy(auth_data, icv, esp->auth.icv_trunc_len); +} + +#endif diff -Nru a/include/net/flow.h b/include/net/flow.h --- a/include/net/flow.h Thu May 8 10:41:37 2003 +++ b/include/net/flow.h Thu May 8 10:41:37 2003 @@ -1,6 +1,6 @@ /* * - * Flow based forwarding rules (usage: firewalling, etc) + * Generic internet FLOW. * */ =20 @@ -8,12 +8,16 @@ #define _NET_FLOW_H =20 struct flowi { - int proto; /* {TCP, UDP, ICMP} */ + int oif; + int iif; =20 union { struct { __u32 daddr; __u32 saddr; + __u32 fwmark; + __u8 tos; + __u8 scope; } ip4_u; =09 struct { @@ -27,9 +31,12 @@ #define fl6_flowlabel nl_u.ip6_u.flowlabel #define fl4_dst nl_u.ip4_u.daddr #define fl4_src nl_u.ip4_u.saddr +#define fl4_fwmark nl_u.ip4_u.fwmark +#define fl4_tos nl_u.ip4_u.tos +#define fl4_scope nl_u.ip4_u.scope =20 - int oif; - + __u8 proto; + __u8 flags; union { struct { __u16 sport; @@ -41,61 +48,12 @@ __u8 code; } icmpt; =20 - unsigned long data; + __u32 spi; } uli_u; +#define fl_ip_sport uli_u.ports.sport +#define fl_ip_dport uli_u.ports.dport +#define fl_icmp_type uli_u.icmpt.type +#define fl_icmp_code uli_u.icmpt.code +#define fl_ipsec_spi uli_u.spi }; - -#define FLOWR_NODECISION 0 /* rule not appliable to flow */ -#define FLOWR_SELECT 1 /* flow must follow this rule */ -#define FLOWR_CLEAR 2 /* priority level clears flow */ -#define FLOWR_ERROR 3 - -struct fl_acc_args { - int type; - - -#define FL_ARG_FORWARD 1 -#define FL_ARG_ORIGIN 2 - - union { - struct sk_buff *skb; - struct { - struct sock *sk; - struct flowi *flow; - } fl_o; - } fl_u; -}; - - -struct pkt_filter { - atomic_t refcnt; - unsigned int offset; - __u32 value; - __u32 mask; - struct pkt_filter *next; -}; - -#define FLR_INPUT 1 -#define FLR_OUTPUT 2 - -struct flow_filter { - int type; - union { - struct pkt_filter *filter; - struct sock *sk; - } u; -}; - -struct flow_rule { - struct flow_rule_ops *ops; - unsigned char private[0]; -}; - -struct flow_rule_ops { - int (*accept)(struct rt6_info *rt, - struct rt6_info *rule, - struct fl_acc_args *args, - struct rt6_info **nrt); -}; - #endif diff -Nru a/include/net/ip.h b/include/net/ip.h --- a/include/net/ip.h Thu May 8 10:41:37 2003 +++ b/include/net/ip.h Thu May 8 10:41:37 2003 @@ -46,6 +46,7 @@ #define IPSKB_MASQUERADED 1 #define IPSKB_TRANSLATED 2 #define IPSKB_FORWARDED 4 +#define IPSKB_XFRM_TUNNEL_SIZE 8 }; =20 struct ipcm_cookie @@ -97,16 +98,19 @@ extern void ip_send_check(struct iphdr *ip); extern int ip_queue_xmit(struct sk_buff *skb); extern void ip_init(void); -extern int ip_build_xmit(struct sock *sk, - int getfrag (const void *, - char *, - unsigned int, - unsigned int), - const void *frag, - unsigned length, - struct ipcm_cookie *ipc, - struct rtable *rt, - int flags); +extern int ip_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, int len, + int odd, struct sk_buff *skb), + void *from, int len, int protolen, + struct ipcm_cookie *ipc, + struct rtable *rt, + unsigned int flags); +extern int ip_generic_getfrag(void *from, char *to, int offset, int len, = int odd, struct sk_buff *skb); +extern ssize_t ip_append_page(struct sock *sk, struct page *page, + int offset, size_t size, int flags); +extern int ip_push_pending_frames(struct sock *sk); +extern void ip_flush_pending_frames(struct sock *sk); + =20 /* * Map a multicast IP onto multicast MAC for type Token Ring. @@ -126,8 +130,7 @@ } =20 struct ip_reply_arg { - struct iovec iov[2]; =20 - int n_iov; /* redundant */ + struct iovec iov[1]; =20 u32 csum;=20 int csumoffset; /* u16 offset of csum in iov[0].iov_base */ /* -1 if not needed */=20 @@ -159,14 +162,6 @@ extern int sysctl_ip_default_ttl; =20 #ifdef CONFIG_INET -static inline int ip_send(struct sk_buff *skb) -{ - if (skb->len > skb->dst->pmtu) - return ip_fragment(skb, ip_finish_output); - else - return ip_finish_output(skb); -} - /* The function in 2.2 was invalid, producing wrong result for * check=3D0xFEFF. It was noticed by Arthur Skawina _year_ ago. --ANK(0006= 25) */ static inline @@ -183,7 +178,7 @@ { return (sk->protinfo.af_inet.pmtudisc =3D=3D IP_PMTUDISC_DO || (sk->protinfo.af_inet.pmtudisc =3D=3D IP_PMTUDISC_WANT && - !(dst->mxlock&(1< - -struct ip6_fw_rule { - struct flow_rule flowr; - struct ip6_fw_rule *next; - struct ip6_fw_rule *prev; - struct flowi info; - unsigned long policy; -}; - -#endif - -#endif diff -Nru a/include/net/ip6_route.h b/include/net/ip6_route.h --- a/include/net/ip6_route.h Thu May 8 10:41:37 2003 +++ b/include/net/ip6_route.h Thu May 8 10:41:37 2003 @@ -60,6 +60,8 @@ struct in6_addr *saddr, int oif, int flags); =20 +extern struct rt6_info *ip6_dst_alloc(void); + /* * support functions for ND * diff -Nru a/include/net/ip_fib.h b/include/net/ip_fib.h --- a/include/net/ip_fib.h Thu May 8 10:41:37 2003 +++ b/include/net/ip_fib.h Thu May 8 10:41:37 2003 @@ -17,6 +17,7 @@ #define _NET_IP_FIB_H =20 #include +#include =20 struct kern_rta { @@ -65,7 +66,7 @@ int fib_protocol; u32 fib_prefsrc; u32 fib_priority; - unsigned fib_metrics[RTAX_MAX]; + u32 fib_metrics[RTAX_MAX]; #define fib_mtu fib_metrics[RTAX_MTU-1] #define fib_window fib_metrics[RTAX_WINDOW-1] #define fib_rtt fib_metrics[RTAX_RTT-1] @@ -117,7 +118,7 @@ { unsigned char tb_id; unsigned tb_stamp; - int (*tb_lookup)(struct fib_table *tb, const struct rt_key *key, struct = fib_result *res); + int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct f= ib_result *res); int (*tb_insert)(struct fib_table *table, struct rtmsg *r, struct kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req); @@ -130,7 +131,7 @@ int (*tb_get_info)(struct fib_table *table, char *buf, int first, int count); void (*tb_select_default)(struct fib_table *table, - const struct rt_key *key, struct fib_result *res); + const struct flowi *flp, struct fib_result *res); =20 unsigned char tb_data[0]; }; @@ -152,18 +153,18 @@ return fib_get_table(id); } =20 -static inline int fib_lookup(const struct rt_key *key, struct fib_result *= res) +static inline int fib_lookup(const struct flowi *flp, struct fib_result *r= es) { - if (local_table->tb_lookup(local_table, key, res) && - main_table->tb_lookup(main_table, key, res)) + if (local_table->tb_lookup(local_table, flp, res) && + main_table->tb_lookup(main_table, flp, res)) return -ENETUNREACH; return 0; } =20 -static inline void fib_select_default(const struct rt_key *key, struct fib= _result *res) +static inline void fib_select_default(const struct flowi *flp, struct fib_= result *res) { if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope =3D=3D RT_SCOPE_LINK) - main_table->tb_select_default(main_table, key, res); + main_table->tb_select_default(main_table, flp, res); } =20 #else /* CONFIG_IP_MULTIPLE_TABLES */ @@ -171,7 +172,7 @@ #define main_table (fib_tables[RT_TABLE_MAIN]) =20 extern struct fib_table * fib_tables[RT_TABLE_MAX+1]; -extern int fib_lookup(const struct rt_key *key, struct fib_result *res); +extern int fib_lookup(const struct flowi *flp, struct fib_result *res); extern struct fib_table *__fib_new_table(int id); extern void fib_rule_put(struct fib_rule *r); =20 @@ -191,7 +192,7 @@ return fib_tables[id] ? : __fib_new_table(id); } =20 -extern void fib_select_default(const struct rt_key *key, struct fib_result= *res); +extern void fib_select_default(const struct flowi *flp, struct fib_result = *res); =20 #endif /* CONFIG_IP_MULTIPLE_TABLES */ =20 @@ -204,13 +205,13 @@ extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)= ; extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, struct net_device *dev, u32 *spec_dst, u32 *itag); -extern void fib_select_multipath(const struct rt_key *key, struct fib_resu= lt *res); +extern void fib_select_multipath(const struct flowi *flp, struct fib_resul= t *res); =20 /* Exported by fib_semantics.c */ extern int ip_fib_check_default(u32 gw, struct net_device *dev); extern void fib_release_info(struct fib_info *); extern int fib_semantic_match(int type, struct fib_info *, - const struct rt_key *, struct fib_result*); + const struct flowi *, struct fib_result*); extern struct fib_info *fib_create_info(const struct rtmsg *r, struct kern= _rta *rta, const struct nlmsghdr *, int *err); extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *, struct kern_rt= a *rta, struct fib_info *fi); diff -Nru a/include/net/ipip.h b/include/net/ipip.h --- a/include/net/ipip.h Thu May 8 10:41:38 2003 +++ b/include/net/ipip.h Thu May 8 10:41:38 2003 @@ -34,7 +34,7 @@ ip_select_ident(iph, &rt->u.dst, NULL); \ ip_send_check(iph); \ \ - err =3D NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, do_ip= _send); \ + err =3D NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_o= utput);\ if (err =3D=3D NET_XMIT_SUCCESS || err =3D=3D NET_XMIT_CN) { \ stats->tx_bytes +=3D pkt_len; \ stats->tx_packets++; \ diff -Nru a/include/net/ipv6.h b/include/net/ipv6.h --- a/include/net/ipv6.h Thu May 8 10:41:37 2003 +++ b/include/net/ipv6.h Thu May 8 10:41:37 2003 @@ -198,11 +198,7 @@ =20 extern int ip6_call_ra_chain(struct sk_buff *skb, int sel); =20 -extern int ipv6_reassembly(struct sk_buff **skb, int); - extern int ipv6_parse_hopopts(struct sk_buff *skb, int); - -extern int ipv6_parse_exthdrs(struct sk_buff **skb, int); =20 extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct i= pv6_txoptions *opt); =20 diff -Nru a/include/net/protocol.h b/include/net/protocol.h --- a/include/net/protocol.h Thu May 8 10:41:37 2003 +++ b/include/net/protocol.h Thu May 8 10:41:37 2003 @@ -30,7 +30,7 @@ #include #endif =20 -#define MAX_INET_PROTOS 32 /* Must be a power of 2 */ +#define MAX_INET_PROTOS 256 /* Must be a power of 2 */ =20 =20 /* This is used to register protocols. */ @@ -38,29 +38,23 @@ { int (*handler)(struct sk_buff *skb); void (*err_handler)(struct sk_buff *skb, u32 info); - struct inet_protocol *next; - unsigned char protocol; - unsigned char copy:1; - void *data; - const char *name; + int no_policy; }; =20 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) struct inet6_protocol=20 { - int (*handler)(struct sk_buff *skb); + int (*handler)(struct sk_buff **skb, unsigned int *nhoffp); =20 void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info); - struct inet6_protocol *next; - unsigned char protocol; - unsigned char copy:1; - void *data; - const char *name; + unsigned int flags; /* INET6_PROTO_xxx */ }; =20 +#define INET6_PROTO_NOPOLICY 0x1 +#define INET6_PROTO_FINAL 0x2 #endif =20 /* This is used to register socket interfaces for IP protocols. */ @@ -93,14 +87,14 @@ extern struct list_head inetsw6[SOCK_MAX]; #endif =20 -extern void inet_add_protocol(struct inet_protocol *prot); -extern int inet_del_protocol(struct inet_protocol *prot); +extern int inet_add_protocol(struct inet_protocol *prot, unsigned char num= ); +extern int inet_del_protocol(struct inet_protocol *prot, unsigned char num= ); extern void inet_register_protosw(struct inet_protosw *p); extern void inet_unregister_protosw(struct inet_protosw *p); =20 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) -extern void inet6_add_protocol(struct inet6_protocol *prot); -extern int inet6_del_protocol(struct inet6_protocol *prot); +extern int inet6_add_protocol(struct inet6_protocol *prot, unsigned char n= um); +extern int inet6_del_protocol(struct inet6_protocol *prot, unsigned char n= um); extern void inet6_register_protosw(struct inet_protosw *p); extern void inet6_unregister_protosw(struct inet_protosw *p); #endif diff -Nru a/include/net/raw.h b/include/net/raw.h --- a/include/net/raw.h Thu May 8 10:41:37 2003 +++ b/include/net/raw.h Thu May 8 10:41:37 2003 @@ -37,6 +37,6 @@ unsigned long raddr, unsigned long laddr, int dif); =20 -extern struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, i= nt hash); +extern void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)= ; =20 #endif /* _RAW_H */ diff -Nru a/include/net/rawv6.h b/include/net/rawv6.h --- a/include/net/rawv6.h Thu May 8 10:41:37 2003 +++ b/include/net/rawv6.h Thu May 8 10:41:37 2003 @@ -7,9 +7,7 @@ extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE]; extern rwlock_t raw_v6_lock; =20 -extern struct sock * ipv6_raw_deliver(struct sk_buff *skb, - int nexthdr); - +extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr); =20 extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, struct in6_addr *loc_addr, struct in6_addr *rmt_addr); diff -Nru a/include/net/route.h b/include/net/route.h --- a/include/net/route.h Thu May 8 10:41:36 2003 +++ b/include/net/route.h Thu May 8 10:41:36 2003 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -45,19 +46,6 @@ =20 #define RT_CONN_FLAGS(sk) (RT_TOS(sk->protinfo.af_inet.tos) | sk->localr= oute) =20 -struct rt_key -{ - __u32 dst; - __u32 src; - int iif; - int oif; -#ifdef CONFIG_IP_ROUTE_FWMARK - __u32 fwmark; -#endif - __u8 tos; - __u8 scope; -}; - struct inet_peer; struct rtable { @@ -78,7 +66,7 @@ __u32 rt_gateway; =20 /* Cache lookup keys */ - struct rt_key key; + struct flowi fl; =20 /* Miscellaneous cached information */ __u32 rt_spec_dst; /* RFC1122 specific destination */ @@ -124,10 +112,11 @@ u32 src, u8 tos, struct net_device *dev); extern void ip_rt_advice(struct rtable **rp, int advice); extern void rt_cache_flush(int how); -extern int ip_route_output_key(struct rtable **, const struct rt_key *key= ); +extern int __ip_route_output_key(struct rtable **, const struct flowi *fl= p); +extern int ip_route_output_key(struct rtable **, struct flowi *flp); +extern int ip_route_output_flow(struct rtable **rp, struct flowi *flp, st= ruct sock *sk, int flags); extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, stru= ct net_device *devin); extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short = new_mtu); -extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu); extern void ip_rt_send_redirect(struct sk_buff *skb); =20 extern unsigned inet_addr_type(u32 addr); @@ -136,16 +125,6 @@ extern void ip_rt_get_source(u8 *src, struct rtable *rt); extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb); =20 -/* Deprecated: use ip_route_output_key directly */ -static inline int ip_route_output(struct rtable **rp, - u32 daddr, u32 saddr, u32 tos, int oif) -{ - struct rt_key key =3D { dst:daddr, src:saddr, oif:oif, tos:tos }; - - return ip_route_output_key(rp, &key); -} - - static inline void ip_rt_put(struct rtable * rt) { if (rt) @@ -161,17 +140,47 @@ return ip_tos2prio[IPTOS_TOS(tos)>>1]; } =20 -static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u= 32 tos, int oif) -{ +static inline int ip_route_connect(struct rtable **rp, u32 dst, + u32 src, u32 tos, int oif, u8 protocol, + u16 sport, u16 dport, struct sock *sk) +{ + struct flowi fl =3D { .oif =3D oif, + .nl_u =3D { .ip4_u =3D { .daddr =3D dst, + .saddr =3D src, + .tos =3D tos } }, + .proto =3D protocol, + .uli_u =3D { .ports =3D + { .sport =3D sport, + .dport =3D dport } } }; + int err; - err =3D ip_route_output(rp, dst, src, tos, oif); - if (err || (dst && src)) - return err; - dst =3D (*rp)->rt_dst; - src =3D (*rp)->rt_src; - ip_rt_put(*rp); - *rp =3D NULL; - return ip_route_output(rp, dst, src, tos, oif); + if (!dst || !src) { + err =3D __ip_route_output_key(rp, &fl); + if (err) + return err; + fl.fl4_dst =3D (*rp)->rt_dst; + fl.fl4_src =3D (*rp)->rt_src; + ip_rt_put(*rp); + *rp =3D NULL; + } + return ip_route_output_flow(rp, &fl, sk, 0); +} + +static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dpo= rt, + struct sock *sk) +{ + if (sport !=3D (*rp)->fl.fl_ip_sport || + dport !=3D (*rp)->fl.fl_ip_dport) { + struct flowi fl; + + memcpy(&fl, &(*rp)->fl, sizeof(fl)); + fl.fl_ip_sport =3D sport; + fl.fl_ip_dport =3D dport; + ip_rt_put(*rp); + *rp =3D NULL; + return ip_route_output_flow(rp, &fl, sk, 0); + } + return 0; } =20 extern void rt_bind_peer(struct rtable *rt, int create); diff -Nru a/include/net/sock.h b/include/net/sock.h --- a/include/net/sock.h Thu May 8 10:41:37 2003 +++ b/include/net/sock.h Thu May 8 10:41:37 2003 @@ -221,7 +221,24 @@ int mc_index; /* Multicast device index */ __u32 mc_addr; struct ip_mc_socklist *mc_list; /* Group array */ + struct page *sndmsg_page; /* Cached page for sendmsg */ + u32 sndmsg_off; /* Cached offset for sendmsg */ + /* + * Following members are used to retain the infomation to build + * an ip header on each ip fragmentation while the socket is corked. + */ + struct { + unsigned int flags; + unsigned int fragsize; + struct ip_options *opt; + struct rtable *rt; + int length; /* Total length of all frames */ + u32 addr; + } cork; }; + +#define IPCORK_OPT 1 /* ip-options has been held in ipcork.opt */ + #endif =20 #if defined(CONFIG_PPPOE) || defined (CONFIG_PPPOE_MODULE) @@ -247,6 +264,14 @@ #define pppoe_relay proto.pppoe.relay #endif =20 +#if defined(CONFIG_NET_KEY) || defined(CONFIG_NET_KEY_MODULE) +struct pfkey_opt { + int registered; + int promisc; +}; +#define pfkey_sk(__sk) ((__sk)->protinfo.pf_key) +#endif + /* This defines a selective acknowledgement block. */ struct tcp_sack_block { __u32 start_seq; @@ -304,6 +329,7 @@ __u16 mss_cache; /* Cached effective mss, not including SACKS */ __u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ __u16 ext_header_len; /* Network protocol overhead (IP/IPv6 options) */ + __u16 ext2_header_len;/* Options depending on route */ __u8 ca_state; /* State of fast-retransmit machine */ __u8 retransmits; /* Number of unrecovered RTO timeouts. */ =20 @@ -344,8 +370,6 @@ =20 struct tcp_func *af_specific; /* Operations which are AF_INET{4,6} speci= fic */ struct sk_buff *send_head; /* Front of stuff to transmit */ - struct page *sndmsg_page; /* Cached page for sendmsg */ - u32 sndmsg_off; /* Cached offset for sendmsg */ =20 __u32 rcv_wnd; /* Current receiver window */ __u32 rcv_wup; /* rcv_nxt on last window update sent */ @@ -431,6 +455,20 @@ unsigned long last_synq_overflow;=20 }; =20 +struct udp_opt { + int pending; /* Any pending frames ? */ + unsigned int corkflag; /* Cork is required */ + __u16 encap_type; /* Is this an Encapsulation socket? */ + /* + * Following members retains the infomation to create a UDP header + * when the socket is uncorked. + */ + u32 saddr; /* source address */ + u32 daddr; /* destination address */ + __u16 sport; /* source port */ + __u16 dport; /* destination port */ + __u16 len; /* total length of pending frames */ +}; =09 /* * This structure really needs to be cleaned up. @@ -526,6 +564,7 @@ wait_queue_head_t *sleep; /* Sock wait queue */ struct dst_entry *dst_cache; /* Destination cache */ rwlock_t dst_lock; + struct xfrm_policy *policy[2]; atomic_t rmem_alloc; /* Receive queue bytes committed */ struct sk_buff_head receive_queue; /* Incoming packets */ atomic_t wmem_alloc; /* Transmit queue bytes committed */ @@ -586,6 +625,7 @@ =20 union { struct tcp_opt af_tcp; + struct udp_opt af_udp; #if defined(CONFIG_INET) || defined (CONFIG_INET_MODULE) struct raw_opt tp_raw4; #endif @@ -597,6 +637,8 @@ #endif /* CONFIG_SPX */ =20 } tp_pinfo; +#define tcp_sk(sk) (&(sk)->tp_pinfo.af_tcp) +#define udp_sk(sk) (&(sk)->tp_pinfo.af_udp) =20 int err, err_soft; /* Soft holds errors that don't cause failure but are the cause @@ -667,8 +709,11 @@ #if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE) struct wanpipe_opt *af_wanpipe; #endif +#if defined(CONFIG_NET_KEY) || defined(CONFIG_NET_KEY_MODULE) + struct pfkey_opt *pf_key; +#endif } protinfo; =09 - +#define inet_sk(sk) (&(sk)->protinfo.af_inet) =20 /* This part is used for the timeout functions. */ struct timer_list timer; /* This is the sock cleanup timer. */ @@ -732,6 +777,8 @@ int (*recvmsg)(struct sock *sk, struct msghdr *msg, int len, int noblock, int flags,=20 int *addr_len); + int (*sendpage)(struct sock *sk, struct page *page, + int offset, size_t size, int flags); int (*bind)(struct sock *sk,=20 struct sockaddr *uaddr, int addr_len); =20 diff -Nru a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h Thu May 8 10:41:36 2003 +++ b/include/net/tcp.h Thu May 8 10:41:36 2003 @@ -907,9 +907,12 @@ struct dst_entry *dst =3D __sk_dst_get(sk); int mss_now =3D tp->mss_cache;=20 =20 - if (dst && dst->pmtu !=3D tp->pmtu_cookie) - mss_now =3D tcp_sync_mss(sk, dst->pmtu); - + if (dst) { + u32 mtu =3D dst_pmtu(dst); + if (mtu !=3D tp->pmtu_cookie || + tp->ext2_header_len !=3D dst->header_len) + mss_now =3D tcp_sync_mss(sk, mtu); + } if (tp->eff_sacks) mss_now -=3D (TCPOLEN_SACK_BASE_ALIGNED + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); diff -Nru a/include/net/transp_v6.h b/include/net/transp_v6.h --- a/include/net/transp_v6.h Thu May 8 10:41:37 2003 +++ b/include/net/transp_v6.h Thu May 8 10:41:37 2003 @@ -15,6 +15,14 @@ =20 struct flowi; =20 +/* extention headers */ +extern void ipv6_hopopts_init(void); +extern void ipv6_rthdr_init(void); +extern void ipv6_frag_init(void); +extern void ipv6_nodata_init(void); +extern void ipv6_destopt_init(void); + +/* transport protocols */ extern void rawv6_init(void); extern void udpv6_init(void); extern void tcpv6_init(void); diff -Nru a/include/net/xfrm.h b/include/net/xfrm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/xfrm.h Thu May 8 10:41:38 2003 @@ -0,0 +1,824 @@ +#ifndef _NET_XFRM_H +#define _NET_XFRM_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define XFRM_ALIGN8(len) (((len) + 7) & ~7) + +extern struct semaphore xfrm_cfg_sem; + +/* Organization of SPD aka "XFRM rules" + ------------------------------------ + + Basic objects: + - policy rule, struct xfrm_policy (=3DSPD entry) + - bundle of transformations, struct dst_entry =3D=3D struct xfrm_dst (= =3DSA bundle) + - instance of a transformer, struct xfrm_state (=3DSA) + - template to clone xfrm_state, struct xfrm_tmpl + + SPD is plain linear list of xfrm_policy rules, ordered by priority. + (To be compatible with existing pfkeyv2 implementations, + many rules with priority of 0x7fffffff are allowed to exist and + such rules are ordered in an unpredictable way, thanks to bsd folks.) + + Lookup is plain linear search until the first match with selector. + + If "action" is "block", then we prohibit the flow, otherwise: + if "xfrms_nr" is zero, the flow passes untransformed. Otherwise, + policy entry has list of up to XFRM_MAX_DEPTH transformations, + described by templates xfrm_tmpl. Each template is resolved + to a complete xfrm_state (see below) and we pack bundle of transformati= ons + to a dst_entry returned to requestor. + + dst -. xfrm .-> xfrm_state #1 + |---. child .-> dst -. xfrm .-> xfrm_state #2 + |---. child .-> dst -. xfrm .-> xfrm_state #3 + |---. child .-> NULL + + Bundles are cached at xrfm_policy struct (field ->bundles). + + + Resolution of xrfm_tmpl + ----------------------- + Template contains: + 1. ->mode Mode: transport or tunnel + 2. ->id.proto Protocol: AH/ESP/IPCOMP + 3. ->id.daddr Remote tunnel endpoint, ignored for transport mode. + Q: allow to resolve security gateway? + 4. ->id.spi If not zero, static SPI. + 5. ->saddr Local tunnel endpoint, ignored for transport mode. + 6. ->algos List of allowed algos. Plain bitmask now. + Q: ealgos, aalgos, calgos. What a mess... + 7. ->share Sharing mode. + Q: how to implement private sharing mode? To add struct sock* to + flow id? + + Having this template we search through SAD searching for entries + with appropriate mode/proto/algo, permitted by selector. + If no appropriate entry found, it is requested from key manager. + + PROBLEMS: + Q: How to find all the bundles referring to a physical path for + PMTU discovery? Seems, dst should contain list of all parents... + and enter to infinite locking hierarchy disaster. + No! It is easier, we will not search for them, let them find us. + We add genid to each dst plus pointer to genid of raw IP route, + pmtu disc will update pmtu on raw IP route and increase its genid. + dst_check() will see this for top level and trigger resyncing + metrics. Plus, it will be made via sk->dst_cache. Solved. + */ + +/* Full description of state of transformer. */ +struct xfrm_state +{ + /* Note: bydst is re-used during gc */ + struct list_head bydst; + struct list_head byspi; + + atomic_t refcnt; + spinlock_t lock; + + struct xfrm_id id; + struct xfrm_selector sel; + + /* Key manger bits */ + struct { + u8 state; + u8 dying; + u32 seq; + } km; + + /* Parameters of this state. */ + struct { + u8 mode; + u8 replay_window; + u8 aalgo, ealgo, calgo; + u16 reqid; + u16 family; + xfrm_address_t saddr; + int header_len; + int trailer_len; + } props; + + struct xfrm_lifetime_cfg lft; + + /* Data for transformer */ + struct xfrm_algo *aalg; + struct xfrm_algo *ealg; + struct xfrm_algo *calg; + + /* Data for encapsulator */ + struct xfrm_encap_tmpl *encap; + + /* State for replay detection */ + struct xfrm_replay_state replay; + + /* Statistics */ + struct xfrm_stats stats; + + struct xfrm_lifetime_cur curlft; + struct timer_list timer; + + /* Reference to data common to all the instances of this + * transformer. */ + struct xfrm_type *type; + + /* Private data of this transformer, format is opaque, + * interpreted by xfrm_type methods. */ + void *data; +}; + +enum { + XFRM_STATE_VOID, + XFRM_STATE_ACQ, + XFRM_STATE_VALID, + XFRM_STATE_ERROR, + XFRM_STATE_EXPIRED, + XFRM_STATE_DEAD +}; + +struct xfrm_type; +struct xfrm_dst; +struct xfrm_policy_afinfo { + unsigned short family; + rwlock_t lock; + struct xfrm_type_map *type_map; + struct dst_ops *dst_ops; + void (*garbage_collect)(void); + int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); + struct dst_entry *(*find_bundle)(struct flowi *fl, struct rtable *rt, str= uct xfrm_policy *policy); + int (*bundle_create)(struct xfrm_policy *policy,=20 + struct xfrm_state **xfrm,=20 + int nx, + struct flowi *fl,=20 + struct dst_entry **dst_p); + void (*decode_session)(struct sk_buff *skb, + struct flowi *fl); +}; + +extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); +extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo= ); +extern struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short fa= mily); +extern void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); + +#define XFRM_ACQ_EXPIRES 30 + +struct xfrm_tmpl; +struct xfrm_state_afinfo { + unsigned short family; + rwlock_t lock; + struct list_head *state_bydst; + struct list_head *state_byspi; + void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, + struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr); + struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 pro= to); + struct xfrm_state *(*find_acq)(u8 mode, u16 reqid, u8 proto,=20 + xfrm_address_t *daddr, xfrm_address_t *saddr,=20 + int create); +}; + +extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); +extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); +extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short fami= ly); +extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); + +struct xfrm_decap_state; +struct xfrm_type +{ + char *description; + struct module *owner; + __u8 proto; + + int (*init_state)(struct xfrm_state *x, void *args); + void (*destructor)(struct xfrm_state *); + int (*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_= buff *skb); + int (*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struc= t sk_buff *skb); + int (*output)(struct sk_buff *skb); + /* Estimate maximal size of result of transformation of a dgram */ + u32 (*get_max_size)(struct xfrm_state *, int size); +}; + +struct xfrm_type_map { + rwlock_t lock; + struct xfrm_type *map[256]; +}; + +extern int xfrm_register_type(struct xfrm_type *type, unsigned short famil= y); +extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short fam= ily); +extern struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family); +extern void xfrm_put_type(struct xfrm_type *type); + +struct xfrm_tmpl +{ +/* id in template is interpreted as: + * daddr - destination of tunnel, may be zero for transport mode. + * spi - zero to acquire spi. Not zero if spi is static, then + * daddr must be fixed too. + * proto - AH/ESP/IPCOMP + */ + struct xfrm_id id; + +/* Source address of tunnel. Ignored, if it is not a tunnel. */ + xfrm_address_t saddr; + + __u16 reqid; + +/* Mode: transport/tunnel */ + __u8 mode; + +/* Sharing mode: unique, this session only, this user only etc. */ + __u8 share; + +/* May skip this transfomration if no SA is found */ + __u8 optional; + +/* Bit mask of algos allowed for acquisition */ + __u32 aalgos; + __u32 ealgos; + __u32 calgos; +}; + +#define XFRM_MAX_DEPTH 4 + +struct xfrm_policy +{ + struct xfrm_policy *next; + + /* This lock only affects elements except for entry. */ + rwlock_t lock; + atomic_t refcnt; + struct timer_list timer; + + u32 priority; + u32 index; + struct xfrm_selector selector; + struct xfrm_lifetime_cfg lft; + struct xfrm_lifetime_cur curlft; + struct dst_entry *bundles; + __u16 family; + __u8 action; + __u8 flags; + __u8 dead; + __u8 xfrm_nr; + struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; +}; + +struct xfrm_mgr +{ + struct list_head list; + char *id; + int (*notify)(struct xfrm_state *x, int event); + int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_po= licy *xp, int dir); + struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int = len, int *dir); + int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sp= ort); +}; + +extern int xfrm_register_km(struct xfrm_mgr *km); +extern int xfrm_unregister_km(struct xfrm_mgr *km); + + +#define XFRM_FLOWCACHE_HASH_SIZE 1024 + +static inline u32 __flow_hash4(struct flowi *fl) +{ + u32 hash =3D fl->fl4_src ^ fl->fl_ip_sport; + + hash =3D ((hash & 0xF0F0F0F0) >> 4) | ((hash & 0x0F0F0F0F) << 4); + + hash ^=3D fl->fl4_dst ^ fl->fl_ip_dport; + hash ^=3D (hash >> 10); + hash ^=3D (hash >> 20); + return hash & (XFRM_FLOWCACHE_HASH_SIZE-1); +} + +static inline u32 __flow_hash6(struct flowi *fl) +{ + u32 hash =3D fl->fl6_src->s6_addr32[2] ^ + fl->fl6_src->s6_addr32[3] ^=20 + fl->fl_ip_sport; + + hash =3D ((hash & 0xF0F0F0F0) >> 4) | ((hash & 0x0F0F0F0F) << 4); + + hash ^=3D fl->fl6_dst->s6_addr32[2] ^ + fl->fl6_dst->s6_addr32[3] ^=20 + fl->fl_ip_dport; + hash ^=3D (hash >> 10); + hash ^=3D (hash >> 20); + return hash & (XFRM_FLOWCACHE_HASH_SIZE-1); +} + +static inline u32 flow_hash(struct flowi *fl, unsigned short family) +{ + switch (family) { + case AF_INET: + return __flow_hash4(fl); + case AF_INET6: + return __flow_hash6(fl); + } + return 0; /*XXX*/ +} + +extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; + +static inline void xfrm_pol_hold(struct xfrm_policy *policy) +{ + if (policy) + atomic_inc(&policy->refcnt); +} + +extern void __xfrm_policy_destroy(struct xfrm_policy *policy); + +static inline void xfrm_pol_put(struct xfrm_policy *policy) +{ + if (atomic_dec_and_test(&policy->refcnt)) + __xfrm_policy_destroy(policy); +} + +#define XFRM_DST_HSIZE 1024 + +static __inline__ +unsigned __xfrm4_dst_hash(xfrm_address_t *addr) +{ + unsigned h; + h =3D ntohl(addr->a4); + h =3D (h ^ (h>>16)) % XFRM_DST_HSIZE; + return h; +} + +static __inline__ +unsigned __xfrm6_dst_hash(xfrm_address_t *addr) +{ + unsigned h; + h =3D ntohl(addr->a6[2]^addr->a6[3]); + h =3D (h ^ (h>>16)) % XFRM_DST_HSIZE; + return h; +} + +static __inline__ +unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family) +{ + switch (family) { + case AF_INET: + return __xfrm4_dst_hash(addr); + case AF_INET6: + return __xfrm6_dst_hash(addr); + } + return 0; +} + +static __inline__ +unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto) +{ + unsigned h; + h =3D ntohl(addr->a4^spi^proto); + h =3D (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE; + return h; +} + +static __inline__ +unsigned __xfrm6_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto) +{ + unsigned h; + h =3D ntohl(addr->a6[2]^addr->a6[3]^spi^proto); + h =3D (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE; + return h; +} + +static __inline__ +unsigned xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned s= hort family) +{ + switch (family) { + case AF_INET: + return __xfrm4_spi_hash(addr, spi, proto); + case AF_INET6: + return __xfrm6_spi_hash(addr, spi, proto); + } + return 0; /*XXX*/ +} + +extern void __xfrm_state_destroy(struct xfrm_state *); + +static inline void xfrm_state_put(struct xfrm_state *x) +{ + if (atomic_dec_and_test(&x->refcnt)) + __xfrm_state_destroy(x); +} + +static inline void xfrm_state_hold(struct xfrm_state *x) +{ + atomic_inc(&x->refcnt); +} + +static __inline__ int addr_match(void *token1, void *token2, int prefixlen= ) +{ + __u32 *a1 =3D token1; + __u32 *a2 =3D token2; + int pdw; + int pbi; + + pdw =3D prefixlen >> 5; /* num of whole __u32 in prefix */ + pbi =3D prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ + + if (pdw) + if (memcmp(a1, a2, pdw << 2)) + return 0; + + if (pbi) { + __u32 mask; + + mask =3D htonl((0xffffffff) << (32 - pbi)); + + if ((a1[pdw] ^ a2[pdw]) & mask) + return 0; + } + + return 1; +} + +static inline int +__xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl) +{ + return addr_match(&fl->fl4_dst, &sel->daddr, sel->prefixlen_d) && + addr_match(&fl->fl4_src, &sel->saddr, sel->prefixlen_s) && + !((fl->fl_ip_dport^sel->dport)&sel->dport_mask) && + !((fl->fl_ip_sport^sel->sport)&sel->sport_mask) && + (fl->proto =3D=3D sel->proto || !sel->proto) && + (fl->oif =3D=3D sel->ifindex || !sel->ifindex); +} + +static inline int +__xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl) +{ + return addr_match(fl->fl6_dst, &sel->daddr, sel->prefixlen_d) && + addr_match(fl->fl6_src, &sel->saddr, sel->prefixlen_s) && + !((fl->fl_ip_dport^sel->dport)&sel->dport_mask) && + !((fl->fl_ip_sport^sel->sport)&sel->sport_mask) && + (fl->proto =3D=3D sel->proto || !sel->proto) && + (fl->oif =3D=3D sel->ifindex || !sel->ifindex); +} + +static inline int +xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, + unsigned short family) +{ + switch (family) { + case AF_INET: + return __xfrm4_selector_match(sel, fl); + case AF_INET6: + return __xfrm6_selector_match(sel, fl); + } + return 0; +} + +/* placeholder until xfrm6_tunnel.c is written */ +static inline int xfrm6_tunnel_check_size(struct sk_buff *skb) +{ return 0; } + +/* A struct encoding bundle of transformations to apply to some set of flo= w. + * + * dst->child points to the next element of bundle. + * dst->xfrm points to an instanse of transformer. + * + * Due to unfortunate limitations of current routing cache, which we + * have no time to fix, it mirrors struct rtable and bound to the same + * routing key, including saddr,daddr. However, we can have many of + * bundles differing by session id. All the bundles grow from a parent + * policy rule. + */ +struct xfrm_dst +{ + union { + struct xfrm_dst *next; + struct dst_entry dst; + struct rtable rt; + struct rt6_info rt6; + } u; +}; + +/* Decapsulation state, used by the input to store data during + * decapsulation procedure, to be used later (during the policy + * check + */ +struct xfrm_decap_state { + char decap_data[20]; + __u16 decap_type; +}; =20 + +struct sec_decap_state { + struct xfrm_state *xvec; + struct xfrm_decap_state decap; +}; + +struct sec_path +{ + kmem_cache_t *pool; + atomic_t refcnt; + int len; + struct sec_decap_state x[XFRM_MAX_DEPTH]; +}; + +static inline struct sec_path * +secpath_get(struct sec_path *sp) +{ + if (sp) + atomic_inc(&sp->refcnt); + return sp; +} + +extern void __secpath_destroy(struct sec_path *sp); + +static inline void +secpath_put(struct sec_path *sp) +{ + if (sp && atomic_dec_and_test(&sp->refcnt)) + __secpath_destroy(sp); +} + +static inline int +__xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x) +{ + return (tmpl->saddr.a4 && + tmpl->saddr.a4 !=3D x->props.saddr.a4); +} + +static inline int +__xfrm6_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x) +{ + return (!ipv6_addr_any((struct in6_addr*)&tmpl->saddr) && + ipv6_addr_cmp((struct in6_addr *)&tmpl->saddr, (struct in6_addr*)&x->pr= ops.saddr)); +} + +static inline int +xfrm_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned= short family) +{ + switch (family) { + case AF_INET: + return __xfrm4_state_addr_cmp(tmpl, x); + case AF_INET6: + return __xfrm6_state_addr_cmp(tmpl, x); + } + return !0; +} + +extern int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb= , unsigned short family); + +static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_bu= ff *skb, unsigned short family) +{ + if (sk && sk->policy[XFRM_POLICY_IN]) + return __xfrm_policy_check(sk, dir, skb, family); + =09 + return !xfrm_policy_list[dir] || + (skb->dst->flags & DST_NOPOLICY) || + __xfrm_policy_check(sk, dir, skb, family); +} + +static inline int xfrm4_policy_check(struct sock *sk, int dir, struct sk_b= uff *skb) +{ + return xfrm_policy_check(sk, dir, skb, AF_INET); +} + +static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_b= uff *skb) +{ + return xfrm_policy_check(sk, dir, skb, AF_INET6); +} + + +extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family= ); + +static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short f= amily) +{ + return !xfrm_policy_list[XFRM_POLICY_OUT] || + (skb->dst->flags & DST_NOXFRM) || + __xfrm_route_forward(skb, family); +} + +static inline int xfrm4_route_forward(struct sk_buff *skb) +{ + return xfrm_route_forward(skb, AF_INET); +} + +static inline int xfrm6_route_forward(struct sk_buff *skb) +{ + return xfrm_route_forward(skb, AF_INET6); +} + +extern int __xfrm_sk_clone_policy(struct sock *sk); + +static inline int xfrm_sk_clone_policy(struct sock *sk) +{ + if (unlikely(sk->policy[0] || sk->policy[1])) + return __xfrm_sk_clone_policy(sk); + return 0; +} + +extern void __xfrm_sk_free_policy(struct xfrm_policy *, int dir); + +static inline void xfrm_sk_free_policy(struct sock *sk) +{ + if (unlikely(sk->policy[0] !=3D NULL)) { + __xfrm_sk_free_policy(sk->policy[0], 0); + sk->policy[0] =3D NULL; + } + if (unlikely(sk->policy[1] !=3D NULL)) { + __xfrm_sk_free_policy(sk->policy[1], 1); + sk->policy[1] =3D NULL; + } +} + +static __inline__ +xfrm_address_t *xfrm_flowi_daddr(struct flowi *fl, unsigned short family) +{ + switch (family){ + case AF_INET: + return (xfrm_address_t *)&fl->fl4_dst; + case AF_INET6: + return (xfrm_address_t *)fl->fl6_dst; + } + return NULL; +} + +static __inline__ +xfrm_address_t *xfrm_flowi_saddr(struct flowi *fl, unsigned short family) +{ + switch (family){ + case AF_INET: + return (xfrm_address_t *)&fl->fl4_src; + case AF_INET6: + return (xfrm_address_t *)fl->fl6_src; + } + return NULL; +} + +static __inline__ int +__xfrm4_state_addr_check(struct xfrm_state *x, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + if (daddr->a4 =3D=3D x->id.daddr.a4 && + (saddr->a4 =3D=3D x->props.saddr.a4 || !saddr->a4 || !x->props.saddr.= a4)) + return 1; + return 0; +} + +static __inline__ int +__xfrm6_state_addr_check(struct xfrm_state *x, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + if (!ipv6_addr_cmp((struct in6_addr *)daddr, (struct in6_addr *)&x->id.da= ddr) && + (!ipv6_addr_cmp((struct in6_addr *)saddr, (struct in6_addr *)&x->prop= s.saddr)||=20 + ipv6_addr_any((struct in6_addr *)saddr) ||=20 + ipv6_addr_any((struct in6_addr *)&x->props.saddr))) + return 1; + return 0; +} + +static __inline__ int +xfrm_state_addr_check(struct xfrm_state *x, + xfrm_address_t *daddr, xfrm_address_t *saddr, + unsigned short family) +{ + switch (family) { + case AF_INET: + return __xfrm4_state_addr_check(x, daddr, saddr); + case AF_INET6: + return __xfrm6_state_addr_check(x, daddr, saddr); + } + return 0; +} + +/* + * xfrm algorithm information + */ +struct xfrm_algo_auth_info { + u16 icv_truncbits; + u16 icv_fullbits; +}; + +struct xfrm_algo_encr_info { + u16 blockbits; + u16 defkeybits; +}; + +struct xfrm_algo_comp_info { + u16 threshold; +}; + +struct xfrm_algo_desc { + char *name; + u8 available:1; + union { + struct xfrm_algo_auth_info auth; + struct xfrm_algo_encr_info encr; + struct xfrm_algo_comp_info comp; + } uinfo; + struct sadb_alg desc; +}; + +/* XFRM tunnel handlers. */ +struct xfrm_tunnel { + int (*handler)(struct sk_buff *skb); + void (*err_handler)(struct sk_buff *skb, void *info); +}; + +extern void xfrm_init(void); +extern void xfrm4_init(void); +extern void xfrm4_fini(void); +extern void xfrm6_init(void); +extern void xfrm6_fini(void); +extern void xfrm_state_init(void); +extern void xfrm4_state_init(void); +extern void xfrm4_state_fini(void); +extern void xfrm6_state_init(void); +extern void xfrm6_state_fini(void); + +extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int,= void*), void *); +extern struct xfrm_state *xfrm_state_alloc(void); +extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_addr= ess_t *saddr,=20 + struct flowi *fl, struct xfrm_tmpl *tmpl, + struct xfrm_policy *pol, int *err, + unsigned short family); +extern int xfrm_state_check_expire(struct xfrm_state *x); +extern void xfrm_state_insert(struct xfrm_state *x); +extern int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *sk= b); +extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi= , u8 proto, unsigned short family); +extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); +extern void xfrm_state_delete(struct xfrm_state *x); +extern void xfrm_state_flush(u8 proto); +extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); +extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); +extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi= *fl); +extern int xfrm_check_output(struct xfrm_state *x, struct sk_buff *skb, un= signed short family); +extern int xfrm4_rcv(struct sk_buff *skb); +extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type); +extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); +extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); +extern int xfrm4_tunnel_check_size(struct sk_buff *skb); +extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); +extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset= , int dir); +extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int = optlen); + +void xfrm_policy_init(void); +void xfrm4_policy_init(void); +void xfrm6_policy_init(void); +struct xfrm_policy *xfrm_policy_alloc(int gfp); +extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, vo= id*), void *); +struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl, unsigned= short family); +int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); +struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel)= ; +struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); +void xfrm_policy_flush(void); +u32 xfrm_get_acqseq(void); +void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); +struct xfrm_state * xfrm_find_acq(u8 mode, u16 reqid, u8 proto,=20 + xfrm_address_t *daddr, xfrm_address_t *saddr,=20 + int create, unsigned short family); +extern void xfrm_policy_flush(void); +extern void xfrm_policy_kill(struct xfrm_policy *); +extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_pol= icy *pol); +extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,= struct flowi *fl); +extern int xfrm_flush_bundles(struct xfrm_state *x); +extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsign= ed short family); + +extern wait_queue_head_t km_waitq; +extern void km_warn_expired(struct xfrm_state *x); +extern void km_expired(struct xfrm_state *x); +extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_= policy *pol); +extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u1= 6 sport); + +extern void xfrm4_input_init(void); +extern void xfrm6_input_init(void); +extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *= seq); + +extern void xfrm_probe_algs(void); +extern int xfrm_count_auth_supported(void); +extern int xfrm_count_enc_supported(void); +extern struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx); +extern struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx); +extern struct xfrm_algo_desc *xfrm_calg_get_byidx(unsigned int idx); +extern struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name); +extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name); +extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name); + +struct crypto_tfm; +typedef void (icv_update_fn_t)(struct crypto_tfm *, struct scatterlist *, = unsigned int); + +extern void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm= , + int offset, int len, icv_update_fn_t icv_update); + +#endif /* _NET_XFRM_H */ diff -Nru a/lib/Config.in b/lib/Config.in --- a/lib/Config.in Thu May 8 10:41:37 2003 +++ b/lib/Config.in Thu May 8 10:41:37 2003 @@ -9,12 +9,14 @@ # if [ "$CONFIG_CRAMFS" =3D "y" -o \ "$CONFIG_PPP_DEFLATE" =3D "y" -o \ + "$CONFIG_CRYPTO_DEFLATE" =3D "y" -o \ "$CONFIG_JFFS2_FS" =3D "y" -o \ "$CONFIG_ZISOFS_FS" =3D "y" ]; then define_tristate CONFIG_ZLIB_INFLATE y else if [ "$CONFIG_CRAMFS" =3D "m" -o \ "$CONFIG_PPP_DEFLATE" =3D "m" -o \ + "$CONFIG_CRYPTO_DEFLATE" =3D "m" -o \ "$CONFIG_JFFS2_FS" =3D "m" -o \ "$CONFIG_ZISOFS_FS" =3D "m" ]; then define_tristate CONFIG_ZLIB_INFLATE m @@ -24,10 +26,12 @@ fi =20 if [ "$CONFIG_PPP_DEFLATE" =3D "y" -o \ + "$CONFIG_CRYPTO_DEFLATE" =3D "y" -o \ "$CONFIG_JFFS2_FS" =3D "y" ]; then define_tristate CONFIG_ZLIB_DEFLATE y else if [ "$CONFIG_PPP_DEFLATE" =3D "m" -o \ + "$CONFIG_CRYPTO_DEFLATE" =3D "m" -o \ "$CONFIG_JFFS2_FS" =3D "m" ]; then define_tristate CONFIG_ZLIB_DEFLATE m else diff -Nru a/net/Config.in b/net/Config.in --- a/net/Config.in Thu May 8 10:41:37 2003 +++ b/net/Config.in Thu May 8 10:41:37 2003 @@ -16,9 +16,11 @@ fi bool 'Socket Filtering' CONFIG_FILTER tristate 'Unix domain sockets' CONFIG_UNIX +tristate 'PF_KEY sockets' CONFIG_NET_KEY bool 'TCP/IP networking' CONFIG_INET if [ "$CONFIG_INET" =3D "y" ]; then source net/ipv4/Config.in + source net/xfrm/Config.in if [ "$CONFIG_EXPERIMENTAL" =3D "y" ]; then # IPv6 as module will cause a CRASH if you try to unload it tristate ' The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6 diff -Nru a/net/Makefile b/net/Makefile --- a/net/Makefile Thu May 8 10:41:37 2003 +++ b/net/Makefile Thu May 8 10:41:37 2003 @@ -7,15 +7,15 @@ =20 O_TARGET :=3D network.o =20 -mod-subdirs :=3D ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netl= ink sched core +mod-subdirs :=3D ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netl= ink sched core xfrm export-objs :=3D netsyms.o =20 subdir-y :=3D core ethernet -subdir-m :=3D ipv4 # hum? +subdir-m :=3D ipv4 xfrm # hum? =20 =20 subdir-$(CONFIG_NET) +=3D 802 sched netlink -subdir-$(CONFIG_INET) +=3D ipv4 +subdir-$(CONFIG_INET) +=3D ipv4 xfrm subdir-$(CONFIG_NETFILTER) +=3D ipv4/netfilter subdir-$(CONFIG_UNIX) +=3D unix subdir-$(CONFIG_IPV6) +=3D ipv6 @@ -28,6 +28,7 @@ =20 subdir-$(CONFIG_KHTTPD) +=3D khttpd subdir-$(CONFIG_PACKET) +=3D packet +subdir-$(CONFIG_NET_KEY) +=3D key subdir-$(CONFIG_NET_SCHED) +=3D sched subdir-$(CONFIG_BRIDGE) +=3D bridge subdir-$(CONFIG_IPX) +=3D ipx diff -Nru a/net/atm/clip.c b/net/atm/clip.c --- a/net/atm/clip.c Thu May 8 10:41:37 2003 +++ b/net/atm/clip.c Thu May 8 10:41:37 2003 @@ -509,6 +509,7 @@ struct atmarp_entry *entry; int error; struct clip_vcc *clip_vcc; + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D ip, .tos =3D 1 = } } }; struct rtable *rt; =20 if (vcc->push !=3D clip_push) { @@ -525,7 +526,7 @@ unlink_clip_vcc(clip_vcc); return 0; } - error =3D ip_route_output(&rt,ip,0,1,0); + error =3D ip_route_output_key(&rt,&fl); if (error) return error; neigh =3D __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1); ip_rt_put(rt); diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Thu May 8 10:41:37 2003 +++ b/net/core/dev.c Thu May 8 10:41:37 2003 @@ -912,6 +912,13 @@ return notifier_chain_register(&netdev_chain, nb); } =20 +/* Synchronize with packet receive processing. */ +void synchronize_net(void)=20 +{ + br_write_lock_bh(BR_NETPROTO_LOCK); + br_write_unlock_bh(BR_NETPROTO_LOCK); +} + /** * unregister_netdevice_notifier - unregister a network notifier block * @nb: notifier diff -Nru a/net/core/dst.c b/net/core/dst.c --- a/net/core/dst.c Thu May 8 10:41:37 2003 +++ b/net/core/dst.c Thu May 8 10:41:37 2003 @@ -36,11 +36,11 @@ static unsigned long dst_gc_timer_expires; static unsigned long dst_gc_timer_inc =3D DST_GC_MAX; static void dst_run_gc(unsigned long); +static void ___dst_free(struct dst_entry * dst); =20 static struct timer_list dst_gc_timer =3D { data: DST_GC_MIN, function: dst_run_gc }; =20 - static void dst_run_gc(unsigned long dummy) { int delayed =3D 0; @@ -61,7 +61,25 @@ continue; } *dstp =3D dst->next; - dst_destroy(dst); + + dst =3D dst_destroy(dst); + if (dst) { + /* NOHASH and still referenced. Unless it is already + * on gc list, invalidate it and add to gc list. + * + * Note: this is temporary. Actually, NOHASH dst's + * must be obsoleted when parent is obsoleted. + * But we do not have state "obsoleted, but + * referenced by parent", so it is right. + */ + if (dst->obsolete > 1) + continue; + + ___dst_free(dst); + dst->next =3D *dstp; + *dstp =3D dst; + dstp =3D &dst->next; + } } if (!dst_garbage_list) { dst_gc_timer_inc =3D DST_GC_MAX; @@ -107,6 +125,7 @@ memset(dst, 0, ops->entry_size); dst->ops =3D ops; dst->lastuse =3D jiffies; + dst->path =3D dst; dst->input =3D dst_discard; dst->output =3D dst_blackhole; #if RT_CACHE_DEBUG >=3D 2=20 @@ -116,10 +135,8 @@ return dst; } =20 -void __dst_free(struct dst_entry * dst) +static void ___dst_free(struct dst_entry * dst) { - spin_lock_bh(&dst_lock); - /* The first case (dev=3D=3DNULL) is required, when protocol module is unloaded. */ @@ -128,6 +145,12 @@ dst->output =3D dst_blackhole; } dst->obsolete =3D 2; +} + +void __dst_free(struct dst_entry * dst) +{ + spin_lock_bh(&dst_lock); + ___dst_free(dst); dst->next =3D dst_garbage_list; dst_garbage_list =3D dst; if (dst_gc_timer_inc > DST_GC_INC) { @@ -137,14 +160,19 @@ dst_gc_timer.expires =3D jiffies + dst_gc_timer_expires; add_timer(&dst_gc_timer); } - spin_unlock_bh(&dst_lock); } =20 -void dst_destroy(struct dst_entry * dst) +struct dst_entry *dst_destroy(struct dst_entry * dst) { - struct neighbour *neigh =3D dst->neighbour; - struct hh_cache *hh =3D dst->hh; + struct dst_entry *child; + struct neighbour *neigh; + struct hh_cache *hh; + +again: + neigh =3D dst->neighbour; + hh =3D dst->hh; + child =3D dst->child; =20 dst->hh =3D NULL; if (hh && atomic_dec_and_test(&hh->hh_refcnt)) @@ -165,6 +193,21 @@ atomic_dec(&dst_total); #endif kmem_cache_free(dst->ops->kmem_cachep, dst); + + dst =3D child; + if (dst) { + if (atomic_dec_and_test(&dst->__refcnt)) { + /* We were real parent of this dst, so kill child. */ + if (dst->flags&DST_NOHASH) + goto again; + } else { + /* Child is still referenced, return it for freeing. */ + if (dst->flags&DST_NOHASH) + return dst; + /* Child is still in his hash table */ + } + } + return NULL; } =20 static int dst_dev_event(struct notifier_block *this, unsigned long event,= void *ptr) diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c --- a/net/core/netfilter.c Thu May 8 10:41:37 2003 +++ b/net/core/netfilter.c Thu May 8 10:41:37 2003 @@ -563,13 +563,15 @@ { struct iphdr *iph =3D (*pskb)->nh.iph; struct rtable *rt; - struct rt_key key =3D { dst:iph->daddr, - src:iph->saddr, - oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, - tos:RT_TOS(iph->tos)|RTO_CONN, + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D iph->daddr, + .saddr =3D iph->saddr, + .tos =3D RT_TOS(iph->tos)|RTO_CONN, #ifdef CONFIG_IP_ROUTE_FWMARK - fwmark:(*pskb)->nfmark + .fwmark =3D (*pskb)->nfmark #endif + } }, + .oif =3D (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, }; struct net_device *dev_src =3D NULL; int err; @@ -578,10 +580,10 @@ 0 or a local address; however some non-standard hacks like ipt_REJECT.c:send_reset() can cause packets with foreign saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */ - if(key.src && !(dev_src =3D ip_dev_find(key.src))) - key.src =3D 0; + if(fl.fl4_src && !(dev_src =3D ip_dev_find(fl.fl4_src))) + fl.fl4_src =3D 0; =20 - if ((err=3Dip_route_output_key(&rt, &key)) !=3D 0) { + if ((err=3Dip_route_output_key(&rt, &fl)) !=3D 0) { printk("route_me_harder: ip_route_output_key(dst=3D%u.%u.%u.%u, src=3D%u= .%u.%u.%u, oif=3D%d, tos=3D0x%x, fwmark=3D0x%lx) error %d\n", NIPQUAD(iph->daddr), NIPQUAD(iph->saddr), (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, diff -Nru a/net/core/rtnetlink.c b/net/core/rtnetlink.c --- a/net/core/rtnetlink.c Thu May 8 10:41:37 2003 +++ b/net/core/rtnetlink.c Thu May 8 10:41:37 2003 @@ -128,7 +128,7 @@ return err; } =20 -int rtnetlink_put_metrics(struct sk_buff *skb, unsigned *metrics) +int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) { struct rtattr *mx =3D (struct rtattr*)skb->tail; int i; @@ -136,7 +136,7 @@ RTA_PUT(skb, RTA_METRICS, 0, NULL); for (i=3D0; irta_len =3D skb->tail - (u8*)mx; if (mx->rta_len =3D=3D RTA_LENGTH(0)) diff -Nru a/net/core/skbuff.c b/net/core/skbuff.c --- a/net/core/skbuff.c Thu May 8 10:41:36 2003 +++ b/net/core/skbuff.c Thu May 8 10:41:36 2003 @@ -57,6 +57,7 @@ #include #include #include +#include =20 #include #include @@ -201,6 +202,7 @@ =20 /* Set up other state */ skb->len =3D 0; + skb->local_df =3D 0; skb->cloned =3D 0; skb->data_len =3D 0; =20 @@ -232,6 +234,7 @@ skb->stamp.tv_sec=3D0; /* No idea about time */ skb->dev =3D NULL; skb->dst =3D NULL; + skb->sp =3D NULL; memset(skb->cb, 0, sizeof(skb->cb)); skb->pkt_type =3D PACKET_HOST; /* Default type */ skb->ip_summed =3D 0; @@ -316,6 +319,9 @@ } =20 dst_release(skb->dst); +#ifdef CONFIG_INET + secpath_put(skb->sp); +#endif if(skb->destructor) { if (in_irq()) { printk(KERN_WARNING "Warning: kfree_skb on hard IRQ %p\n", @@ -367,10 +373,15 @@ C(mac); C(dst); dst_clone(n->dst); + C(sp); +#ifdef CONFIG_INET + secpath_get(n->sp); +#endif memcpy(n->cb, skb->cb, sizeof(skb->cb)); C(len); C(data_len); C(csum); + C(local_df); n->cloned =3D 1; C(pkt_type); C(ip_summed); @@ -420,11 +431,15 @@ new->priority=3Dold->priority; new->protocol=3Dold->protocol; new->dst=3Ddst_clone(old->dst); +#ifdef CONFIG_INET + new->sp=3Dsecpath_get(old->sp); +#endif new->h.raw=3Dold->h.raw+offset; new->nh.raw=3Dold->nh.raw+offset; new->mac.raw=3Dold->mac.raw+offset; memcpy(new->cb, old->cb, sizeof(old->cb)); atomic_set(&new->users, 1); + new->local_df=3Dold->local_df; new->pkt_type=3Dold->pkt_type; new->stamp=3Dold->stamp; new->destructor =3D NULL; diff -Nru a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c --- a/net/decnet/dn_nsp_out.c Thu May 8 10:41:38 2003 +++ b/net/decnet/dn_nsp_out.c Thu May 8 10:41:38 2003 @@ -593,7 +593,7 @@ * associations. */ skb->dst =3D dst_clone(dst); - skb->dst->output(skb); + dst_output(skb); } =20 =20 diff -Nru a/net/decnet/dn_route.c b/net/decnet/dn_route.c --- a/net/decnet/dn_route.c Thu May 8 10:41:38 2003 +++ b/net/decnet/dn_route.c Thu May 8 10:41:38 2003 @@ -100,7 +100,6 @@ =20 static int dn_dst_gc(void); static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); -static struct dst_entry *dn_dst_reroute(struct dst_entry *, struct sk_buff= *skb); static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); static void dn_dst_link_failure(struct sk_buff *); static int dn_route_input(struct sk_buff *); @@ -119,7 +118,6 @@ gc_thresh: 128, gc: dn_dst_gc, check: dn_dst_check, - reroute: dn_dst_reroute, negative_advice: dn_dst_negative_advice, link_failure: dn_dst_link_failure, entry_size: sizeof(struct dn_route), @@ -202,12 +200,6 @@ return NULL; } =20 -static struct dst_entry *dn_dst_reroute(struct dst_entry *dst, - struct sk_buff *skb) -{ - return NULL; -} - /* * This is called through sendmsg() when you specify MSG_TRYHARD * and there is already a route in cache. @@ -396,7 +388,7 @@ int err; =20 if ((err =3D dn_route_input(skb)) =3D=3D 0) - return skb->dst->input(skb); + return dst_input(skb); =20 if (decnet_debug_level & 4) { char *devname =3D skb->dev ? skb->dev->name : "???"; @@ -1049,10 +1041,12 @@ RTA_PUT(skb, RTA_SRC, 2, &rt->rt_saddr); if (rt->u.dst.dev) RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); - if (rt->u.dst.window) - RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window); - if (rt->u.dst.rtt) - RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt); + if (dst_metric(&rt->u.dst, RTAX_WINDOW)) + RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), + &rt->u.dst.metrics[RTAX_WINDOW - 1]); + if (dst_metric(&rt->u.dst, RTAX_RTT)) + RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), + &rt->u.dst.metrics[RTAX_RTT]); =20 nlh->nlmsg_len =3D skb->tail - b; return skb->len; @@ -1208,7 +1202,7 @@ dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), atomic_read(&rt->u.dst.__refcnt), rt->u.dst.__use, - (int)rt->u.dst.rtt + (int) dst_metric(&rt->u.dst, RTAX_RTT) ); =20 =20 diff -Nru a/net/ipv4/Config.in b/net/ipv4/Config.in --- a/net/ipv4/Config.in Thu May 8 10:41:36 2003 +++ b/net/ipv4/Config.in Thu May 8 10:41:36 2003 @@ -41,6 +41,9 @@ fi bool ' IP: TCP Explicit Congestion Notification support' CONFIG_INET_ECN bool ' IP: TCP syncookie support (disabled per default)' CONFIG_SYN_COOKI= ES +tristate ' IP: AH transformation' CONFIG_INET_AH +tristate ' IP: ESP transformation' CONFIG_INET_ESP +tristate ' IP: IPComp transformation' CONFIG_INET_IPCOMP if [ "$CONFIG_NETFILTER" !=3D "n" ]; then source net/ipv4/netfilter/Config.in fi diff -Nru a/net/ipv4/Makefile b/net/ipv4/Makefile --- a/net/ipv4/Makefile Thu May 8 10:41:37 2003 +++ b/net/ipv4/Makefile Thu May 8 10:41:37 2003 @@ -24,6 +24,11 @@ obj-$(CONFIG_NET_IPIP) +=3D ipip.o obj-$(CONFIG_NET_IPGRE) +=3D ip_gre.o obj-$(CONFIG_SYN_COOKIES) +=3D syncookies.o +obj-$(CONFIG_INET_AH) +=3D ah.o +obj-$(CONFIG_INET_ESP) +=3D esp.o +obj-$(CONFIG_INET_IPCOMP) +=3D ipcomp.o obj-$(CONFIG_IP_PNP) +=3D ipconfig.o + +obj-y +=3D xfrm4_policy.o xfrm4_state.o xfrm4_input.o xfrm4_tunnel.o =20 include $(TOPDIR)/Rules.make diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c --- a/net/ipv4/af_inet.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/af_inet.c Thu May 8 10:41:36 2003 @@ -89,6 +89,7 @@ =20 #include #include +#include #include #include #include @@ -103,6 +104,7 @@ #include #include #include +#include #ifdef CONFIG_IP_MROUTE #include #endif @@ -213,6 +215,8 @@ =20 sock_orphan(sk); =20 + xfrm_sk_free_policy(sk); + #ifdef INET_REFCNT_DEBUG if (atomic_read(&sk->refcnt) !=3D 1) { printk(KERN_DEBUG "Destruction inet %p delayed, c=3D%d\n", sk, atomic_re= ad(&sk->refcnt)); @@ -724,6 +728,7 @@ sin->sin_port =3D sk->sport; sin->sin_addr.s_addr =3D addr; } + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); *uaddr_len =3D sizeof(*sin); return(0); } @@ -757,6 +762,21 @@ return sk->prot->sendmsg(sk, msg, size); } =20 + +ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, = size_t size, int flags) +{ + struct sock *sk =3D sock->sk; + + /* We may need to bind the socket. */ + if (!sk->num && inet_autobind(sk)) + return -EAGAIN; + + if (sk->prot->sendpage) + return sk->prot->sendpage(sk, page, offset, size, flags); + return sock_no_sendpage(sock, page, offset, size, flags); +} + + int inet_shutdown(struct socket *sock, int how) { struct sock *sk =3D sock->sk; @@ -981,7 +1001,7 @@ sendmsg: inet_sendmsg, recvmsg: inet_recvmsg, mmap: sock_no_mmap, - sendpage: sock_no_sendpage, + sendpage: inet_sendpage, }; =20 struct net_proto_family inet_family_ops =3D { @@ -1100,6 +1120,27 @@ } } =20 +#ifdef CONFIG_IP_MULTICAST +static struct inet_protocol igmp_protocol =3D { + .handler =3D igmp_rcv, +}; +#endif + +static struct inet_protocol tcp_protocol =3D { + .handler =3D tcp_v4_rcv, + .err_handler =3D tcp_v4_err, + .no_policy =3D 1, +}; + +static struct inet_protocol udp_protocol =3D { + .handler =3D udp_rcv, + .err_handler =3D udp_err, + .no_policy =3D 1, +}; + +static struct inet_protocol icmp_protocol =3D { + .handler =3D icmp_rcv, +}; =20 /* * Called by socket.c on kernel startup. =20 @@ -1108,7 +1149,6 @@ static int __init inet_init(void) { struct sk_buff *dummy_skb; - struct inet_protocol *p; struct inet_protosw *q; struct list_head *r; =20 @@ -1126,16 +1166,19 @@ (void) sock_register(&inet_family_ops); =20 /* - * Add all the protocols.=20 + * Add all the base protocols. */ =20 - printk(KERN_INFO "IP Protocols: "); - for (p =3D inet_protocol_base; p !=3D NULL;) { - struct inet_protocol *tmp =3D (struct inet_protocol *) p->next; - inet_add_protocol(p); - printk("%s%s",p->name,tmp?", ":"\n"); - p =3D tmp; - } + if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) + printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n"); + if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) + printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n"); + if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) + printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n"); +#ifdef CONFIG_IP_MULTICAST + if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) + printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n"); +#endif =20 /* Register the socket-side information for inet_create. */ for(r =3D &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r) diff -Nru a/net/ipv4/ah.c b/net/ipv4/ah.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/ah.c Thu May 8 10:41:38 2003 @@ -0,0 +1,366 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Clear mutable options and find final destination to substitute + * into IP header for icv calculation. Options are already checked + * for validity, so paranoia is not required. */ + +static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) +{ + unsigned char * optptr =3D (unsigned char*)(iph+1); + int l =3D iph->ihl*4 - sizeof(struct iphdr); + int optlen; + + while (l > 0) { + switch (*optptr) { + case IPOPT_END: + return 0; + case IPOPT_NOOP: + l--; + optptr++; + continue; + } + optlen =3D optptr[1]; + if (optlen<2 || optlen>l) + return -EINVAL; + switch (*optptr) { + case IPOPT_SEC: + case 0x85: /* Some "Extended Security" crap. */ + case 0x86: /* Another "Commercial Security" crap. */ + case IPOPT_RA: + case 0x80|21: /* RFC1770 */ + break; + case IPOPT_LSRR: + case IPOPT_SSRR: + if (optlen < 6) + return -EINVAL; + memcpy(daddr, optptr+optlen-4, 4); + /* Fall through */ + default: + memset(optptr+2, 0, optlen-2); + } + l -=3D optlen; + optptr +=3D optlen; + } + return 0; +} + +static int ah_output(struct sk_buff *skb) +{ + int err; + struct dst_entry *dst =3D skb->dst; + struct xfrm_state *x =3D dst->xfrm; + struct iphdr *iph, *top_iph; + struct ip_auth_hdr *ah; + struct ah_data *ahp; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + if (skb->ip_summed =3D=3D CHECKSUM_HW && skb_checksum_help(skb) =3D=3D NU= LL) { + err =3D -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err =3D xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + + iph =3D skb->nh.iph; + if (x->props.mode) { + top_iph =3D (struct iphdr*)skb_push(skb, x->props.header_len); + top_iph->ihl =3D 5; + top_iph->version =3D 4; + top_iph->tos =3D 0; + top_iph->tot_len =3D htons(skb->len); + if (!(iph->frag_off&htons(IP_DF))) { +#ifdef NETIF_F_TSO + __ip_select_ident(top_iph, dst, 0); +#else + __ip_select_ident(top_iph, dst); +#endif + } + top_iph->frag_off =3D 0; + top_iph->ttl =3D 0; + top_iph->protocol =3D IPPROTO_AH; + top_iph->check =3D 0; + top_iph->saddr =3D x->props.saddr.a4; + top_iph->daddr =3D x->id.daddr.a4; + ah =3D (struct ip_auth_hdr*)(top_iph+1); + ah->nexthdr =3D IPPROTO_IPIP; + } else { + memcpy(&tmp_iph, skb->data, iph->ihl*4); + top_iph =3D (struct iphdr*)skb_push(skb, x->props.header_len); + memcpy(top_iph, &tmp_iph, iph->ihl*4); + iph =3D &tmp_iph.iph; + top_iph->tos =3D 0; + top_iph->tot_len =3D htons(skb->len); + top_iph->frag_off =3D 0; + top_iph->ttl =3D 0; + top_iph->protocol =3D IPPROTO_AH; + top_iph->check =3D 0; + if (top_iph->ihl !=3D 5) { + err =3D ip_clear_mutable_options(top_iph, &top_iph->daddr); + if (err) + goto error; + } + ah =3D (struct ip_auth_hdr*)((char*)top_iph+iph->ihl*4); + ah->nexthdr =3D iph->protocol; + } + ahp =3D x->data; + ah->hdrlen =3D (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +=20 + ahp->icv_trunc_len) >> 2) - 2; + + ah->reserved =3D 0; + ah->spi =3D x->id.spi; + ah->seq_no =3D htonl(++x->replay.oseq); + ahp->icv(ahp, skb, ah->auth_data); + top_iph->tos =3D iph->tos; + top_iph->ttl =3D iph->ttl; + if (x->props.mode) { + top_iph->frag_off =3D iph->frag_off&~htons(IP_MF|IP_OFFSET); + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + } else { + top_iph->frag_off =3D iph->frag_off; + top_iph->daddr =3D iph->daddr; + if (iph->ihl !=3D 5) + memcpy(top_iph+1, iph+1, iph->ihl*4 - sizeof(struct iphdr)); + } + ip_send_check(top_iph); + + skb->nh.raw =3D skb->data; + + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst =3D dst_pop(dst)) =3D=3D NULL) { + err =3D -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + return err; +} + +int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct = sk_buff *skb) +{ + int ah_hlen; + struct iphdr *iph; + struct ip_auth_hdr *ah; + struct ah_data *ahp; + char work_buf[60]; + + if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) + goto out; + + ah =3D (struct ip_auth_hdr*)skb->data; + ahp =3D x->data; + ah_hlen =3D (ah->hdrlen + 2) << 2; +=09 + if (ah_hlen !=3D XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_l= en) && + ah_hlen !=3D XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_= len))=20 + goto out; + + if (!pskb_may_pull(skb, ah_hlen)) + goto out; + + /* We are going to _remove_ AH header to keep sockets happy, + * so... Later this can change. */ + if (skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto out; + + skb->ip_summed =3D CHECKSUM_NONE; + + ah =3D (struct ip_auth_hdr*)skb->data; + iph =3D skb->nh.iph; + + memcpy(work_buf, iph, iph->ihl*4); + + iph->ttl =3D 0; + iph->tos =3D 0; + iph->frag_off =3D 0; + iph->check =3D 0; + if (iph->ihl !=3D 5) { + u32 dummy; + if (ip_clear_mutable_options(iph, &dummy)) + goto out; + } + { + u8 auth_data[ahp->icv_trunc_len]; + =09 + memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); + skb_push(skb, skb->data - skb->nh.raw); + ahp->icv(ahp, skb, ah->auth_data); + if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { + x->stats.integrity_failed++; + goto out; + } + } + ((struct iphdr*)work_buf)->protocol =3D ah->nexthdr; + skb->nh.raw =3D skb_pull(skb, ah_hlen); + memcpy(skb->nh.raw, work_buf, iph->ihl*4); + skb->nh.iph->tot_len =3D htons(skb->len); + skb_pull(skb, skb->nh.iph->ihl*4); + skb->h.raw =3D skb->data; + + return 0; + +out: + return -EINVAL; +} + +void ah4_err(struct sk_buff *skb, u32 info) +{ + struct iphdr *iph =3D (struct iphdr*)skb->data; + struct ip_auth_hdr *ah =3D (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2))= ; + struct xfrm_state *x; + + if (skb->h.icmph->type !=3D ICMP_DEST_UNREACH || + skb->h.icmph->code !=3D ICMP_FRAG_NEEDED) + return; + + x =3D xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_A= H, AF_INET); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/%08x\n", + ntohl(ah->spi), ntohl(iph->daddr)); + xfrm_state_put(x); +} + +static int ah_init_state(struct xfrm_state *x, void *args) +{ + struct ah_data *ahp =3D NULL; + struct xfrm_algo_desc *aalg_desc; + + /* null auth can use a zero length key */ + if (x->aalg->alg_key_len > 512) + goto error; + + ahp =3D kmalloc(sizeof(*ahp), GFP_KERNEL); + if (ahp =3D=3D NULL) + return -ENOMEM; + + memset(ahp, 0, sizeof(*ahp)); + + ahp->key =3D x->aalg->alg_key; + ahp->key_len =3D (x->aalg->alg_key_len+7)/8; + ahp->tfm =3D crypto_alloc_tfm(x->aalg->alg_name, 0); + if (!ahp->tfm) + goto error; + ahp->icv =3D ah_hmac_digest; +=09 + /* + * Lookup the algorithm description maintained by xfrm_algo, + * verify crypto transform properties, and store information + * we need for AH processing. This lookup cannot fail here + * after a successful crypto_alloc_tfm(). + */ + aalg_desc =3D xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 !=3D + crypto_tfm_alg_digestsize(ahp->tfm)) { + printk(KERN_INFO "AH: %s digestsize %u !=3D %hu\n", + x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } +=09 + ahp->icv_full_len =3D aalg_desc->uinfo.auth.icv_fullbits/8; + ahp->icv_trunc_len =3D aalg_desc->uinfo.auth.icv_truncbits/8; +=09 + ahp->work_icv =3D kmalloc(ahp->icv_full_len, GFP_KERNEL); + if (!ahp->work_icv) + goto error; +=09 + x->props.header_len =3D XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv= _trunc_len); + if (x->props.mode) + x->props.header_len +=3D sizeof(struct iphdr); + x->data =3D ahp; + + return 0; + +error: + if (ahp) { + if (ahp->work_icv) + kfree(ahp->work_icv); + if (ahp->tfm) + crypto_free_tfm(ahp->tfm); + kfree(ahp); + } + return -EINVAL; +} + +static void ah_destroy(struct xfrm_state *x) +{ + struct ah_data *ahp =3D x->data; + + if (ahp->work_icv) { + kfree(ahp->work_icv); + ahp->work_icv =3D NULL; + } + if (ahp->tfm) { + crypto_free_tfm(ahp->tfm); + ahp->tfm =3D NULL; + } + kfree(ahp); +} + + +static struct xfrm_type ah_type =3D +{ + .description =3D "AH4", + .owner =3D THIS_MODULE, + .proto =3D IPPROTO_AH, + .init_state =3D ah_init_state, + .destructor =3D ah_destroy, + .input =3D ah_input, + .output =3D ah_output +}; + +static struct inet_protocol ah4_protocol =3D { + .handler =3D xfrm4_rcv, + .err_handler =3D ah4_err, + .no_policy =3D 1, +}; + +static int __init ah4_init(void) +{ + if (xfrm_register_type(&ah_type, AF_INET) < 0) { + printk(KERN_INFO "ip ah init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) { + printk(KERN_INFO "ip ah init: can't add protocol\n"); + xfrm_unregister_type(&ah_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit ah4_fini(void) +{ + if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0) + printk(KERN_INFO "ip ah close: can't remove protocol\n"); + if (xfrm_unregister_type(&ah_type, AF_INET) < 0) + printk(KERN_INFO "ip ah close: can't remove xfrm type\n"); +} + +module_init(ah4_init); +module_exit(ah4_fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c --- a/net/ipv4/arp.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/arp.c Thu May 8 10:41:37 2003 @@ -347,11 +347,13 @@ =20 static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D sip, + .saddr =3D tip } } }; struct rtable *rt; int flag =3D 0;=20 /*unsigned long now; */ =20 - if (ip_route_output(&rt, sip, tip, 0, 0) < 0)=20 + if (ip_route_output_key(&rt, &fl) < 0)=20 return 1; if (rt->u.dst.dev !=3D dev) {=20 NET_INC_STATS_BH(ArpFilter); @@ -505,11 +507,11 @@ */ =09 skb =3D alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) - + dev->hard_header_len + 15, GFP_ATOMIC); + + LL_RESERVED_SPACE(dev), GFP_ATOMIC); if (skb =3D=3D NULL) return; =20 - skb_reserve(skb, (dev->hard_header_len+15)&~15); + skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb->nh.raw =3D skb->data; arp =3D (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->add= r_len+4)); skb->dev =3D dev; @@ -918,8 +920,10 @@ if (r->arp_flags & ATF_PERM) r->arp_flags |=3D ATF_COM; if (dev =3D=3D NULL) { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D ip, + .tos =3D RTO_ONLINK } } }; struct rtable * rt; - if ((err =3D ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) !=3D 0) + if ((err =3D ip_route_output_key(&rt, &fl)) !=3D 0) return err; dev =3D rt->u.dst.dev; ip_rt_put(rt); @@ -1001,8 +1005,10 @@ } =20 if (dev =3D=3D NULL) { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D ip, + .tos =3D RTO_ONLINK } } }; struct rtable * rt; - if ((err =3D ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) !=3D 0) + if ((err =3D ip_route_output_key(&rt, &fl)) !=3D 0) return err; dev =3D rt->u.dst.dev; ip_rt_put(rt); diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c --- a/net/ipv4/devinet.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/devinet.c Thu May 8 10:41:37 2003 @@ -847,6 +847,8 @@ memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); inet_insert_ifa(ifa); } + in_dev->cnf.no_xfrm =3D 1; + in_dev->cnf.no_policy =3D 1; } ip_mc_up(in_dev); break; @@ -1053,10 +1055,66 @@ return ret; } =20 +static int ipv4_doint_and_flush(ctl_table *ctl, int write, + struct file* filp, void *buffer, + size_t *lenp) +{ + int *valp =3D ctl->data; + int val =3D *valp; + int ret =3D proc_dointvec(ctl, write, filp, buffer, lenp); + + if (write && *valp !=3D val) + rt_cache_flush(0); + + return ret; +} + +static int ipv4_doint_and_flush_strategy(ctl_table *table, int *name, int = nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen,=20 + void **context) +{ + int *valp =3D table->data; + int new; + + if (!newval || !newlen) + return 0; + + if (newlen !=3D sizeof(int)) + return -EINVAL; + + if (get_user(new, (int *)newval)) + return -EFAULT; + + if (new =3D=3D *valp) + return 0; + + if (oldval && oldlenp) { + size_t len; + + if (get_user(len, oldlenp)) + return -EFAULT; + + if (len) { + if (len > table->maxlen) + len =3D table->maxlen; + if (copy_to_user(oldval, valp, len)) + return -EFAULT; + if (put_user(len, oldlenp)) + return -EFAULT; + } + } + + *valp =3D new; + rt_cache_flush(0); + return 1; +} + + static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[15]; + ctl_table devinet_vars[17]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -1105,6 +1163,12 @@ {NET_IPV4_CONF_ARPFILTER, "arp_filter", &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_CONF_NOXFRM, "disable_xfrm", + &ipv4_devconf.no_xfrm, sizeof(int), 0644, NULL, + &ipv4_doint_and_flush, &ipv4_doint_and_flush_strategy,}, + {NET_IPV4_CONF_NOPOLICY, "disable_policy", + &ipv4_devconf.no_policy, sizeof(int), 0644, NULL, + &ipv4_doint_and_flush, &ipv4_doint_and_flush_strategy}, {0}}, =20 {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},= {0}}, diff -Nru a/net/ipv4/esp.c b/net/ipv4/esp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/esp.c Thu May 8 10:41:38 2003 @@ -0,0 +1,604 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SG_ONSTACK 4 + +/* decapsulation data for use when post-processing */ +struct esp_decap_data { + xfrm_address_t saddr; + __u16 sport; + __u8 proto; +}; + +int esp_output(struct sk_buff *skb) +{ + int err; + struct dst_entry *dst =3D skb->dst; + struct xfrm_state *x =3D dst->xfrm; + struct iphdr *iph, *top_iph; + struct ip_esp_hdr *esph; + struct crypto_tfm *tfm; + struct esp_data *esp; + struct sk_buff *trailer; + struct udphdr *uh =3D NULL; + struct xfrm_encap_tmpl *encap =3D NULL; + int blksize; + int clen; + int alen; + int nfrags; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + /* First, if the skb is not checksummed, complete checksum. */ + if (skb->ip_summed =3D=3D CHECKSUM_HW && skb_checksum_help(skb) =3D=3D NU= LL) { + err =3D -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err =3D xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + err =3D -ENOMEM; + + /* Strip IP header in transport mode. Save it. */ + if (!x->props.mode) { + iph =3D skb->nh.iph; + memcpy(&tmp_iph, iph, iph->ihl*4); + __skb_pull(skb, iph->ihl*4); + } + /* Now skb is pure payload to encrypt */ + + /* Round to block size */ + clen =3D skb->len; + + esp =3D x->data; + alen =3D esp->auth.icv_trunc_len; + tfm =3D esp->conf.tfm; + blksize =3D (crypto_tfm_alg_blocksize(tfm) + 3) & ~3; + clen =3D (clen + 2 + blksize-1)&~(blksize-1); + if (esp->conf.padlen) + clen =3D (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + if ((nfrags =3D skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) + goto error; + + /* Fill padding... */ + do { + int i; + for (i=3D0; ilen - 2; i++) + *(u8*)(trailer->tail + i) =3D i+1; + } while (0); + *(u8*)(trailer->tail + clen-skb->len - 2) =3D (clen - skb->len)-2; + pskb_put(skb, trailer, clen - skb->len); + + encap =3D x->encap; + + iph =3D skb->nh.iph; + if (x->props.mode) { + top_iph =3D (struct iphdr*)skb_push(skb, x->props.header_len); + esph =3D (struct ip_esp_hdr*)(top_iph+1); + if (encap && encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + uh =3D (struct udphdr*) esph; + esph =3D (struct ip_esp_hdr*)(uh+1); + top_iph->protocol =3D IPPROTO_UDP; + break; + default: + printk(KERN_INFO + "esp_output(): Unhandled encap: %u\n", + encap->encap_type); + top_iph->protocol =3D IPPROTO_ESP; + break; + } + } else + top_iph->protocol =3D IPPROTO_ESP; + *(u8*)(trailer->tail - 1) =3D IPPROTO_IPIP; + top_iph->ihl =3D 5; + top_iph->version =3D 4; + top_iph->tos =3D iph->tos; /* DS disclosed */ + top_iph->tot_len =3D htons(skb->len + alen); + top_iph->frag_off =3D iph->frag_off&htons(IP_DF); + if (!(top_iph->frag_off)) + ip_select_ident(top_iph, dst, 0); + top_iph->ttl =3D iph->ttl; /* TTL disclosed */ + top_iph->check =3D 0; + top_iph->saddr =3D x->props.saddr.a4; + top_iph->daddr =3D x->id.daddr.a4; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + } else { + esph =3D (struct ip_esp_hdr*)skb_push(skb, x->props.header_len); + top_iph =3D (struct iphdr*)skb_push(skb, iph->ihl*4); + memcpy(top_iph, &tmp_iph, iph->ihl*4); + if (encap && encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + uh =3D (struct udphdr*) esph; + esph =3D (struct ip_esp_hdr*)(uh+1); + top_iph->protocol =3D IPPROTO_UDP; + break; + default: + printk(KERN_INFO + "esp_output(): Unhandled encap: %u\n", + encap->encap_type); + top_iph->protocol =3D IPPROTO_ESP; + break; + } + } else + top_iph->protocol =3D IPPROTO_ESP; + iph =3D &tmp_iph.iph; + top_iph->tot_len =3D htons(skb->len + alen); + top_iph->check =3D 0; + top_iph->frag_off =3D iph->frag_off; + *(u8*)(trailer->tail - 1) =3D iph->protocol; + } + + /* this is non-NULL only with UDP Encapsulation */ + if (encap && uh) { + uh->source =3D encap->encap_sport; + uh->dest =3D encap->encap_dport; + uh->len =3D htons(skb->len + alen - sizeof(struct iphdr)); + uh->check =3D 0; + } + + esph->spi =3D x->id.spi; + esph->seq_no =3D htonl(++x->replay.oseq); + + if (esp->conf.ivlen) + crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + + do { + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg =3D sgbuf; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg =3D kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto error; + } + skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); + crypto_cipher_encrypt(tfm, sg, sg, clen); + if (unlikely(sg !=3D sgbuf)) + kfree(sg); + } while (0); + + if (esp->conf.ivlen) { + memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + } + + if (esp->auth.icv_full_len) { + esp->auth.icv(esp, skb, (u8*)esph-skb->data, + sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer-= >tail); + pskb_put(skb, trailer, alen); + } + + ip_send_check(top_iph); + + skb->nh.raw =3D skb->data; + + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst =3D dst_pop(dst)) =3D=3D NULL) { + err =3D -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + 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. + */ +int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct= sk_buff *skb) +{ + struct iphdr *iph; + struct ip_esp_hdr *esph; + struct esp_data *esp =3D x->data; + struct sk_buff *trailer; + int blksize =3D crypto_tfm_alg_blocksize(esp->conf.tfm); + int alen =3D esp->auth.icv_trunc_len; + int elen =3D skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - ale= n; + int nfrags; + int encap_len =3D 0; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) + goto out; + + if (elen <=3D 0 || (elen & (blksize-1))) + goto out; + + /* If integrity check is required, do this. */ + if (esp->auth.icv_full_len) { + u8 sum[esp->auth.icv_full_len]; + u8 sum1[alen]; + =09 + esp->auth.icv(esp, skb, 0, skb->len-alen, sum); + + if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) + BUG(); + + if (unlikely(memcmp(sum, sum1, alen))) { + x->stats.integrity_failed++; + goto out; + } + } + + if ((nfrags =3D skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + + skb->ip_summed =3D CHECKSUM_NONE; + + esph =3D (struct ip_esp_hdr*)skb->data; + iph =3D skb->nh.iph; + + /* Get ivec. This can be wrong, check against another impls. */ + if (esp->conf.ivlen) + crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsiz= e(esp->conf.tfm)); + + { + u8 nexthdr[2]; + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg =3D sgbuf; + u8 workbuf[60]; + int padlen; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg =3D kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto out; + } + skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen)= ; + crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); + if (unlikely(sg !=3D sgbuf)) + kfree(sg); + + if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) + BUG(); + + padlen =3D nexthdr[0]; + if (padlen+2 >=3D elen) + goto out; + + /* ... check padding bits here. Silly. :-) */=20 + + if (x->encap && decap && decap->decap_type) { + struct esp_decap_data *encap_data; + struct udphdr *uh =3D (struct udphdr *) (iph+1); + + encap_data =3D (struct esp_decap_data *) (decap->decap_data); + encap_data->proto =3D 0; + + switch (decap->decap_type) { + case UDP_ENCAP_ESPINUDP: + + if ((void*)uh =3D=3D (void*)esph) { + printk(KERN_DEBUG + "esp_input(): Got ESP; expecting ESPinUDP\n"); + break; + } + + encap_data->proto =3D AF_INET; + encap_data->saddr.a4 =3D iph->saddr; + encap_data->sport =3D uh->source; + encap_len =3D (void*)esph - (void*)uh; + if (encap_len !=3D sizeof(*uh)) + printk(KERN_DEBUG + "esp_input(): UDP -> ESP: too much room: %d\n", + encap_len); + break; + + default: + printk(KERN_INFO + "esp_input(): processing unknown encap type: %u\n", + decap->decap_type); + break; + } + } + + iph->protocol =3D nexthdr[1]; + pskb_trim(skb, skb->len - alen - padlen - 2); + memcpy(workbuf, skb->nh.raw, iph->ihl*4); + skb->h.raw =3D skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen= ); + skb->nh.raw +=3D encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen= ; + memcpy(skb->nh.raw, workbuf, iph->ihl*4); + skb->nh.iph->tot_len =3D htons(skb->len); + } + + return 0; + +out: + return -EINVAL; +} + +int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, s= truct sk_buff *skb) +{ + =20 + if (x->encap) { + struct xfrm_encap_tmpl *encap; + struct esp_decap_data *decap_data; + + encap =3D x->encap; + decap_data =3D (struct esp_decap_data *)(decap->decap_data); + + /* first, make sure that the decap type =3D=3D the encap type */ + if (encap->encap_type !=3D decap->decap_type) + return -EINVAL; + + /* Next, if we don't have an encap type, then ignore it */ + if (!encap->encap_type) + return 0; + + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + /* + * 1) if the NAT-T peer's IP or port changed then + * advertize the change to the keying daemon. + * This is an inbound SA, so just compare + * SRC ports. + */ + if (decap_data->proto =3D=3D AF_INET && + (decap_data->saddr.a4 !=3D x->props.saddr.a4 || + decap_data->sport !=3D encap->encap_sport)) { + xfrm_address_t ipaddr; + + ipaddr.a4 =3D decap_data->saddr.a4; + km_new_mapping(x, &ipaddr, decap_data->sport); + =09 + /* XXX: perhaps add an extra + * policy check here, to see + * if we should allow or + * reject a packet from a + * different source + * address/port. + */ + } + =09 + /* + * 2) ignore UDP/TCP checksums in case + * of NAT-T in Transport Mode, or + * perform other post-processing fixes + * as per * draft-ietf-ipsec-udp-encaps-06, + * section 3.1.2 + */ + if (!x->props.mode) + skb->ip_summed =3D CHECKSUM_UNNECESSARY; + + break; + default: + printk(KERN_INFO + "esp4_post_input(): Unhandled encap type: %u\n", + encap->encap_type); + break; + } + } + return 0; +} + +static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) +{ + struct esp_data *esp =3D x->data; + u32 blksize =3D crypto_tfm_alg_blocksize(esp->conf.tfm); + + if (x->props.mode) { + mtu =3D (mtu + 2 + blksize-1)&~(blksize-1); + } else { + /* The worst case. */ + mtu +=3D 2 + blksize; + } + if (esp->conf.padlen) + mtu =3D (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + return mtu + x->props.header_len + esp->auth.icv_trunc_len; +} + +void esp4_err(struct sk_buff *skb, u32 info) +{ + struct iphdr *iph =3D (struct iphdr*)skb->data; + struct ip_esp_hdr *esph =3D (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2))= ; + struct xfrm_state *x; + + if (skb->h.icmph->type !=3D ICMP_DEST_UNREACH || + skb->h.icmph->code !=3D ICMP_FRAG_NEEDED) + return; + + x =3D xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO= _ESP, AF_INET); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA ESP/%08x/%08x\n", + ntohl(esph->spi), ntohl(iph->daddr)); + xfrm_state_put(x); +} + +void esp_destroy(struct xfrm_state *x) +{ + struct esp_data *esp =3D x->data; + + if (esp->conf.tfm) { + crypto_free_tfm(esp->conf.tfm); + esp->conf.tfm =3D NULL; + } + if (esp->conf.ivec) { + kfree(esp->conf.ivec); + esp->conf.ivec =3D NULL; + } + if (esp->auth.tfm) { + crypto_free_tfm(esp->auth.tfm); + esp->auth.tfm =3D NULL; + } + if (esp->auth.work_icv) { + kfree(esp->auth.work_icv); + esp->auth.work_icv =3D NULL; + } + kfree(esp); +} + +int esp_init_state(struct xfrm_state *x, void *args) +{ + struct esp_data *esp =3D NULL; + + /* null auth and encryption can have zero length keys */ + if (x->aalg) { + if (x->aalg->alg_key_len > 512) + goto error; + } + if (x->ealg =3D=3D NULL) + goto error; + + esp =3D kmalloc(sizeof(*esp), GFP_KERNEL); + if (esp =3D=3D NULL) + return -ENOMEM; + + memset(esp, 0, sizeof(*esp)); + + if (x->aalg) { + struct xfrm_algo_desc *aalg_desc; + + esp->auth.key =3D x->aalg->alg_key; + esp->auth.key_len =3D (x->aalg->alg_key_len+7)/8; + esp->auth.tfm =3D crypto_alloc_tfm(x->aalg->alg_name, 0); + if (esp->auth.tfm =3D=3D NULL) + goto error; + esp->auth.icv =3D esp_hmac_digest; + + aalg_desc =3D xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 !=3D + crypto_tfm_alg_digestsize(esp->auth.tfm)) { + printk(KERN_INFO "ESP: %s digestsize %u !=3D %hu\n", + x->aalg->alg_name, + crypto_tfm_alg_digestsize(esp->auth.tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } + + esp->auth.icv_full_len =3D aalg_desc->uinfo.auth.icv_fullbits/8; + esp->auth.icv_trunc_len =3D aalg_desc->uinfo.auth.icv_truncbits/8; + + esp->auth.work_icv =3D kmalloc(esp->auth.icv_full_len, GFP_KERNEL); + if (!esp->auth.work_icv) + goto error; + } + esp->conf.key =3D x->ealg->alg_key; + esp->conf.key_len =3D (x->ealg->alg_key_len+7)/8; + esp->conf.tfm =3D crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC= ); + if (esp->conf.tfm =3D=3D NULL) + goto error; + esp->conf.ivlen =3D crypto_tfm_alg_ivsize(esp->conf.tfm); + esp->conf.padlen =3D 0; + if (esp->conf.ivlen) { + esp->conf.ivec =3D kmalloc(esp->conf.ivlen, GFP_KERNEL); + get_random_bytes(esp->conf.ivec, esp->conf.ivlen); + } + crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len); + x->props.header_len =3D sizeof(struct ip_esp_hdr) + esp->conf.ivlen; + if (x->props.mode) + x->props.header_len +=3D sizeof(struct iphdr); + if (x->encap) { + struct xfrm_encap_tmpl *encap =3D x->encap; + + if (encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + x->props.header_len +=3D sizeof(struct udphdr); + break; + default: + printk (KERN_INFO + "esp_init_state(): Unhandled encap type: %u\n", + encap->encap_type); + break; + } + } + } + x->data =3D esp; + x->props.trailer_len =3D esp4_get_max_size(x, 0) - x->props.header_len; + return 0; + +error: + if (esp) { + if (esp->auth.tfm) + crypto_free_tfm(esp->auth.tfm); + if (esp->auth.work_icv) + kfree(esp->auth.work_icv); + if (esp->conf.tfm) + crypto_free_tfm(esp->conf.tfm); + kfree(esp); + } + return -EINVAL; +} + +static struct xfrm_type esp_type =3D +{ + .description =3D "ESP4", + .owner =3D THIS_MODULE, + .proto =3D IPPROTO_ESP, + .init_state =3D esp_init_state, + .destructor =3D esp_destroy, + .get_max_size =3D esp4_get_max_size, + .input =3D esp_input, + .post_input =3D esp_post_input, + .output =3D esp_output +}; + +static struct inet_protocol esp4_protocol =3D { + .handler =3D xfrm4_rcv, + .err_handler =3D esp4_err, + .no_policy =3D 1, +}; + +int __init esp4_init(void) +{ + struct xfrm_decap_state decap; + + if (sizeof(struct esp_decap_data) < + sizeof(decap.decap_data)) { + extern void decap_data_too_small(void); + + decap_data_too_small(); + } + + SET_MODULE_OWNER(&esp_type); + if (xfrm_register_type(&esp_type, AF_INET) < 0) { + printk(KERN_INFO "ip esp init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { + printk(KERN_INFO "ip esp init: can't add protocol\n"); + xfrm_unregister_type(&esp_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit esp4_fini(void) +{ + if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) + printk(KERN_INFO "ip esp close: can't remove protocol\n"); + if (xfrm_unregister_type(&esp_type, AF_INET) < 0) + printk(KERN_INFO "ip esp close: can't remove xfrm type\n"); +} + +module_init(esp4_init); +module_exit(esp4_fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c --- a/net/ipv4/fib_frontend.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/fib_frontend.c Thu May 8 10:41:37 2003 @@ -144,17 +144,15 @@ =20 struct net_device * ip_dev_find(u32 addr) { - struct rt_key key; + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D addr } } }; struct fib_result res; struct net_device *dev =3D NULL; =20 - memset(&key, 0, sizeof(key)); - key.dst =3D addr; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r =3D NULL; #endif =20 - if (!local_table || local_table->tb_lookup(local_table, &key, &res)) { + if (!local_table || local_table->tb_lookup(local_table, &fl, &res)) { return NULL; } if (res.type !=3D RTN_LOCAL) @@ -170,7 +168,7 @@ =20 unsigned inet_addr_type(u32 addr) { - struct rt_key key; + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D addr } } }; struct fib_result res; unsigned ret =3D RTN_BROADCAST; =20 @@ -179,15 +177,13 @@ if (MULTICAST(addr)) return RTN_MULTICAST; =20 - memset(&key, 0, sizeof(key)); - key.dst =3D addr; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r =3D NULL; #endif =09 if (local_table) { ret =3D RTN_UNICAST; - if (local_table->tb_lookup(local_table, &key, &res) =3D=3D 0) { + if (local_table->tb_lookup(local_table, &fl, &res) =3D=3D 0) { ret =3D res.type; fib_res_put(&res); } @@ -207,18 +203,15 @@ struct net_device *dev, u32 *spec_dst, u32 *itag) { struct in_device *in_dev; - struct rt_key key; + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D src, + .saddr =3D dst, + .tos =3D tos } }, + .iif =3D oif }; struct fib_result res; int no_addr, rpf; int ret; =20 - key.dst =3D src; - key.src =3D dst; - key.tos =3D tos; - key.oif =3D 0; - key.iif =3D oif; - key.scope =3D RT_SCOPE_UNIVERSE; - no_addr =3D rpf =3D 0; read_lock(&inetdev_lock); in_dev =3D __in_dev_get(dev); @@ -231,7 +224,7 @@ if (in_dev =3D=3D NULL) goto e_inval; =20 - if (fib_lookup(&key, &res)) + if (fib_lookup(&fl, &res)) goto last_resort; if (res.type !=3D RTN_UNICAST) goto e_inval_res; @@ -252,10 +245,10 @@ goto last_resort; if (rpf) goto e_inval; - key.oif =3D dev->ifindex; + fl.oif =3D dev->ifindex; =20 ret =3D 0; - if (fib_lookup(&key, &res) =3D=3D 0) { + if (fib_lookup(&fl, &res) =3D=3D 0) { if (res.type =3D=3D RTN_UNICAST) { *spec_dst =3D FIB_RES_PREFSRC(res); ret =3D FIB_RES_NH(res).nh_scope >=3D RT_SCOPE_HOST; diff -Nru a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c --- a/net/ipv4/fib_hash.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/fib_hash.c Thu May 8 10:41:37 2003 @@ -266,7 +266,7 @@ } =20 static int -fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_= result *res) +fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_r= esult *res) { int err; struct fn_zone *fz; @@ -275,7 +275,7 @@ read_lock(&fib_hash_lock); for (fz =3D t->fn_zone_list; fz; fz =3D fz->fz_next) { struct fib_node *f; - fn_key_t k =3D fz_key(key->dst, fz); + fn_key_t k =3D fz_key(flp->fl4_dst, fz); =20 for (f =3D fz_chain(k, fz); f; f =3D f->fn_next) { if (!fn_key_eq(k, f->fn_key)) { @@ -285,17 +285,17 @@ continue; } #ifdef CONFIG_IP_ROUTE_TOS - if (f->fn_tos && f->fn_tos !=3D key->tos) + if (f->fn_tos && f->fn_tos !=3D flp->fl4_tos) continue; #endif f->fn_state |=3D FN_S_ACCESSED; =20 if (f->fn_state&FN_S_ZOMBIE) continue; - if (f->fn_scope < key->scope) + if (f->fn_scope < flp->fl4_scope) continue; =20 - err =3D fib_semantic_match(f->fn_type, FIB_INFO(f), key, res); + err =3D fib_semantic_match(f->fn_type, FIB_INFO(f), flp, res); if (err =3D=3D 0) { res->type =3D f->fn_type; res->scope =3D f->fn_scope; @@ -338,7 +338,7 @@ } =20 static void -fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, str= uct fib_result *res) +fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, stru= ct fib_result *res) { int order, last_idx; struct fib_node *f; diff -Nru a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c --- a/net/ipv4/fib_rules.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/fib_rules.c Thu May 8 10:41:37 2003 @@ -307,28 +307,28 @@ } } =20 -int fib_lookup(const struct rt_key *key, struct fib_result *res) +int fib_lookup(const struct flowi *flp, struct fib_result *res) { int err; struct fib_rule *r, *policy; struct fib_table *tb; =20 - u32 daddr =3D key->dst; - u32 saddr =3D key->src; + u32 daddr =3D flp->fl4_dst; + u32 saddr =3D flp->fl4_src; =20 FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", - NIPQUAD(key->dst), NIPQUAD(key->src)); + NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src)); read_lock(&fib_rules_lock); for (r =3D fib_rules; r; r=3Dr->r_next) { if (((saddr^r->r_src) & r->r_srcmask) || ((daddr^r->r_dst) & r->r_dstmask) || #ifdef CONFIG_IP_ROUTE_TOS - (r->r_tos && r->r_tos !=3D key->tos) || + (r->r_tos && r->r_tos !=3D flp->fl4_tos) || #endif #ifdef CONFIG_IP_ROUTE_FWMARK - (r->r_fwmark && r->r_fwmark !=3D key->fwmark) || + (r->r_fwmark && r->r_fwmark !=3D flp->fl4_fwmark) || #endif - (r->r_ifindex && r->r_ifindex !=3D key->iif)) + (r->r_ifindex && r->r_ifindex !=3D flp->iif)) continue; =20 FRprintk("tb %d r %d ", r->r_table, r->r_action); @@ -351,7 +351,7 @@ =20 if ((tb =3D fib_get_table(r->r_table)) =3D=3D NULL) continue; - err =3D tb->tb_lookup(tb, key, res); + err =3D tb->tb_lookup(tb, flp, res); if (err =3D=3D 0) { res->r =3D policy; if (policy) @@ -369,13 +369,13 @@ return -ENETUNREACH; } =20 -void fib_select_default(const struct rt_key *key, struct fib_result *res) +void fib_select_default(const struct flowi *flp, struct fib_result *res) { if (res->r && res->r->r_action =3D=3D RTN_UNICAST && FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope =3D=3D RT_SCOPE_LINK) { struct fib_table *tb; if ((tb =3D fib_get_table(res->r->r_table)) !=3D NULL) - tb->tb_select_default(tb, key, res); + tb->tb_select_default(tb, flp, res); } } =20 diff -Nru a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c --- a/net/ipv4/fib_semantics.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/fib_semantics.c Thu May 8 10:41:36 2003 @@ -349,7 +349,6 @@ int err; =20 if (nh->nh_gw) { - struct rt_key key; struct fib_result res; =20 #ifdef CONFIG_IP_ROUTE_PERVASIVE @@ -372,16 +371,18 @@ nh->nh_scope =3D RT_SCOPE_LINK; return 0; } - memset(&key, 0, sizeof(key)); - key.dst =3D nh->nh_gw; - key.oif =3D nh->nh_oif; - key.scope =3D r->rtm_scope + 1; - - /* It is not necessary, but requires a bit of thinking */ - if (key.scope < RT_SCOPE_LINK) - key.scope =3D RT_SCOPE_LINK; - if ((err =3D fib_lookup(&key, &res)) !=3D 0) - return err; + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D nh->nh_gw, + .scope =3D r->rtm_scope + 1 } }, + .oif =3D nh->nh_oif }; + + /* It is not necessary, but requires a bit of thinking */ + if (fl.fl4_scope < RT_SCOPE_LINK) + fl.fl4_scope =3D RT_SCOPE_LINK; + if ((err =3D fib_lookup(&fl, &res)) !=3D 0) + return err; + } err =3D -EINVAL; if (res.type !=3D RTN_UNICAST && res.type !=3D RTN_LOCAL) goto out; @@ -578,7 +579,7 @@ } =20 int=20 -fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key= , struct fib_result *res) +fib_semantic_match(int type, struct fib_info *fi, const struct flowi *flp,= struct fib_result *res) { int err =3D fib_props[type].error; =20 @@ -603,7 +604,7 @@ for_nexthops(fi) { if (nh->nh_flags&RTNH_F_DEAD) continue; - if (!key->oif || key->oif =3D=3D nh->nh_oif) + if (!flp->oif || flp->oif =3D=3D nh->nh_oif) break; } #ifdef CONFIG_IP_ROUTE_MULTIPATH @@ -949,7 +950,7 @@ fair weighted route distribution. */ =20 -void fib_select_multipath(const struct rt_key *key, struct fib_result *res= ) +void fib_select_multipath(const struct flowi *flp, struct fib_result *res) { struct fib_info *fi =3D res->fi; int w; diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c --- a/net/ipv4/icmp.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/icmp.c Thu May 8 10:41:37 2003 @@ -101,7 +101,6 @@ int offset; int data_len; =20 - unsigned int csum; struct { struct icmphdr icmph; __u32 times[3]; @@ -275,37 +274,47 @@ * Checksum each fragment, and on the first include the headers and final = checksum. */ =20 -static int icmp_glue_bits(const void *p, char *to, unsigned int offset, un= signed int fraglen) +int +icmp_glue_bits(void *from, char *to, int offset, int len, int odd, struct = sk_buff *skb) { - struct icmp_bxm *icmp_param =3D (struct icmp_bxm *)p; - struct icmphdr *icmph; + struct icmp_bxm *icmp_param =3D (struct icmp_bxm *)from; unsigned int csum; =20 - if (offset) { - icmp_param->csum=3Dskb_copy_and_csum_bits(icmp_param->skb, - icmp_param->offset+(offset-icmp_param->head_len),=20 - to, fraglen,icmp_param->csum); - return 0; - } + csum =3D skb_copy_and_csum_bits(icmp_param->skb, + icmp_param->offset + offset, + to, len, 0); =20 - /* - * First fragment includes header. Note that we've done - * the other fragments first, so that we get the checksum - * for the whole packet here. - */ - csum =3D csum_partial_copy_nocheck((void *)&icmp_param->data, - to, icmp_param->head_len, - icmp_param->csum); - csum=3Dskb_copy_and_csum_bits(icmp_param->skb, - icmp_param->offset,=20 - to+icmp_param->head_len, - fraglen-icmp_param->head_len, - csum); - icmph=3D(struct icmphdr *)to; - icmph->checksum =3D csum_fold(csum); + skb->csum =3D csum_block_add(skb->csum, csum, odd); return 0; } =20 +static void +icmp_push_reply(struct icmp_bxm *icmp_param, struct ipcm_cookie *ipc, stru= ct rtable *rt) +{ + struct sk_buff *skb; + + ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param, + icmp_param->data_len+icmp_param->head_len, + icmp_param->head_len, + ipc, rt, MSG_DONTWAIT); + + if ((skb =3D skb_peek(&icmp_socket->sk->write_queue)) !=3D NULL) { + struct icmphdr *icmph =3D skb->h.icmph; + unsigned int csum =3D 0; + struct sk_buff *skb1; + + skb_queue_walk(&icmp_socket->sk->write_queue, skb1) { + csum =3D csum_add(csum, skb1->csum); + } + csum =3D csum_partial_copy_nocheck((void *)&icmp_param->data, + (char*)icmph, icmp_param->head_len,=09 + csum); + icmph->checksum =3D csum_fold(csum); + skb->ip_summed =3D CHECKSUM_NONE; + ip_push_pending_frames(icmp_socket->sk); + } +} + /* * Driving logic for building and sending ICMP messages. */ @@ -323,7 +332,6 @@ icmp_xmit_lock(); =20 icmp_param->data.icmph.checksum=3D0; - icmp_param->csum=3D0; icmp_out_count(icmp_param->data.icmph.type); =20 sk->protinfo.af_inet.tos =3D skb->nh.iph->tos; @@ -335,14 +343,18 @@ if (ipc.opt->srr) daddr =3D icmp_param->replyopts.faddr; } - if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos)= , 0)) - goto out; - if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,=20 - icmp_param->data.icmph.code)) {=20 - ip_build_xmit(sk, icmp_glue_bits, icmp_param,=20 - icmp_param->data_len+icmp_param->head_len, - &ipc, rt, MSG_DONTWAIT); + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D daddr, + .saddr =3D rt->rt_spec_dst, + .tos =3D RT_TOS(skb->nh.iph->tos) } }, + .proto =3D IPPROTO_ICMP }; + if (ip_route_output_key(&rt, &fl)) + goto out; } + if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,=20 + icmp_param->data.icmph.code)) + icmp_push_reply(icmp_param, &ipc, rt); ip_rt_put(rt); out: icmp_xmit_unlock(); @@ -438,8 +450,8 @@ * Restore original addresses if packet has been translated. */ if (rt->rt_flags&RTCF_NAT && IPCB(skb_in)->flags&IPSKB_TRANSLATED) { - iph->daddr =3D rt->key.dst; - iph->saddr =3D rt->key.src; + iph->daddr =3D rt->fl.fl4_dst; + iph->saddr =3D rt->fl.fl4_src; } #endif =20 @@ -451,9 +463,14 @@ ((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) : iph->tos; =20 - if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) - goto out; - + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D iph->saddr, + .saddr =3D saddr, + .tos =3D RT_TOS(tos) } }, + .proto =3D IPPROTO_ICMP }; + if (ip_route_output_key(&rt, &fl)) + goto out; + } if (ip_options_echo(&icmp_param.replyopts, skb_in))=20 goto ende; =20 @@ -466,7 +483,6 @@ icmp_param.data.icmph.code=3Dcode; icmp_param.data.icmph.un.gateway =3D info; icmp_param.data.icmph.checksum=3D0; - icmp_param.csum=3D0; icmp_param.skb=3Dskb_in; icmp_param.offset=3Dskb_in->nh.raw - skb_in->data; icmp_out_count(icmp_param.data.icmph.type); @@ -475,8 +491,13 @@ ipc.addr =3D iph->saddr; ipc.opt =3D &icmp_param.replyopts; if (icmp_param.replyopts.srr) { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D icmp_param.replyopts.faddr, + .saddr =3D saddr, + .tos =3D RT_TOS(tos) } }, + .proto =3D IPPROTO_ICMP }; ip_rt_put(rt); - if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos),= 0)) + if (ip_route_output_key(&rt, &fl)) goto out; } =20 @@ -485,7 +506,7 @@ =20 /* RFC says return as much as we can without exceeding 576 bytes. */ =20 - room =3D rt->u.dst.pmtu; + room =3D dst_pmtu(&rt->u.dst); if (room > 576) room =3D 576; room -=3D sizeof(struct iphdr) + icmp_param.replyopts.optlen; @@ -496,9 +517,7 @@ icmp_param.data_len =3D room; icmp_param.head_len =3D sizeof(struct icmphdr); =20 - ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param,=20 - icmp_param.data_len+sizeof(struct icmphdr), - &ipc, rt, MSG_DONTWAIT); + icmp_push_reply(&icmp_param, &ipc, rt); =20 ende: ip_rt_put(rt); @@ -634,24 +653,10 @@ * we are OK. */ =20 - ipprot =3D (struct inet_protocol *) inet_protos[hash]; - while (ipprot) { - struct inet_protocol *nextip; - - nextip =3D (struct inet_protocol *) ipprot->next; -=09 - /*=20 - * Pass it off to everyone who wants it.=20 - */ - - /* RFC1122: OK. Passes appropriate ICMP errors to the */ - /* appropriate protocol layer (MUST), as per 3.2.2. */ - - if (protocol =3D=3D ipprot->protocol && ipprot->err_handler) - ipprot->err_handler(skb, info); + ipprot =3D inet_protos[hash]; + if (ipprot && ipprot->err_handler) + ipprot->err_handler(skb, info); =20 - ipprot =3D nextip; - } out:; } =20 diff -Nru a/net/ipv4/igmp.c b/net/ipv4/igmp.c --- a/net/ipv4/igmp.c Thu May 8 10:41:38 2003 +++ b/net/ipv4/igmp.c Thu May 8 10:41:38 2003 @@ -184,14 +184,6 @@ =20 #define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4) =20 -/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook - changes route */ -static inline int -output_maybe_reroute(struct sk_buff *skb) -{ - return skb->dst->output(skb); -} - static int igmp_send_report(struct net_device *dev, u32 group, int type) { struct sk_buff *skb; @@ -207,14 +199,19 @@ if (type =3D=3D IGMP_HOST_LEAVE_MESSAGE) dst =3D IGMP_ALL_ROUTER; =20 - if (ip_route_output(&rt, dst, 0, 0, dev->ifindex)) - return -1; + { + struct flowi fl =3D { .oif =3D dev->ifindex, + .nl_u =3D { .ip4_u =3D { .daddr =3D dst } }, + .proto =3D IPPROTO_IGMP }; + if (ip_route_output_key(&rt, &fl)) + return -1; + } if (rt->rt_src =3D=3D 0) { ip_rt_put(rt); return -1; } =20 - skb=3Dalloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC); + skb=3Dalloc_skb(IGMP_SIZE+LL_RESERVED_SPACE(dev), GFP_ATOMIC); if (skb =3D=3D NULL) { ip_rt_put(rt); return -1; @@ -222,7 +219,7 @@ =20 skb->dst =3D &rt->u.dst; =20 - skb_reserve(skb, (dev->hard_header_len+15)&~15); + skb_reserve(skb, LL_RESERVED_SPACE(dev)); =20 skb->nh.iph =3D iph =3D (struct iphdr *)skb_put(skb, sizeof(struct iphdr)= +4); =20 @@ -250,7 +247,7 @@ ih->csum=3Dip_compute_csum((void *)ih, sizeof(struct igmphdr)); =20 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, - output_maybe_reroute); + dst_output); } =20 =20 @@ -366,7 +363,7 @@ case IGMP_HOST_MEMBERSHIP_REPORT: case IGMP_HOST_NEW_MEMBERSHIP_REPORT: /* Is it our report looped back? */ - if (((struct rtable*)skb->dst)->key.iif =3D=3D 0) + if (((struct rtable*)skb->dst)->fl.iif =3D=3D 0) break; igmp_heard_report(in_dev, ih->group); break; @@ -600,6 +597,8 @@ =20 static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D imr->imr_multiaddr.s_addr } } }; struct rtable *rt; struct net_device *dev =3D NULL; struct in_device *idev =3D NULL; @@ -611,7 +610,7 @@ __dev_put(dev); } =20 - if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) { + if (!dev && !ip_route_output_key(&rt, &fl)) { dev =3D rt->u.dst.dev; ip_rt_put(rt); } diff -Nru a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c --- a/net/ipv4/ip_forward.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/ip_forward.c Thu May 8 10:41:36 2003 @@ -40,6 +40,7 @@ #include #include #include +#include =20 static inline int ip_forward_finish(struct sk_buff *skb) { @@ -47,36 +48,20 @@ =20 IP_INC_STATS_BH(IpForwDatagrams); =20 - if (opt->optlen =3D=3D 0) { -#ifdef CONFIG_NET_FASTROUTE - struct rtable *rt =3D (struct rtable*)skb->dst; - - if (rt->rt_flags&RTCF_FAST && !netdev_fastroute_obstacles) { - struct dst_entry *old_dst; - unsigned h =3D ((*(u8*)&rt->key.dst)^(*(u8*)&rt->key.src))&NETDEV_FASTR= OUTE_HMASK; - - write_lock_irq(&skb->dev->fastpath_lock); - old_dst =3D skb->dev->fastpath[h]; - skb->dev->fastpath[h] =3D dst_clone(&rt->u.dst); - write_unlock_irq(&skb->dev->fastpath_lock); - - dst_release(old_dst); - } -#endif - return (ip_send(skb)); - } + if (unlikely(opt->optlen)) + ip_forward_options(skb); =20 - ip_forward_options(skb); - return (ip_send(skb)); + return dst_output(skb); } =20 int ip_forward(struct sk_buff *skb) { - struct net_device *dev2; /* Output device */ struct iphdr *iph; /* Our header */ struct rtable *rt; /* Route we use */ struct ip_options * opt =3D &(IPCB(skb)->opt); - unsigned short mtu; + + if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) + goto drop; =20 if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) return NET_RX_SUCCESS; @@ -93,32 +78,21 @@ */ =20 iph =3D skb->nh.iph; - rt =3D (struct rtable*)skb->dst; =20 if (iph->ttl <=3D 1) goto too_many_hops; =20 - if (opt->is_strictroute && rt->rt_dst !=3D rt->rt_gateway) - goto sr_failed; - - /* - * Having picked a route we can now send the frame out - * after asking the firewall permission to do so. - */ + if (!xfrm4_route_forward(skb)) + goto drop; =20 - skb->priority =3D rt_tos2priority(iph->tos); - dev2 =3D rt->u.dst.dev; - mtu =3D rt->u.dst.pmtu; + iph =3D skb->nh.iph; + rt =3D (struct rtable*)skb->dst; =20 - /* - * We now generate an ICMP HOST REDIRECT giving the route - * we calculated. - */ - if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr) - ip_rt_send_redirect(skb); + if (opt->is_strictroute && rt->rt_dst !=3D rt->rt_gateway) + goto sr_failed; =20 /* We are about to mangle packet. Copy it! */ - if (skb_cow(skb, dev2->hard_header_len)) + if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len)) goto drop; iph =3D skb->nh.iph; =20 @@ -126,29 +100,16 @@ ip_decrease_ttl(iph); =20 /* - * We now may allocate a new buffer, and copy the datagram into it. - * If the indicated interface is up and running, kick it. + * We now generate an ICMP HOST REDIRECT giving the route + * we calculated. */ + if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr) + ip_rt_send_redirect(skb); =20 - if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF)) - goto frag_needed; - -#ifdef CONFIG_IP_ROUTE_NAT - if (rt->rt_flags & RTCF_NAT) { - if (ip_do_nat(skb)) { - kfree_skb(skb); - return NET_RX_BAD; - } - } -#endif + skb->priority =3D rt_tos2priority(iph->tos); =20 - return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2, + return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev, ip_forward_finish); - -frag_needed: - IP_INC_STATS_BH(IpFragFails); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); - goto drop; =20 sr_failed: /* diff -Nru a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c --- a/net/ipv4/ip_gre.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/ip_gre.c Thu May 8 10:41:37 2003 @@ -410,6 +410,7 @@ u16 flags; int grehlen =3D (iph->ihl<<2) + 4; struct sk_buff *skb2; + struct flowi fl; struct rtable *rt; =20 if (p[1] !=3D htons(ETH_P_IP)) @@ -486,7 +487,11 @@ skb2->nh.raw =3D skb2->data; =20 /* Try to guess incoming interface */ - if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) { + memset(&fl, 0, sizeof(fl)); + fl.fl4_dst =3D eiph->saddr; + fl.fl4_tos =3D RT_TOS(eiph->tos); + fl.proto =3D IPPROTO_GRE; + if (ip_route_output_key(&rt, &fl)) { kfree_skb(skb2); return; } @@ -496,7 +501,10 @@ if (rt->rt_flags&RTCF_LOCAL) { ip_rt_put(rt); rt =3D NULL; - if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) || + fl.fl4_dst =3D eiph->daddr; + fl.fl4_src =3D eiph->saddr; + fl.fl4_tos =3D eiph->tos; + if (ip_route_output_key(&rt, &fl) || rt->u.dst.dev->type !=3D ARPHRD_IPGRE) { ip_rt_put(rt); kfree_skb(skb2); @@ -513,11 +521,11 @@ =20 /* change mtu on this route */ if (type =3D=3D ICMP_DEST_UNREACH && code =3D=3D ICMP_FRAG_NEEDED) { - if (rel_info > skb2->dst->pmtu) { + if (rel_info > dst_pmtu(skb2->dst)) { kfree_skb(skb2); return; } - skb2->dst->pmtu =3D rel_info; + skb2->dst->ops->update_pmtu(skb2->dst, rel_info); rel_info =3D htonl(rel_info); } else if (type =3D=3D ICMP_TIME_EXCEEDED) { struct ip_tunnel *t =3D (struct ip_tunnel*)skb2->dev->priv; @@ -617,7 +625,7 @@ #ifdef CONFIG_NET_IPGRE_BROADCAST if (MULTICAST(iph->daddr)) { /* Looped back packet, drop it! */ - if (((struct rtable*)skb->dst)->key.iif =3D=3D 0) + if (((struct rtable*)skb->dst)->fl.iif =3D=3D 0) goto drop; tunnel->stat.multicast++; skb->pkt_type =3D PACKET_BROADCAST; @@ -665,12 +673,6 @@ return(0); } =20 -/* Need this wrapper because NF_HOOK takes the function address */ -static inline int do_ip_send(struct sk_buff *skb) -{ - return ip_send(skb); -} - static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel =3D (struct ip_tunnel*)dev->priv; @@ -747,9 +749,17 @@ tos &=3D ~1; } =20 - if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.lin= k)) { - tunnel->stat.tx_carrier_errors++; - goto tx_error; + { + struct flowi fl =3D { .oif =3D tunnel->parms.link, + .nl_u =3D { .ip4_u =3D + { .daddr =3D dst, + .saddr =3D tiph->saddr, + .tos =3D RT_TOS(tos) } }, + .proto =3D IPPROTO_GRE }; + if (ip_route_output_key(&rt, &fl)) { + tunnel->stat.tx_carrier_errors++; + goto tx_error; + } } tdev =3D rt->u.dst.dev; =20 @@ -761,14 +771,14 @@ =20 df =3D tiph->frag_off; if (df) - mtu =3D rt->u.dst.pmtu - tunnel->hlen; + mtu =3D dst_pmtu(&rt->u.dst) - tunnel->hlen; else - mtu =3D skb->dst ? skb->dst->pmtu : dev->mtu; + mtu =3D skb->dst ? dst_pmtu(skb->dst) : dev->mtu; =20 - if (skb->protocol =3D=3D htons(ETH_P_IP)) { - if (skb->dst && mtu < skb->dst->pmtu && mtu >=3D 68) - skb->dst->pmtu =3D mtu; + if (skb->dst) + skb->dst->ops->update_pmtu(skb->dst, mtu); =20 + if (skb->protocol =3D=3D htons(ETH_P_IP)) { df |=3D (old_iph->frag_off&htons(IP_DF)); =20 if ((old_iph->frag_off&htons(IP_DF)) && @@ -782,11 +792,11 @@ else if (skb->protocol =3D=3D htons(ETH_P_IPV6)) { struct rt6_info *rt6 =3D (struct rt6_info*)skb->dst; =20 - if (rt6 && mtu < rt6->u.dst.pmtu && mtu >=3D IPV6_MIN_MTU) { + if (rt6 && mtu < dst_pmtu(skb->dst) && mtu >=3D IPV6_MIN_MTU) { if ((tunnel->parms.iph.daddr && !MULTICAST(tunnel->parms.iph.daddr)) || rt6->rt6i_dst.plen =3D=3D 128) { rt6->rt6i_flags |=3D RTF_MODIFIED; - skb->dst->pmtu =3D mtu; + skb->dst->metrics[RTAX_MTU-1] =3D mtu; } } =20 @@ -809,7 +819,7 @@ =20 skb->h.raw =3D skb->nh.raw; =20 - max_headroom =3D ((tdev->hard_header_len+15)&~15)+ gre_hlen; + max_headroom =3D LL_RESERVED_SPACE(tdev) + gre_hlen; =20 if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb= )) { struct sk_buff *new_skb =3D skb_realloc_headroom(skb, max_headroom); @@ -1102,10 +1112,14 @@ =20 MOD_INC_USE_COUNT; if (MULTICAST(t->parms.iph.daddr)) { + struct flowi fl =3D { .oif =3D t->parms.link, + .nl_u =3D { .ip4_u =3D + { .daddr =3D t->parms.iph.daddr, + .saddr =3D t->parms.iph.saddr, + .tos =3D RT_TOS(t->parms.iph.tos) } }, + .proto =3D IPPROTO_GRE }; struct rtable *rt; - if (ip_route_output(&rt, t->parms.iph.daddr, - t->parms.iph.saddr, RT_TOS(t->parms.iph.tos),=20 - t->parms.link)) { + if (ip_route_output_key(&rt, &fl)) { MOD_DEC_USE_COUNT; return -EADDRNOTAVAIL; } @@ -1175,8 +1189,14 @@ /* Guess output device to choose reasonable mtu and hard_header_len */ =20 if (iph->daddr) { + struct flowi fl =3D { .oif =3D tunnel->parms.link, + .nl_u =3D { .ip4_u =3D + { .daddr =3D iph->daddr, + .saddr =3D iph->saddr, + .tos =3D RT_TOS(iph->tos) } }, + .proto =3D IPPROTO_GRE }; struct rtable *rt; - if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunn= el->parms.link)) { + if (!ip_route_output_key(&rt, &fl)) { tdev =3D rt->u.dst.dev; ip_rt_put(rt); } @@ -1257,13 +1277,8 @@ =20 =20 static struct inet_protocol ipgre_protocol =3D { - ipgre_rcv, /* GRE handler */ - ipgre_err, /* TUNNEL error control */ - 0, /* next */ - IPPROTO_GRE, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "GRE" /* name */ + .handler =3D ipgre_rcv, + .err_handler =3D ipgre_err, }; =20 =20 @@ -1279,9 +1294,13 @@ { printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); =20 + if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) { + printk(KERN_INFO "ipgre init: can't add protocol\n"); + return -EAGAIN; + } + ipgre_fb_tunnel_dev.priv =3D (void*)&ipgre_fb_tunnel; register_netdev(&ipgre_fb_tunnel_dev); - inet_add_protocol(&ipgre_protocol); return 0; } =20 @@ -1289,7 +1308,7 @@ =20 void cleanup_module(void) { - if ( inet_del_protocol(&ipgre_protocol) < 0 ) + if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) printk(KERN_INFO "ipgre close: can't remove protocol\n"); =20 unregister_netdev(&ipgre_fb_tunnel_dev); diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c --- a/net/ipv4/ip_input.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/ip_input.c Thu May 8 10:41:36 2003 @@ -141,6 +141,7 @@ #include #include #include +#include #include #include =20 @@ -194,28 +195,6 @@ return 0; } =20 -/* Handle this out of line, it is rare. */ -static int ip_run_ipprot(struct sk_buff *skb, struct iphdr *iph, - struct inet_protocol *ipprot, int force_copy) -{ - int ret =3D 0; - - do { - if (ipprot->protocol =3D=3D iph->protocol) { - struct sk_buff *skb2 =3D skb; - if (ipprot->copy || force_copy) - skb2 =3D skb_clone(skb, GFP_ATOMIC); - if(skb2 !=3D NULL) { - ret =3D 1; - ipprot->handler(skb2); - } - } - ipprot =3D (struct inet_protocol *) ipprot->next; - } while(ipprot !=3D NULL); - - return ret; -} - static inline int ip_local_deliver_finish(struct sk_buff *skb) { int ihl =3D skb->nh.iph->ihl*4; @@ -239,44 +218,40 @@ { /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE=3D=3DMAX_INET_PROTOS= */ int protocol =3D skb->nh.iph->protocol; - int hash =3D protocol & (MAX_INET_PROTOS - 1); - struct sock *raw_sk =3D raw_v4_htable[hash]; + int hash; + struct sock *raw_sk; struct inet_protocol *ipprot; - int flag; + + resubmit: + hash =3D protocol & (MAX_INET_PROTOS - 1); + raw_sk =3D raw_v4_htable[hash]; =20 /* If there maybe a raw socket we must check - if not we * don't care less */ - if(raw_sk !=3D NULL) - raw_sk =3D raw_v4_input(skb, skb->nh.iph, hash); + if (raw_sk) + raw_v4_input(skb, skb->nh.iph, hash); =20 - ipprot =3D (struct inet_protocol *) inet_protos[hash]; - flag =3D 0; - if(ipprot !=3D NULL) { - if(raw_sk =3D=3D NULL && - ipprot->next =3D=3D NULL && - ipprot->protocol =3D=3D protocol) { - int ret; - - /* Fast path... */ - ret =3D ipprot->handler(skb); - - return ret; - } else { - flag =3D ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk !=3D NULL)); - } - } + if ((ipprot =3D inet_protos[hash]) !=3D NULL) { + int ret; =20 - /* All protocols checked. - * If this packet was a broadcast, we may *not* reply to it, since that - * causes (proven, grin) ARP storms and a leakage of memory (i.e. all - * ICMP reply messages get queued up for transmission...) - */ - if(raw_sk !=3D NULL) { /* Shift to last raw user */ - raw_rcv(raw_sk, skb); - sock_put(raw_sk); - } else if (!flag) { /* Free and report errors */ - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);=09 + if (!ipprot->no_policy && + !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + return 0; + } + ret =3D ipprot->handler(skb); + if (ret < 0) { + protocol =3D -ret; + goto resubmit; + } + } else { + if (!raw_sk) { + if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { + icmp_send(skb, ICMP_DEST_UNREACH, + ICMP_PROT_UNREACH, 0); + } + } kfree_skb(skb); } } @@ -364,7 +339,7 @@ } } =20 - return skb->dst->input(skb); + return dst_input(skb); =20 inhdr_error: IP_INC_STATS_BH(IpInHdrErrors); diff -Nru a/net/ipv4/ip_nat_dumb.c b/net/ipv4/ip_nat_dumb.c --- a/net/ipv4/ip_nat_dumb.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/ip_nat_dumb.c Thu May 8 10:41:37 2003 @@ -117,23 +117,23 @@ if (rt->rt_flags&RTCF_SNAT) { if (ciph->daddr !=3D osaddr) { struct fib_result res; - struct rt_key key; unsigned flags =3D 0; - - key.src =3D ciph->daddr; - key.dst =3D ciph->saddr; - key.iif =3D skb->dev->ifindex; - key.oif =3D 0; + struct flowi fl =3D { + .iif =3D skb->dev->ifindex, + .nl_u =3D + { .ip4_u =3D + { .daddr =3D ciph->saddr, + .saddr =3D ciph->daddr, #ifdef CONFIG_IP_ROUTE_TOS - key.tos =3D RT_TOS(ciph->tos); -#endif -#ifdef CONFIG_IP_ROUTE_FWMARK - key.fwmark =3D 0; + .tos =3D RT_TOS(ciph->tos) #endif + } }, + .proto =3D ciph->protocol }; + /* Use fib_lookup() until we get our own * hash table of NATed hosts -- Rani */ - if (fib_lookup(&key, &res) =3D=3D 0) { + if (fib_lookup(&fl, &res) =3D=3D 0) { if (res.r) { ciph->daddr =3D fib_rules_policy(ciph->daddr, &res, &flags); if (ciph->daddr !=3D idaddr) diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c --- a/net/ipv4/ip_output.c Thu May 8 10:41:38 2003 +++ b/net/ipv4/ip_output.c Thu May 8 10:41:38 2003 @@ -15,6 +15,7 @@ * Stefan Becker, * Jorge Cwik, * Arnt Gulbrandsen, + * Hirokazu Takahashi, * * See ip_input.c for original log * @@ -38,6 +39,9 @@ * Marc Boucher : When call_out_firewall returns FW_QUEUE, * silently drop skb instead of failing with -EPERM. * Detlev Wengorz : Copy protocol for fragments. + * Hirokazu Takahashi: HW checksumming for outgoing UDP + * datagrams. + * Hirokazu Takahashi: sendfile() on UDP works now. */ =20 #include @@ -108,16 +112,9 @@ return 0; } =20 -/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook - changes route */ -static inline int -output_maybe_reroute(struct sk_buff *skb) -{ - return skb->dst->output(skb); -} - /*=20 * Add an ip header to a skbuff and send it out. + * */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, u32 saddr, u32 daddr, struct ip_options *opt) @@ -152,15 +149,34 @@ } ip_send_check(iph); =20 + skb->priority =3D sk->priority; + /* Send it out. */ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, - output_maybe_reroute); + dst_output); } =20 static inline int ip_finish_output2(struct sk_buff *skb) { struct dst_entry *dst =3D skb->dst; struct hh_cache *hh =3D dst->hh; + struct net_device *dev =3D dst->dev; + int hh_len =3D LL_RESERVED_SPACE(dev); + + /* Be paranoid, rather than too clever. */ + if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) { + struct sk_buff *skb2; + + skb2 =3D skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); + if (skb2 =3D=3D NULL) { + kfree_skb(skb); + return -ENOMEM; + } + if (skb->sk) + skb_set_owner_w(skb2, skb->sk); + kfree_skb(skb); + skb =3D skb2; + } =20 #ifdef CONFIG_NETFILTER_DEBUG nf_debug_ip_finish_output2(skb); @@ -181,7 +197,7 @@ return -EINVAL; } =20 -__inline__ int ip_finish_output(struct sk_buff *skb) +int ip_finish_output(struct sk_buff *skb) { struct net_device *dev =3D skb->dst->dev; =20 @@ -202,10 +218,6 @@ * If the indicated interface is up and running, send the packet. */ IP_INC_STATS(IpOutRequests); -#ifdef CONFIG_IP_ROUTE_NAT - if (rt->rt_flags & RTCF_NAT) - ip_do_nat(skb); -#endif =20 skb->dev =3D dev; skb->protocol =3D htons(ETH_P_IP); @@ -250,90 +262,26 @@ newskb->dev, ip_dev_loopback_xmit); } =20 - return ip_finish_output(skb); + if (skb->len > dst_pmtu(&rt->u.dst) || skb_shinfo(skb)->frag_list) + return ip_fragment(skb, ip_finish_output); + else + return ip_finish_output(skb); } =20 int ip_output(struct sk_buff *skb) { -#ifdef CONFIG_IP_ROUTE_NAT - struct rtable *rt =3D (struct rtable*)skb->dst; -#endif - IP_INC_STATS(IpOutRequests); =20 -#ifdef CONFIG_IP_ROUTE_NAT - if (rt->rt_flags&RTCF_NAT) - ip_do_nat(skb); + if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list) && +#ifdef NETIF_F_TSO + !skb_shinfo(skb)->tso_size +#else + 1 #endif - - return ip_finish_output(skb); -} - -/* Queues a packet to be sent, and starts the transmitter if necessary. =20 - * This routine also needs to put in the total length and compute the=20 - * checksum. We use to do this in two stages, ip_build_header() then - * this, but that scheme created a mess when routes disappeared etc. - * So we do it all here, and the TCP send engine has been changed to - * match. (No more unroutable FIN disasters, etc. wheee...) This will - * most likely make other reliable transport layers above IP easier - * to implement under Linux. - */ -static inline int ip_queue_xmit2(struct sk_buff *skb) -{ - struct sock *sk =3D skb->sk; - struct rtable *rt =3D (struct rtable *)skb->dst; - struct net_device *dev; - struct iphdr *iph =3D skb->nh.iph; - - dev =3D rt->u.dst.dev; - - /* This can happen when the transport layer has segments queued - * with a cached route, and by the time we get here things are - * re-routed to a device with a different MTU than the original - * device. Sick, but we must cover it. - */ - if (skb_headroom(skb) < dev->hard_header_len && dev->hard_header) { - struct sk_buff *skb2; - - skb2 =3D skb_realloc_headroom(skb, (dev->hard_header_len + 15) & ~15); - kfree_skb(skb); - if (skb2 =3D=3D NULL) - return -ENOMEM; - if (sk) - skb_set_owner_w(skb2, sk); - skb =3D skb2; - iph =3D skb->nh.iph; - } - - if (skb->len > rt->u.dst.pmtu) - goto fragment; - - ip_select_ident(iph, &rt->u.dst, sk); - - /* Add an IP checksum. */ - ip_send_check(iph); - - skb->priority =3D sk->priority; - return skb->dst->output(skb); - -fragment: - if (ip_dont_fragment(sk, &rt->u.dst)) { - /* Reject packet ONLY if TCP might fragment - * it itself, if were careful enough. - */ - NETDEBUG(printk(KERN_DEBUG "sending pkt_too_big (len[%u] pmtu[%u]) to se= lf\n", - skb->len, rt->u.dst.pmtu)); - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(rt->u.dst.pmtu)); - kfree_skb(skb); - return -EMSGSIZE; - } - ip_select_ident(iph, &rt->u.dst, sk); - if (skb->ip_summed =3D=3D CHECKSUM_HW && - (skb =3D skb_checksum_help(skb)) =3D=3D NULL) - return -ENOMEM; - return ip_fragment(skb, skb->dst->output); + ) + return ip_fragment(skb, ip_finish_output); + else + return ip_finish_output(skb); } =20 int ip_queue_xmit(struct sk_buff *skb) @@ -342,6 +290,9 @@ struct ip_options *opt =3D sk->protinfo.af_inet.opt; struct rtable *rt; struct iphdr *iph; +#ifdef NETIF_F_TSO + u32 mtu; +#endif =20 /* Skip all of this if the packet is already routed, * f.e. by something like SCTP. @@ -360,14 +311,24 @@ if(opt && opt->srr) daddr =3D opt->faddr; =20 - /* If this fails, retransmit mechanism of transport layer will - * keep trying until route appears or the connection times itself - * out. - */ - if (ip_route_output(&rt, daddr, sk->saddr, - RT_CONN_FLAGS(sk), - sk->bound_dev_if)) - goto no_route; + { + struct flowi fl =3D { .oif =3D sk->bound_dev_if, + .nl_u =3D { .ip4_u =3D + { .daddr =3D daddr, + .saddr =3D sk->saddr, + .tos =3D RT_CONN_FLAGS(sk) } }, + .proto =3D sk->protocol, + .uli_u =3D { .ports =3D + { .sport =3D sk->sport, + .dport =3D sk->dport } } }; + + /* If this fails, retransmit mechanism of transport layer will + * keep trying until route appears or the connection times + * itself out. + */ + if (ip_route_output_flow(&rt, &fl, sk, 0)) + goto no_route; + } __sk_dst_set(sk, &rt->u.dst); sk->route_caps =3D rt->u.dst.dev->features; } @@ -397,8 +358,30 @@ ip_options_build(skb, opt, sk->daddr, rt, 0); } =20 +#ifdef NETIF_F_TSO + mtu =3D dst_pmtu(&rt->u.dst); + if (skb->len > mtu && (sk->route_caps&NETIF_F_TSO)) { + unsigned int hlen; + + /* Hack zone: all this must be done by TCP. */ + hlen =3D ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + skb_shinfo(skb)->tso_size =3D mtu - hlen; + skb_shinfo(skb)->tso_segs =3D + (skb->len - hlen + skb_shinfo(skb)->tso_size - 1)/ + skb_shinfo(skb)->tso_size - 1; + } + ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs); +#else + ip_select_ident(iph, &rt->u.dst, sk); +#endif + + /* Add an IP checksum. */ + ip_send_check(iph); + + skb->priority =3D sk->priority; + return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, - ip_queue_xmit2); + dst_output); =20 no_route: IP_INC_STATS(IpOutNoRoutes); @@ -406,336 +389,30 @@ return -EHOSTUNREACH; } =20 -/* - * Build and send a packet, with as little as one copy - * - * Doesn't care much about ip options... option length can be - * different for fragment at 0 and other fragments. - * - * Note that the fragment at the highest offset is sent first, - * so the getfrag routine can fill in the TCP/UDP checksum header - * field in the last fragment it sends... actually it also helps - * the reassemblers, they can put most packets in at the head of - * the fragment queue, and they know the total size in advance. This - * last feature will measurably improve the Linux fragment handler one - * day. - * - * The callback has five args, an arbitrary pointer (copy of frag), - * the source IP address (may depend on the routing table), the=20 - * destination address (char *), the offset to copy from, and the - * length to be copied. - */ - -static int ip_build_xmit_slow(struct sock *sk, - int getfrag (const void *, - char *, - unsigned int,=09 - unsigned int), - const void *frag, - unsigned length, - struct ipcm_cookie *ipc, - struct rtable *rt, - int flags) +static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) { - unsigned int fraglen, maxfraglen, fragheaderlen; - int err; - int offset, mf; - int mtu; - u16 id; - - int hh_len =3D (rt->u.dst.dev->hard_header_len + 15)&~15; - int nfrags=3D0; - struct ip_options *opt =3D ipc->opt; - int df =3D 0; - - mtu =3D rt->u.dst.pmtu; - if (ip_dont_fragment(sk, &rt->u.dst)) - df =3D htons(IP_DF); - - length -=3D sizeof(struct iphdr); + to->pkt_type =3D from->pkt_type; + to->priority =3D from->priority; + to->protocol =3D from->protocol; + to->security =3D from->security; + to->dst =3D dst_clone(from->dst); + to->dev =3D from->dev; =20 - if (opt) { - fragheaderlen =3D sizeof(struct iphdr) + opt->optlen; - maxfraglen =3D ((mtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheade= rlen; - } else { - fragheaderlen =3D sizeof(struct iphdr); - - /* - * Fragheaderlen is the size of 'overhead' on each buffer. Now work - * out the size of the frames to send. - */ - - maxfraglen =3D ((mtu-sizeof(struct iphdr)) & ~7) + fragheaderlen; - } - - if (length + fragheaderlen > 0xFFFF) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu); - return -EMSGSIZE; - } - - /* - * Start at the end of the frame by handling the remainder. - */ - - offset =3D length - (length % (maxfraglen - fragheaderlen)); - - /* - * Amount of memory to allocate for final fragment. - */ - - fraglen =3D length - offset + fragheaderlen; - - if (length-offset=3D=3D0) { - fraglen =3D maxfraglen; - offset -=3D maxfraglen-fragheaderlen; - } - - /* - * The last fragment will not have MF (more fragments) set. - */ - - mf =3D 0; - - /* - * Don't fragment packets for path mtu discovery. - */ + /* Copy the flags to each fragment. */ + IPCB(to)->flags =3D IPCB(from)->flags; =20 - if (offset > 0 && sk->protinfo.af_inet.pmtudisc=3D=3DIP_PMTUDISC_DO) {=20 - ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu); - return -EMSGSIZE; - } - if (flags&MSG_PROBE) - goto out; - - /* - * Begin outputting the bytes. - */ - - id =3D sk->protinfo.af_inet.id++; - - do { - char *data; - struct sk_buff * skb; - - /* - * Get the memory we require with some space left for alignment. - */ - if (!(flags & MSG_DONTWAIT) || nfrags =3D=3D 0) { - skb =3D sock_alloc_send_skb(sk, fraglen + hh_len + 15, - (flags & MSG_DONTWAIT), &err); - } else { - /* On a non-blocking write, we check for send buffer - * usage on the first fragment only. - */ - skb =3D sock_wmalloc(sk, fraglen + hh_len + 15, 1, - sk->allocation); - if (!skb) - err =3D -ENOBUFS; - } - if (skb =3D=3D NULL) - goto error; - - /* - * Fill in the control structures - */ - - skb->priority =3D sk->priority; - skb->dst =3D dst_clone(&rt->u.dst); - skb_reserve(skb, hh_len); - - /* - * Find where to start putting bytes. - */ - - data =3D skb_put(skb, fraglen); - skb->nh.iph =3D (struct iphdr *)data; - - /* - * Only write IP header onto non-raw packets=20 - */ - - { - struct iphdr *iph =3D (struct iphdr *)data; - - iph->version =3D 4; - iph->ihl =3D 5; - if (opt) { - iph->ihl +=3D opt->optlen>>2; - ip_options_build(skb, opt, - ipc->addr, rt, offset); - } - iph->tos =3D sk->protinfo.af_inet.tos; - iph->tot_len =3D htons(fraglen - fragheaderlen + iph->ihl*4); - iph->frag_off =3D htons(offset>>3)|mf|df; - iph->id =3D id; - if (!mf) { - if (offset || !df) { - /* Select an unpredictable ident only - * for packets without DF or having - * been fragmented. - */ - __ip_select_ident(iph, &rt->u.dst); - id =3D iph->id; - } - - /* - * Any further fragments will have MF set. - */ - mf =3D htons(IP_MF); - } - if (rt->rt_type =3D=3D RTN_MULTICAST) - iph->ttl =3D sk->protinfo.af_inet.mc_ttl; - else - iph->ttl =3D sk->protinfo.af_inet.ttl; - iph->protocol =3D sk->protocol; - iph->check =3D 0; - iph->saddr =3D rt->rt_src; - iph->daddr =3D rt->rt_dst; - iph->check =3D ip_fast_csum((unsigned char *)iph, iph->ihl); - data +=3D iph->ihl*4; - } - - /* - * User data callback - */ - - if (getfrag(frag, data, offset, fraglen-fragheaderlen)) { - err =3D -EFAULT; - kfree_skb(skb); - goto error; - } - - offset -=3D (maxfraglen-fragheaderlen); - fraglen =3D maxfraglen; - - nfrags++; - - err =3D NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,=20 - skb->dst->dev, output_maybe_reroute); - if (err) { - if (err > 0) - err =3D sk->protinfo.af_inet.recverr ? net_xmit_errno(err) : 0; - if (err) - goto error; - } - } while (offset >=3D 0); - - if (nfrags>1) - ip_statistics[smp_processor_id()*2 + !in_softirq()].IpFragCreates +=3D n= frags; -out: - return 0; - -error: - IP_INC_STATS(IpOutDiscards); - if (nfrags>1) - ip_statistics[smp_processor_id()*2 + !in_softirq()].IpFragCreates +=3D n= frags; - return err;=20 -} - -/* - * Fast path for unfragmented packets. - */ -int ip_build_xmit(struct sock *sk,=20 - int getfrag (const void *, - char *, - unsigned int,=09 - unsigned int), - const void *frag, - unsigned length, - struct ipcm_cookie *ipc, - struct rtable *rt, - int flags) -{ - int err; - struct sk_buff *skb; - int df; - struct iphdr *iph; - - /* - * Try the simple case first. This leaves fragmented frames, and by - * choice RAW frames within 20 bytes of maximum size(rare) to the long pa= th - */ - - if (!sk->protinfo.af_inet.hdrincl) { - length +=3D sizeof(struct iphdr); - - /* - * Check for slow path. - */ - if (length > rt->u.dst.pmtu || ipc->opt !=3D NULL) =20 - return ip_build_xmit_slow(sk,getfrag,frag,length,ipc,rt,flags);=20 - } else { - if (length > rt->u.dst.dev->mtu) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, rt->u.dst.dev->mtu)= ; - return -EMSGSIZE; - } - } - if (flags&MSG_PROBE) - goto out; - - /* - * Do path mtu discovery if needed. - */ - df =3D 0; - if (ip_dont_fragment(sk, &rt->u.dst)) - df =3D htons(IP_DF); - - /*=20 - * Fast path for unfragmented frames without options.=20 - */=20 - { - int hh_len =3D (rt->u.dst.dev->hard_header_len + 15)&~15; - - skb =3D sock_alloc_send_skb(sk, length+hh_len+15, - flags&MSG_DONTWAIT, &err); - if(skb=3D=3DNULL) - goto error;=20 - skb_reserve(skb, hh_len); - } - - skb->priority =3D sk->priority; - skb->dst =3D dst_clone(&rt->u.dst); - - skb->nh.iph =3D iph =3D (struct iphdr *)skb_put(skb, length); - - if(!sk->protinfo.af_inet.hdrincl) { - iph->version=3D4; - iph->ihl=3D5; - iph->tos=3Dsk->protinfo.af_inet.tos; - iph->tot_len =3D htons(length); - iph->frag_off =3D df; - iph->ttl=3Dsk->protinfo.af_inet.mc_ttl; - ip_select_ident(iph, &rt->u.dst, sk); - if (rt->rt_type !=3D RTN_MULTICAST) - iph->ttl=3Dsk->protinfo.af_inet.ttl; - iph->protocol=3Dsk->protocol; - iph->saddr=3Drt->rt_src; - iph->daddr=3Drt->rt_dst; - iph->check=3D0; - iph->check =3D ip_fast_csum((unsigned char *)iph, iph->ihl); - err =3D getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4); - } - else - err =3D getfrag(frag, (void *)iph, 0, length); - - if (err) - goto error_fault; - - err =3D NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, - output_maybe_reroute); - if (err > 0) - err =3D sk->protinfo.af_inet.recverr ? net_xmit_errno(err) : 0; - if (err) - goto error; -out: - return 0; - -error_fault: - err =3D -EFAULT; - kfree_skb(skb); -error: - IP_INC_STATS(IpOutDiscards); - return err;=20 +#ifdef CONFIG_NET_SCHED + to->tc_index =3D from->tc_index; +#endif +#ifdef CONFIG_NETFILTER + to->nfmark =3D from->nfmark; + /* Connection association is same as pre-frag packet */ + to->nfct =3D from->nfct; + nf_conntrack_get(to->nfct); +#ifdef CONFIG_NETFILTER_DEBUG + to->nf_debug =3D from->nf_debug; +#endif +#endif } =20 /* @@ -743,8 +420,6 @@ * smaller pieces (each of size equal to IP header plus * a block of the data of the original IP data part) that will yet fit in = a * single device frame, and queue such a frame for sending. - * - * Yes this is inefficient, feel free to submit a quicker one. */ =20 int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) @@ -768,13 +443,111 @@ =20 iph =3D skb->nh.iph; =20 + if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(dst_pmtu(&rt->u.dst))); + kfree_skb(skb); + return -EMSGSIZE; + } + /* * Setup starting values. */ =20 hlen =3D iph->ihl * 4; + mtu =3D dst_pmtu(&rt->u.dst) - hlen; /* Size of data space */ + + /* When frag_list is given, use it. First, check its validity: + * some transformers could create wrong frag_list or break existing + * one, it is not prohibited. In this case fall back to copying. + * + * LATER: this step can be merged to real generation of fragments, + * we can switch to copy when see the first bad fragment. + */ + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *frag; + int first_len =3D skb_pagelen(skb); + + if (first_len - hlen > mtu || + ((first_len - hlen) & 7) || + (iph->frag_off & htons(IP_MF|IP_OFFSET)) || + skb_cloned(skb)) + goto slow_path; + + for (frag =3D skb_shinfo(skb)->frag_list; frag; frag =3D frag->next) { + /* Correct geometry. */ + if (frag->len > mtu || + ((frag->len & 7) && frag->next) || + skb_headroom(frag) < hlen) + goto slow_path; + + /* Correct socket ownership. */ + if (frag->sk =3D=3D NULL) + goto slow_path; + + /* Partially cloned skb? */ + if (skb_shared(frag)) + goto slow_path; + } + + /* Everything is OK. Generate! */ + + err =3D 0; + offset =3D 0; + frag =3D skb_shinfo(skb)->frag_list; + skb_shinfo(skb)->frag_list =3D 0; + skb->data_len =3D first_len - skb_headlen(skb); + skb->len =3D first_len; + iph->tot_len =3D htons(first_len); + iph->frag_off |=3D htons(IP_MF); + ip_send_check(iph); + + for (;;) { + /* Prepare header of the next frame, + * before previous one went down. */ + if (frag) { + frag->h.raw =3D frag->data; + frag->nh.raw =3D __skb_push(frag, hlen); + memcpy(frag->nh.raw, iph, hlen); + iph =3D frag->nh.iph; + iph->tot_len =3D htons(frag->len); + ip_copy_metadata(frag, skb); + if (offset =3D=3D 0) + ip_options_fragment(frag); + offset +=3D skb->len - hlen; + iph->frag_off =3D htons(offset>>3); + if (frag->next !=3D NULL) + iph->frag_off |=3D htons(IP_MF); + /* Ready, complete checksum */ + ip_send_check(iph); + } + + err =3D output(skb); + + if (err || !frag) + break; + + skb =3D frag; + frag =3D skb->next; + skb->next =3D NULL; + } + + if (err =3D=3D 0) { + IP_INC_STATS(IpFragOKs); + return 0; + } + + while (frag) { + skb =3D frag->next; + kfree_skb(frag); + frag =3D skb; + } + IP_INC_STATS(IpFragFails); + return err; + } + +slow_path: left =3D skb->len - hlen; /* Space per frame */ - mtu =3D rt->u.dst.pmtu - hlen; /* Size of data space */ ptr =3D raw + hlen; /* Where to start from */ =20 /* @@ -802,7 +575,7 @@ * Allocate buffer. */ =20 - if ((skb2 =3D alloc_skb(len+hlen+dev->hard_header_len+15,GFP_ATOMIC)) = =3D=3D NULL) { + if ((skb2 =3D alloc_skb(len+hlen+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_A= TOMIC)) =3D=3D NULL) { NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n")); err =3D -ENOMEM; goto fail; @@ -812,14 +585,11 @@ * Set up data on packet */ =20 - skb2->pkt_type =3D skb->pkt_type; - skb2->priority =3D skb->priority; - skb_reserve(skb2, (dev->hard_header_len+15)&~15); + ip_copy_metadata(skb2, skb); + skb_reserve(skb2, LL_RESERVED_SPACE(rt->u.dst.dev)); skb_put(skb2, len + hlen); skb2->nh.raw =3D skb2->data; skb2->h.raw =3D skb2->data + hlen; - skb2->protocol =3D skb->protocol; - skb2->security =3D skb->security; =20 /* * Charge the memory for the fragment to any owner @@ -828,8 +598,6 @@ =20 if (skb->sk) skb_set_owner_w(skb2, skb->sk); - skb2->dst =3D dst_clone(skb->dst); - skb2->dev =3D skb->dev; =20 /* * Copy the packet header into the new buffer. @@ -859,9 +627,6 @@ if (offset =3D=3D 0) ip_options_fragment(skb); =20 - /* Copy the flags to each fragment. */ - IPCB(skb2)->flags =3D IPCB(skb)->flags; - /* * Added AC : If we are fragmenting a fragment that's not the * last fragment then keep MF on each bit @@ -871,19 +636,6 @@ ptr +=3D len; offset +=3D len; =20 -#ifdef CONFIG_NET_SCHED - skb2->tc_index =3D skb->tc_index; -#endif -#ifdef CONFIG_NETFILTER - skb2->nfmark =3D skb->nfmark; - /* Connection association is same as pre-frag packet */ - skb2->nfct =3D skb->nfct; - nf_conntrack_get(skb2->nfct); -#ifdef CONFIG_NETFILTER_DEBUG - skb2->nf_debug =3D skb->nf_debug; -#endif -#endif - /* * Put this fragment into the sending queue. */ @@ -908,40 +660,562 @@ return err; } =20 +int +ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, str= uct sk_buff *skb) +{ + struct iovec *iov =3D from; + + if (skb->ip_summed =3D=3D CHECKSUM_HW) { + if (memcpy_fromiovecend(to, iov, offset, len) < 0) + return -EFAULT; + } else { + unsigned int csum =3D 0; + if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) + return -EFAULT; + skb->csum =3D csum_block_add(skb->csum, csum, odd); + } + return 0; +} + +static inline int +skb_can_coalesce(struct sk_buff *skb, int i, struct page *page, int off) +{ + if (i) { + skb_frag_t *frag =3D &skb_shinfo(skb)->frags[i-1]; + return page =3D=3D frag->page && + off =3D=3D frag->page_offset+frag->size; + } + return 0; +} + +static void +skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off,= int size) +{ + skb_frag_t *frag =3D &skb_shinfo(skb)->frags[i]; + frag->page =3D page; + frag->page_offset =3D off; + frag->size =3D size; + skb_shinfo(skb)->nr_frags =3D i+1; +} + +static inline unsigned int +csum_page(struct page *page, int offset, int copy) +{ + char *kaddr; + unsigned int csum; + kaddr =3D kmap(page); + csum =3D csum_partial(kaddr + offset, copy, 0); + kunmap(page); + return csum; +} + /* - * Fetch data from kernel space and fill in checksum if needed. + * ip_append_data() and ip_append_page() can make one large IP datagram + * from many pieces of data. Each pieces will be holded on the socket + * until ip_push_pending_frames() is called. Eache pieces can be a page + * or non-page data. + *=09 + * Not only UDP, other transport protocols - e.g. raw sockets - can use + * this interface potentially. + * + * LATER: length must be adjusted by pad at tail, when it is required. */ -static int ip_reply_glue_bits(const void *dptr, char *to, unsigned int off= set,=20 - unsigned int fraglen) +int ip_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, int len, + int odd, struct sk_buff *skb), + void *from, int length, int transhdrlen, + struct ipcm_cookie *ipc, struct rtable *rt, + unsigned int flags) { - struct ip_reply_arg *dp =3D (struct ip_reply_arg*)dptr; - u16 *pktp =3D (u16 *)to; - struct iovec *iov;=20 - int len;=20 - int hdrflag =3D 1;=20 - - iov =3D &dp->iov[0];=20 - if (offset >=3D iov->iov_len) {=20 - offset -=3D iov->iov_len; - iov++;=20 - hdrflag =3D 0;=20 - } - len =3D iov->iov_len - offset; - if (fraglen > len) { /* overlapping. */=20 - dp->csum =3D csum_partial_copy_nocheck(iov->iov_base+offset, to, len, - dp->csum); - offset =3D 0; - fraglen -=3D len;=20 - to +=3D len;=20 - iov++; + struct inet_opt *inet =3D inet_sk(sk); + struct sk_buff *skb; + + struct ip_options *opt =3D NULL; + int hh_len; + int exthdrlen; + int mtu; + int copy; + int err; + int offset =3D 0; + unsigned int maxfraglen, fragheaderlen; + int csummode =3D CHECKSUM_NONE; + + if (flags&MSG_PROBE) + return 0; + + if (skb_queue_empty(&sk->write_queue)) { + /* + * setup for corking. + */ + opt =3D ipc->opt; + if (opt) { + if (inet->cork.opt =3D=3D NULL) + inet->cork.opt =3D kmalloc(sizeof(struct ip_options)+40, sk->allocatio= n); + memcpy(inet->cork.opt, opt, sizeof(struct ip_options)+opt->optlen); + inet->cork.flags |=3D IPCORK_OPT; + inet->cork.addr =3D ipc->addr; + } + dst_hold(&rt->u.dst); + inet->cork.fragsize =3D mtu =3D dst_pmtu(&rt->u.dst); + inet->cork.rt =3D rt; + inet->cork.length =3D 0; + inet->sndmsg_page =3D NULL; + inet->sndmsg_off =3D 0; + if ((exthdrlen =3D rt->u.dst.header_len) !=3D 0) { + length +=3D exthdrlen; + transhdrlen +=3D exthdrlen; + } + } else { + rt =3D inet->cork.rt; + if (inet->cork.flags & IPCORK_OPT) + opt =3D inet->cork.opt; + + transhdrlen =3D 0; + exthdrlen =3D 0; + mtu =3D inet->cork.fragsize; + } + hh_len =3D LL_RESERVED_SPACE(rt->u.dst.dev); + + fragheaderlen =3D sizeof(struct iphdr) + (opt ? opt->optlen : 0); + maxfraglen =3D ((mtu-fragheaderlen) & ~7) + fragheaderlen; + + if (inet->cork.length + length > 0xFFFF - fragheaderlen) { + ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu-exthdrlen); + return -EMSGSIZE; + } + + /* + * transhdrlen > 0 means that this is the first fragment and we wish + * it won't be fragmented in the future. + */ + if (transhdrlen && + length + fragheaderlen <=3D maxfraglen && + rt->u.dst.dev->features&(NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_C= SUM) && + !exthdrlen) + csummode =3D CHECKSUM_HW; + + inet->cork.length +=3D length; + + /* So, what's going on in the loop below? + * + * We use calculated fragment length to generate chained skb, + * each of segments is IP fragment ready for sending to network after + * adding appropriate IP header. + * + * Mistake is: + * + * If mtu-fragheaderlen is not 0 modulo 8, we generate additional + * small fragment of length (mtu-fragheaderlen)%8, even though + * it is not necessary. Not a big bug, but needs a fix. + */ + + if ((skb =3D skb_peek_tail(&sk->write_queue)) =3D=3D NULL) + goto alloc_new_skb; + + while (length > 0) { + if ((copy =3D maxfraglen - skb->len) <=3D 0) { + char *data; + unsigned int datalen; + unsigned int fraglen; + unsigned int alloclen; + BUG_TRAP(copy =3D=3D 0); + +alloc_new_skb: + datalen =3D maxfraglen - fragheaderlen; + if (datalen > length) + datalen =3D length; + + fraglen =3D datalen + fragheaderlen; + if ((flags & MSG_MORE) &&=20 + !(rt->u.dst.dev->features&NETIF_F_SG)) + alloclen =3D maxfraglen; + else + alloclen =3D datalen + fragheaderlen; + + /* The last fragment gets additional space at tail. + * Note, with MSG_MORE we overallocate on fragments, + * because we have no idea what fragment will be + * the last. + */ + if (datalen =3D=3D length) + alloclen +=3D rt->u.dst.trailer_len; + + if (transhdrlen) { + skb =3D sock_alloc_send_skb(sk,=20 + alloclen + hh_len + 15, + (flags & MSG_DONTWAIT), &err); + } else { + skb =3D NULL; + if (atomic_read(&sk->wmem_alloc) <=3D 2*sk->sndbuf) + skb =3D sock_wmalloc(sk,=20 + alloclen + hh_len + 15, 1, + sk->allocation); + if (unlikely(skb =3D=3D NULL)) + err =3D -ENOBUFS; + } + if (skb =3D=3D NULL) + goto error; + + /* + * Fill in the control structures + */ + skb->ip_summed =3D csummode; + skb->csum =3D 0; + skb_reserve(skb, hh_len); + + /* + * Find where to start putting bytes. + */ + data =3D skb_put(skb, fraglen); + skb->nh.raw =3D data + exthdrlen; + data +=3D fragheaderlen; + skb->h.raw =3D data + exthdrlen; + + copy =3D datalen - transhdrlen; + if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, 0, skb)= < 0) { + err =3D -EFAULT; + kfree_skb(skb); + goto error; + } + + offset +=3D copy; + length -=3D datalen; + transhdrlen =3D 0; + exthdrlen =3D 0; + csummode =3D CHECKSUM_NONE; + + /* + * Put the packet on the pending queue. + */ + __skb_queue_tail(&sk->write_queue, skb); + continue; + } + + if (copy > length) + copy =3D length; + + if (!(rt->u.dst.dev->features&NETIF_F_SG)) { + unsigned int off; + + off =3D skb->len; + if (getfrag(from, skb_put(skb, copy),=20 + offset, copy, off, skb) < 0) { + __skb_trim(skb, off); + err =3D -EFAULT; + goto error; + } + } else { + int i =3D skb_shinfo(skb)->nr_frags; + skb_frag_t *frag =3D &skb_shinfo(skb)->frags[i-1]; + struct page *page =3D inet->sndmsg_page; + int off =3D inet->sndmsg_off; + unsigned int left; + + if (page && (left =3D PAGE_SIZE - off) > 0) { + if (copy >=3D left) + copy =3D left; + if (page !=3D frag->page) { + if (i =3D=3D MAX_SKB_FRAGS) { + err =3D -EMSGSIZE; + goto error; + } + get_page(page); + skb_fill_page_desc(skb, i, page, inet->sndmsg_off, 0); + frag =3D &skb_shinfo(skb)->frags[i]; + } + } else if (i < MAX_SKB_FRAGS) { + if (copy > PAGE_SIZE) + copy =3D PAGE_SIZE; + page =3D alloc_pages(sk->allocation, 0); + if (page =3D=3D NULL) { + err =3D -ENOMEM; + goto error; + } + inet->sndmsg_page =3D page; + inet->sndmsg_off =3D 0; + + skb_fill_page_desc(skb, i, page, 0, 0); + frag =3D &skb_shinfo(skb)->frags[i]; + skb->truesize +=3D PAGE_SIZE; + atomic_add(PAGE_SIZE, &sk->wmem_alloc); + } else { + err =3D -EMSGSIZE; + goto error; + } + if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size= , offset, copy, skb->len, skb) < 0) { + err =3D -EFAULT; + goto error; + } + inet->sndmsg_off +=3D copy; + frag->size +=3D copy; + skb->len +=3D copy; + skb->data_len +=3D copy; + } + offset +=3D copy; + length -=3D copy; } =20 - dp->csum =3D csum_partial_copy_nocheck(iov->iov_base+offset, to, fraglen,= =20 - dp->csum);=20 + return 0; =20 - if (hdrflag && dp->csumoffset) - *(pktp + dp->csumoffset) =3D csum_fold(dp->csum); /* fill in checksum */ - return 0; =20 +error: + inet->cork.length -=3D length; + IP_INC_STATS(IpOutDiscards); + return err;=20 +} + +ssize_t ip_append_page(struct sock *sk, struct page *page, + int offset, size_t size, int flags) +{ + struct inet_opt *inet =3D inet_sk(sk); + struct sk_buff *skb; + struct rtable *rt; + struct ip_options *opt =3D NULL; + int hh_len; + int mtu; + int len; + int err; + unsigned int maxfraglen, fragheaderlen; + + if (inet->hdrincl) + return -EPERM; + + if (flags&MSG_PROBE) + return 0; + + if (skb_queue_empty(&sk->write_queue)) + return -EINVAL; + + rt =3D inet->cork.rt; + if (inet->cork.flags & IPCORK_OPT) + opt =3D inet->cork.opt; + + if (!(rt->u.dst.dev->features&NETIF_F_SG)) + return -EOPNOTSUPP; + + hh_len =3D LL_RESERVED_SPACE(rt->u.dst.dev); + mtu =3D inet->cork.fragsize; + + fragheaderlen =3D sizeof(struct iphdr) + (opt ? opt->optlen : 0); + maxfraglen =3D ((mtu-fragheaderlen) & ~7) + fragheaderlen; + + if (inet->cork.length + size > 0xFFFF - fragheaderlen) { + ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu); + return -EMSGSIZE; + } + + if ((skb =3D skb_peek_tail(&sk->write_queue)) =3D=3D NULL) + return -EINVAL; + + inet->cork.length +=3D size; + + while (size > 0) { + int i; + if ((len =3D maxfraglen - skb->len) <=3D 0) { + char *data; + struct iphdr *iph; + BUG_TRAP(len =3D=3D 0); + + skb =3D sock_wmalloc(sk, fragheaderlen + hh_len + 15, 1, + sk->allocation); + if (unlikely(!skb)) { + err =3D -ENOBUFS; + goto error; + } + + /* + * Fill in the control structures + */ + skb->ip_summed =3D CHECKSUM_NONE; + skb->csum =3D 0; + skb_reserve(skb, hh_len); + + /* + * Find where to start putting bytes. + */ + data =3D skb_put(skb, fragheaderlen); + skb->nh.iph =3D iph =3D (struct iphdr *)data; + data +=3D fragheaderlen; + skb->h.raw =3D data; + + /* + * Put the packet on the pending queue. + */ + __skb_queue_tail(&sk->write_queue, skb); + continue; + } + + i =3D skb_shinfo(skb)->nr_frags; + if (len > size) + len =3D size; + if (skb_can_coalesce(skb, i, page, offset)) { + skb_shinfo(skb)->frags[i-1].size +=3D len; + } else if (i < MAX_SKB_FRAGS) { + get_page(page); + skb_fill_page_desc(skb, i, page, offset, len); + } else { + err =3D -EMSGSIZE; + goto error; + } + + if (skb->ip_summed =3D=3D CHECKSUM_NONE) { + unsigned int csum; + csum =3D csum_page(page, offset, len); + skb->csum =3D csum_block_add(skb->csum, csum, skb->len); + } + + skb->len +=3D len; + skb->data_len +=3D len; + offset +=3D len; + size -=3D len; + } + return 0; + +error: + inet->cork.length -=3D size; + IP_INC_STATS(IpOutDiscards); + return err; +} + +/* + * Combined all pending IP fragments on the socket as one IP datagram + * and push them out. + */ +int ip_push_pending_frames(struct sock *sk) +{ + struct sk_buff *skb, *tmp_skb; + struct sk_buff **tail_skb; + struct inet_opt *inet =3D inet_sk(sk); + struct ip_options *opt =3D NULL; + struct rtable *rt =3D inet->cork.rt; + struct iphdr *iph; + int df =3D 0; + __u8 ttl; + int err =3D 0; + + if ((skb =3D __skb_dequeue(&sk->write_queue)) =3D=3D NULL) + goto out; + tail_skb =3D &(skb_shinfo(skb)->frag_list); + + /* move skb->data to ip header from ext header */ + if (skb->data < skb->nh.raw) + __skb_pull(skb, skb->nh.raw - skb->data); + while ((tmp_skb =3D __skb_dequeue(&sk->write_queue)) !=3D NULL) { + __skb_pull(tmp_skb, skb->h.raw - skb->nh.raw); + *tail_skb =3D tmp_skb; + tail_skb =3D &(tmp_skb->next); + skb->len +=3D tmp_skb->len; + skb->data_len +=3D tmp_skb->len; +#if 0 /* Logically correct, but useless work, ip_fragment() will have to u= ndo */ + skb->truesize +=3D tmp_skb->truesize; + __sock_put(tmp_skb->sk); + tmp_skb->destructor =3D NULL; + tmp_skb->sk =3D NULL; +#endif + } + + /* Unless user demanded real pmtu discovery (IP_PMTUDISC_DO), we allow + * to fragment the frame generated here. No matter, what transforms + * how transforms change size of the packet, it will come out. + */ + if (inet->pmtudisc !=3D IP_PMTUDISC_DO) + skb->local_df =3D 1; + + /* DF bit is set when we want to see DF on outgoing frames. + * If local_df is set too, we still allow to fragment this frame + * locally. */ + if (inet->pmtudisc =3D=3D IP_PMTUDISC_DO || + (!skb_shinfo(skb)->frag_list && ip_dont_fragment(sk, &rt->u.dst))) + df =3D htons(IP_DF); + + if (inet->cork.flags & IPCORK_OPT) + opt =3D inet->cork.opt; + + if (rt->rt_type =3D=3D RTN_MULTICAST) + ttl =3D inet->mc_ttl; + else + ttl =3D inet->ttl; + + iph =3D (struct iphdr *)skb->data; + iph->version =3D 4; + iph->ihl =3D 5; + if (opt) { + iph->ihl +=3D opt->optlen>>2; + ip_options_build(skb, opt, inet->cork.addr, rt, 0); + } + iph->tos =3D inet->tos; + iph->tot_len =3D htons(skb->len); + iph->frag_off =3D df; + if (!df) { + __ip_select_ident(iph, &rt->u.dst); + } else { + iph->id =3D htons(inet->id++); + } + iph->ttl =3D ttl; + iph->protocol =3D sk->protocol; + iph->saddr =3D rt->rt_src; + iph->daddr =3D rt->rt_dst; + ip_send_check(iph); + + skb->priority =3D sk->priority; + skb->dst =3D dst_clone(&rt->u.dst); + + /* Netfilter gets whole the not fragmented skb. */ + err =3D NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,=20 + skb->dst->dev, dst_output); + if (err) { + if (err > 0) + err =3D inet->recverr ? net_xmit_errno(err) : 0; + if (err) + goto error; + } + +out: + inet->cork.flags &=3D ~IPCORK_OPT; + if (inet->cork.rt) { + ip_rt_put(inet->cork.rt); + inet->cork.rt =3D NULL; + } + return err; + +error: + IP_INC_STATS(IpOutDiscards); + goto out; +} + +/* + * Throw away all pending data on the socket. + */ +void ip_flush_pending_frames(struct sock *sk) +{ + struct inet_opt *inet =3D inet_sk(sk); + struct sk_buff *skb; + + while ((skb =3D __skb_dequeue_tail(&sk->write_queue)) !=3D NULL) + kfree_skb(skb); + + inet->cork.flags &=3D ~IPCORK_OPT; + if (inet->cork.opt) { + kfree(inet->cork.opt); + inet->cork.opt =3D NULL; + } + if (inet->cork.rt) { + ip_rt_put(inet->cork.rt); + inet->cork.rt =3D NULL; + } +} + + +/* + * Fetch data from kernel space and fill in checksum if needed. + */ +static int ip_reply_glue_bits(void *dptr, char *to, int offset,=20 + int len, int odd, struct sk_buff *skb) +{ + unsigned int csum; + + csum =3D csum_partial_copy_nocheck(dptr+offset, to, len, 0); + skb->csum =3D csum_block_add(skb->csum, csum, odd); + return 0; =20 } =20 /*=20 @@ -950,6 +1224,8 @@ * * Should run single threaded per socket because it uses the sock=20 * structure to pass arguments. + * + * LATER: switch from ip_build_xmit to ip_append_* */ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_a= rg *arg, unsigned int len) @@ -975,8 +1251,19 @@ daddr =3D replyopts.opt.faddr; } =20 - if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos)= , 0)) - return; + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D daddr, + .saddr =3D rt->rt_spec_dst, + .tos =3D RT_TOS(skb->nh.iph->tos) } }, + /* Not quite clean, but right. */ + .uli_u =3D { .ports =3D + { .sport =3D skb->h.th->dest, + .dport =3D skb->h.th->source } }, + .proto =3D sk->protocol }; + if (ip_route_output_key(&rt, &fl)) + return; + } =20 /* And let IP do all the hard work. =20 @@ -988,7 +1275,15 @@ sk->protinfo.af_inet.tos =3D skb->nh.iph->tos; sk->priority =3D skb->priority; sk->protocol =3D skb->nh.iph->protocol; - ip_build_xmit(sk, ip_reply_glue_bits, arg, len, &ipc, rt, MSG_DONTWAIT); + ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0, + &ipc, rt, MSG_DONTWAIT); + if ((skb =3D skb_peek(&sk->write_queue)) !=3D NULL) { + if (arg->csumoffset >=3D 0) + *((u16 *)skb->h.raw + arg->csumoffset) =3D csum_fold(csum_add(skb->csum= , arg->csum)); + skb->ip_summed =3D CHECKSUM_NONE; + ip_push_pending_frames(sk); + } + bh_unlock_sock(sk); =20 ip_rt_put(rt); diff -Nru a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c --- a/net/ipv4/ip_sockglue.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/ip_sockglue.c Thu May 8 10:41:37 2003 @@ -36,6 +36,7 @@ #include #include #include +#include #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #include #endif @@ -380,6 +381,7 @@ =20 int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, i= nt optlen) { + struct inet_opt *inet =3D inet_sk(sk); int val=3D0,err; =20 if (level !=3D SOL_IP) @@ -431,8 +433,10 @@ (!((1<state)&(TCPF_LISTEN|TCPF_CLOSE)) && sk->daddr !=3D LOOPBACK4_IPV6)) { #endif + if (inet->opt) + tp->ext_header_len -=3D inet->opt->optlen; if (opt) - tp->ext_header_len =3D opt->optlen; + tp->ext_header_len +=3D opt->optlen; tcp_sync_mss(sk, tp->pmtu_cookie); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) } @@ -616,6 +620,11 @@ sk->protinfo.af_inet.freebind =3D !!val;=20 break; =09 =20 + case IP_IPSEC_POLICY: + case IP_XFRM_POLICY: + err =3D xfrm_user_policy(sk, optname, optval, optlen); + break; + default: #ifdef CONFIG_NETFILTER err =3D nf_setsockopt(sk, PF_INET, optname, optval,=20 @@ -717,7 +726,7 @@ val =3D 0; dst =3D sk_dst_get(sk); if (dst) { - val =3D dst->pmtu; + val =3D dst_pmtu(dst) - dst->header_len; dst_release(dst); } if (!val) { diff -Nru a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/ipcomp.c Thu May 8 10:41:38 2003 @@ -0,0 +1,376 @@ +/* + * IP Payload Compression Protocol (IPComp) - RFC3713. + * + * Copyright (c) 2003 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + * + * Todo: + * - Tunable compression parameters. + * - Compression stats. + * - Adaptive compression. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPCOMP_SCRATCH_SIZE 65400 + +struct ipcomp_hdr { + u8 nexthdr; + u8 flags; + u16 cpi; +}; + +struct ipcomp_data { + u16 threshold; + u8 *scratch; + struct crypto_tfm *tfm; +}; + +static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) +{ + int err, plen, dlen; + struct iphdr *iph; + struct ipcomp_data *ipcd =3D x->data; + u8 *start, *scratch =3D ipcd->scratch; +=09 + plen =3D skb->len; + dlen =3D IPCOMP_SCRATCH_SIZE; + start =3D skb->data; + + err =3D crypto_comp_decompress(ipcd->tfm, start, plen, scratch, &dlen); + if (err) + goto out; + + if (dlen < (plen + sizeof(struct ipcomp_hdr))) { + err =3D -EINVAL; + goto out; + } + + err =3D pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC); + if (err) + goto out; + =09 + skb_put(skb, dlen - plen); + memcpy(skb->data, scratch, dlen); + iph =3D skb->nh.iph; + iph->tot_len =3D htons(dlen + iph->ihl * 4); +out:=09 + return err; +} + +static int ipcomp_input(struct xfrm_state *x, + struct xfrm_decap_state *decap, struct sk_buff *sk= b) +{ + u8 nexthdr; + int err =3D 0; + struct iphdr *iph; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + + if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && + skb_linearize(skb, GFP_ATOMIC) !=3D 0) { + err =3D -ENOMEM; + goto out; + } + + skb->ip_summed =3D CHECKSUM_NONE; + + /* Remove ipcomp header and decompress original payload */=09 + iph =3D skb->nh.iph; + memcpy(&tmp_iph, iph, iph->ihl * 4); + nexthdr =3D *(u8 *)skb->data; + skb_pull(skb, sizeof(struct ipcomp_hdr)); + skb->nh.raw +=3D sizeof(struct ipcomp_hdr); + memcpy(skb->nh.raw, &tmp_iph, tmp_iph.iph.ihl * 4); + iph =3D skb->nh.iph; + iph->tot_len =3D htons(ntohs(iph->tot_len) - sizeof(struct ipcomp_hdr)); + iph->protocol =3D nexthdr; + skb->h.raw =3D skb->data; + err =3D ipcomp_decompress(x, skb); + +out:=09 + return err; +} + +static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb) +{ + int err, plen, dlen, ihlen; + struct iphdr *iph =3D skb->nh.iph; + struct ipcomp_data *ipcd =3D x->data; + u8 *start, *scratch =3D ipcd->scratch; +=09 + ihlen =3D iph->ihl * 4; + plen =3D skb->len - ihlen; + dlen =3D IPCOMP_SCRATCH_SIZE; + start =3D skb->data + ihlen; + + err =3D crypto_comp_compress(ipcd->tfm, start, plen, scratch, &dlen); + if (err) + goto out; + + if ((dlen + sizeof(struct ipcomp_hdr)) >=3D plen) { + err =3D -EMSGSIZE; + goto out; + } +=09 + memcpy(start, scratch, dlen); + pskb_trim(skb, ihlen + dlen); +=09 +out:=09 + return err; +} + +static void ipcomp_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) +{ + struct dst_entry *dst =3D skb->dst; + struct iphdr *iph, *top_iph; + + iph =3D skb->nh.iph; + top_iph =3D (struct iphdr *)skb_push(skb, sizeof(struct iphdr)); + top_iph->ihl =3D 5; + top_iph->version =3D 4; + top_iph->tos =3D iph->tos; + top_iph->tot_len =3D htons(skb->len); + if (!(iph->frag_off&htons(IP_DF))) { +#ifdef NETIF_F_TSO + __ip_select_ident(top_iph, dst, 0); +#else + __ip_select_ident(top_iph, dst); +#endif + } + top_iph->ttl =3D iph->ttl; + top_iph->check =3D 0; + top_iph->saddr =3D x->props.saddr.a4; + top_iph->daddr =3D x->id.daddr.a4; + top_iph->frag_off =3D iph->frag_off&~htons(IP_MF|IP_OFFSET); + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + skb->nh.raw =3D skb->data; +} + +static int ipcomp_output(struct sk_buff *skb) +{ + int err; + struct dst_entry *dst =3D skb->dst; + struct xfrm_state *x =3D dst->xfrm; + struct iphdr *iph, *top_iph; + struct ipcomp_hdr *ipch; + struct ipcomp_data *ipcd =3D x->data; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + if (skb->ip_summed =3D=3D CHECKSUM_HW && skb_checksum_help(skb) =3D=3D NU= LL) { + err =3D -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err =3D xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + + /* Don't bother compressing */ + if (skb->len < ipcd->threshold) { + if (x->props.mode) { + ipcomp_tunnel_encap(x, skb); + iph =3D skb->nh.iph; + iph->protocol =3D IPPROTO_IPIP; + ip_send_check(iph); + } + goto out_ok; + } + + if (x->props.mode)=20 + ipcomp_tunnel_encap(x, skb); + + if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && + skb_linearize(skb, GFP_ATOMIC) !=3D 0) { + err =3D -ENOMEM; + goto error; + } +=09 + err =3D ipcomp_compress(x, skb); + if (err) { + if (err =3D=3D -EMSGSIZE) { + if (x->props.mode) { + iph =3D skb->nh.iph; + iph->protocol =3D IPPROTO_IPIP; + ip_send_check(iph); + } + goto out_ok; + } + goto error; + } + + /* Install ipcomp header, convert into ipcomp datagram. */ + iph =3D skb->nh.iph; + memcpy(&tmp_iph, iph, iph->ihl * 4); + top_iph =3D (struct iphdr *)skb_push(skb, sizeof(struct ipcomp_hdr)); + memcpy(top_iph, &tmp_iph, iph->ihl * 4); + iph =3D top_iph; + iph->tot_len =3D htons(skb->len); + iph->protocol =3D IPPROTO_COMP; + iph->check =3D 0; + ipch =3D (struct ipcomp_hdr *)((char *)iph + iph->ihl * 4); + ipch->nexthdr =3D x->props.mode ? IPPROTO_IPIP : tmp_iph.iph.protocol; + ipch->flags =3D 0; + ipch->cpi =3D htons((u16 )ntohl(x->id.spi)); + ip_send_check(iph); + skb->nh.raw =3D skb->data; + +out_ok: + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); +=09 + if ((skb->dst =3D dst_pop(dst)) =3D=3D NULL) { + err =3D -EHOSTUNREACH; + goto error_nolock; + } + err =3D NET_XMIT_BYPASS; + +out_exit: + return err; +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + goto out_exit; +} + +static void ipcomp4_err(struct sk_buff *skb, u32 info) +{ + u32 spi; + struct iphdr *iph =3D (struct iphdr *)skb->data; + struct ipcomp_hdr *ipch =3D (struct ipcomp_hdr *)(skb->data+(iph->ihl<<2)= ); + struct xfrm_state *x; + + if (skb->h.icmph->type !=3D ICMP_DEST_UNREACH || + skb->h.icmph->code !=3D ICMP_FRAG_NEEDED) + return; + + spi =3D ntohl(ntohs(ipch->cpi)); + x =3D xfrm_state_lookup((xfrm_address_t *)&iph->daddr, + spi, IPPROTO_COMP, AF_INET); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA IPCOMP/%08x/%u.%u.%u.%u\n", + spi, NIPQUAD(iph->daddr)); + xfrm_state_put(x); +} + +static void ipcomp_free_data(struct ipcomp_data *ipcd) +{ + if (ipcd->tfm) + crypto_free_tfm(ipcd->tfm); + if (ipcd->scratch) + kfree(ipcd->scratch);=09 +} + +static void ipcomp_destroy(struct xfrm_state *x) +{ + struct ipcomp_data *ipcd =3D x->data; + ipcomp_free_data(ipcd); + kfree(ipcd); +} + +static int ipcomp_init_state(struct xfrm_state *x, void *args) +{ + int err =3D -ENOMEM; + struct ipcomp_data *ipcd; + struct xfrm_algo_desc *calg_desc; + + ipcd =3D kmalloc(sizeof(*ipcd), GFP_KERNEL); + if (!ipcd) + goto error; + + memset(ipcd, 0, sizeof(*ipcd)); + x->props.header_len =3D sizeof(struct ipcomp_hdr); + if (x->props.mode) + x->props.header_len +=3D sizeof(struct iphdr); + x->data =3D ipcd; + + ipcd->scratch =3D kmalloc(IPCOMP_SCRATCH_SIZE, GFP_KERNEL); + if (!ipcd->scratch) + goto error; +=09 + ipcd->tfm =3D crypto_alloc_tfm(x->calg->alg_name, 0); + if (!ipcd->tfm) + goto error; + + calg_desc =3D xfrm_calg_get_byname(x->calg->alg_name); + BUG_ON(!calg_desc); + ipcd->threshold =3D calg_desc->uinfo.comp.threshold; + err =3D 0; +out: + return err; + +error: + if (ipcd) { + ipcomp_free_data(ipcd); + kfree(ipcd); + } + goto out; +} + +static struct xfrm_type ipcomp_type =3D +{ + .description =3D "IPCOMP4", + .proto =3D IPPROTO_COMP, + .init_state =3D ipcomp_init_state, + .destructor =3D ipcomp_destroy, + .input =3D ipcomp_input, + .output =3D ipcomp_output +}; + +static struct inet_protocol ipcomp4_protocol =3D { + .handler =3D xfrm4_rcv, + .err_handler =3D ipcomp4_err, + .no_policy =3D 1, +}; + +static int __init ipcomp4_init(void) +{ + SET_MODULE_OWNER(&ipcomp_type); + if (xfrm_register_type(&ipcomp_type, AF_INET) < 0) { + printk(KERN_INFO "ipcomp init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0) { + printk(KERN_INFO "ipcomp init: can't add protocol\n"); + xfrm_unregister_type(&ipcomp_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit ipcomp4_fini(void) +{ + if (inet_del_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0) + printk(KERN_INFO "ip ipcomp close: can't remove protocol\n"); + if (xfrm_unregister_type(&ipcomp_type, AF_INET) < 0) + printk(KERN_INFO "ip ipcomp close: can't remove xfrm type\n"); +} + +module_init(ipcomp4_init); +module_exit(ipcomp4_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3713"); +MODULE_AUTHOR("James Morris "); + diff -Nru a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c --- a/net/ipv4/ipconfig.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/ipconfig.c Thu May 8 10:41:36 2003 @@ -655,7 +655,7 @@ struct net_device *dev =3D d->dev; struct sk_buff *skb; struct bootp_pkt *b; - int hh_len =3D (dev->hard_header_len + 15) & ~15; + int hh_len =3D LL_RESERVED_SPACE(dev); struct iphdr *h; =20 /* Allocate packet */ diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c --- a/net/ipv4/ipip.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/ipip.c Thu May 8 10:41:37 2003 @@ -115,6 +115,7 @@ #include #include #include +#include =20 #define HASH_SIZE 16 #define HASH(addr) ((addr^(addr>>4))&0xF) @@ -207,7 +208,7 @@ write_unlock_bh(&ipip_lock); } =20 -struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int cr= eate) +static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms,= int create) { u32 remote =3D parms->iph.daddr; u32 local =3D parms->iph.saddr; @@ -289,7 +290,7 @@ dev_put(dev); } =20 -void ipip_err(struct sk_buff *skb, u32 info) +static void ipip_err(struct sk_buff *skb, void *__unused) { #ifndef I_WISH_WORLD_WERE_PERFECT =20 @@ -355,6 +356,7 @@ int rel_code =3D 0; int rel_info =3D 0; struct sk_buff *skb2; + struct flowi fl; struct rtable *rt; =20 if (len < hlen + sizeof(struct iphdr)) @@ -417,7 +419,11 @@ skb2->nh.raw =3D skb2->data; =20 /* Try to guess incoming interface */ - if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) { + memset(&fl, 0, sizeof(fl)); + fl.fl4_daddr =3D eiph->saddr; + fl.fl4_tos =3D RT_TOS(eiph->tos); + fl.proto =3D IPPROTO_IPIP; + if (ip_route_output_key(&rt, &key)) { kfree_skb(skb2); return; } @@ -427,8 +433,11 @@ if (rt->rt_flags&RTCF_LOCAL) { ip_rt_put(rt); rt =3D NULL; - if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) || - rt->u.dst.dev->type !=3D ARPHRD_IPGRE) { + fl.fl4_daddr =3D eiph->daddr; + fl.fl4_src =3D eiph->saddr; + fl.fl4_tos =3D eiph->tos; + if (ip_route_output_key(&rt, &fl) || + rt->u.dst.dev->type !=3D ARPHRD_TUNNEL) { ip_rt_put(rt); kfree_skb(skb2); return; @@ -436,7 +445,7 @@ } else { ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev)= || - skb2->dst->dev->type !=3D ARPHRD_IPGRE) { + skb2->dst->dev->type !=3D ARPHRD_TUNNEL) { kfree_skb(skb2); return; } @@ -444,11 +453,11 @@ =20 /* change mtu on this route */ if (type =3D=3D ICMP_DEST_UNREACH && code =3D=3D ICMP_FRAG_NEEDED) { - if (rel_info > skb2->dst->pmtu) { + if (rel_info > dst_pmtu(skb2->dst)) { kfree_skb(skb2); return; } - skb2->dst->pmtu =3D rel_info; + skb2->dst->ops->update_pmtu(skb2->dst, rel_info); rel_info =3D htonl(rel_info); } else if (type =3D=3D ICMP_TIME_EXCEEDED) { struct ip_tunnel *t =3D (struct ip_tunnel*)skb2->dev->priv; @@ -473,7 +482,7 @@ IP_ECN_set_ce(inner_iph); } =20 -int ipip_rcv(struct sk_buff *skb) +static int ipip_rcv(struct sk_buff *skb) { struct iphdr *iph; struct ip_tunnel *tunnel; @@ -509,16 +518,8 @@ } read_unlock(&ipip_lock); =20 - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); out: - kfree_skb(skb); - return 0; -} - -/* Need this wrapper because NF_HOOK takes the function address */ -static inline int do_ip_send(struct sk_buff *skb) -{ - return ip_send(skb); + return -1; } =20 /* @@ -562,9 +563,17 @@ goto tx_error_icmp; } =20 - if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.lin= k)) { - tunnel->stat.tx_carrier_errors++; - goto tx_error_icmp; + { + struct flowi fl =3D { .oif =3D tunnel->parms.link, + .nl_u =3D { .ip4_u =3D + { .daddr =3D dst, + .saddr =3D tiph->saddr, + .tos =3D RT_TOS(tos) } }, + .proto =3D IPPROTO_IPIP }; + if (ip_route_output_key(&rt, &fl)) { + tunnel->stat.tx_carrier_errors++; + goto tx_error_icmp; + } } tdev =3D rt->u.dst.dev; =20 @@ -575,17 +584,17 @@ } =20 if (tiph->frag_off) - mtu =3D rt->u.dst.pmtu - sizeof(struct iphdr); + mtu =3D dst_pmtu(&rt->u.dst) - sizeof(struct iphdr); else - mtu =3D skb->dst ? skb->dst->pmtu : dev->mtu; + mtu =3D skb->dst ? dst_pmtu(skb->dst) : dev->mtu; =20 if (mtu < 68) { tunnel->stat.collisions++; ip_rt_put(rt); goto tx_error; } - if (skb->dst && mtu < skb->dst->pmtu) - skb->dst->pmtu =3D mtu; + if (skb->dst) + skb->dst->ops->update_pmtu(skb->dst, mtu); =20 df |=3D (old_iph->frag_off&htons(IP_DF)); =20 @@ -608,7 +617,7 @@ /* * Okay, now see if we can stuff it in the buffer as-is. */ - max_headroom =3D (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr)); + max_headroom =3D (LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr)); =20 if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb= )) { struct sk_buff *new_skb =3D skb_realloc_headroom(skb, max_headroom); @@ -824,8 +833,14 @@ ipip_tunnel_init_gen(dev); =20 if (iph->daddr) { + struct flowi fl =3D { .oif =3D tunnel->parms.link, + .nl_u =3D { .ip4_u =3D + { .daddr =3D iph->daddr, + .saddr =3D iph->saddr, + .tos =3D RT_TOS(iph->tos) } }, + .proto =3D IPPROTO_IPIP }; struct rtable *rt; - if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunn= el->parms.link)) { + if (!ip_route_output_key(&rt, &fl)) { tdev =3D rt->u.dst.dev; ip_rt_put(rt); } @@ -858,7 +873,7 @@ } #endif =20 -int __init ipip_fb_tunnel_init(struct net_device *dev) +static int __init ipip_fb_tunnel_init(struct net_device *dev) { struct iphdr *iph; =20 @@ -878,11 +893,9 @@ return 0; } =20 -static struct inet_protocol ipip_protocol =3D { - handler: ipip_rcv, - err_handler: ipip_err, - protocol: IPPROTO_IPIP, - name: "IPIP" +static struct xfrm_tunnel ipip_handler =3D { + .handler =3D ipip_rcv, + .err_handler =3D ipip_err, }; =20 static char banner[] __initdata =3D @@ -892,16 +905,20 @@ { printk(banner); =20 + if (xfrm4_tunnel_register(&ipip_handler) < 0) { + printk(KERN_INFO "ipip init: can't register tunnel\n"); + return -EAGAIN; + } + ipip_fb_tunnel_dev.priv =3D (void*)&ipip_fb_tunnel; register_netdev(&ipip_fb_tunnel_dev); - inet_add_protocol(&ipip_protocol); return 0; } =20 static void __exit ipip_fini(void) { - if ( inet_del_protocol(&ipip_protocol) < 0 ) - printk(KERN_INFO "ipip close: can't remove protocol\n"); + if (xfrm4_tunnel_deregister(&ipip_handler) < 0) + printk(KERN_INFO "ipip close: can't deregister tunnel\n"); =20 unregister_netdev(&ipip_fb_tunnel_dev); } diff -Nru a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c --- a/net/ipv4/ipmr.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/ipmr.c Thu May 8 10:41:37 2003 @@ -108,7 +108,7 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)= ; static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, stru= ct rtmsg *rtm); =20 -extern struct inet_protocol pim_protocol; +static struct inet_protocol pim_protocol; =20 static struct timer_list ipmr_expire_timer; =20 @@ -928,23 +928,28 @@ #ifdef CONFIG_IP_PIMSM case MRT_PIM: { - int v; + int v, ret; if(get_user(v,(int *)optval)) return -EFAULT; v =3D (v)?1:0; rtnl_lock(); + ret =3D 0; if (v !=3D mroute_do_pim) { mroute_do_pim =3D v; mroute_do_assert =3D v; #ifdef CONFIG_IP_PIMSM_V2 if (mroute_do_pim) - inet_add_protocol(&pim_protocol); + ret =3D inet_add_protocol(&pim_protocol, + IPPROTO_PIM); else - inet_del_protocol(&pim_protocol); + ret =3D inet_del_protocol(&pim_protocol, + IPPROTO_PIM); + if (ret < 0) + ret =3D -EAGAIN; #endif } rtnl_unlock(); - return 0; + return ret; } #endif /* @@ -1106,10 +1111,10 @@ { struct dst_entry *dst =3D skb->dst; =20 - if (skb->len <=3D dst->pmtu) - return dst->output(skb); + if (skb->len <=3D dst_pmtu(dst)) + return dst_output(skb); else - return ip_fragment(skb, dst->output); + return ip_fragment(skb, dst_output); } =20 /* @@ -1141,17 +1146,28 @@ #endif =20 if (vif->flags&VIFF_TUNNEL) { - if (ip_route_output(&rt, vif->remote, vif->local, RT_TOS(iph->tos), vif-= >link)) + struct flowi fl =3D { .oif =3D vif->link, + .nl_u =3D { .ip4_u =3D + { .daddr =3D vif->remote, + .saddr =3D vif->local, + .tos =3D RT_TOS(iph->tos) } }, + .proto =3D IPPROTO_IPIP }; + if (ip_route_output_key(&rt, &fl)) return; encap =3D sizeof(struct iphdr); } else { - if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), vif->link)) + struct flowi fl =3D { .oif =3D vif->link, + .nl_u =3D { .ip4_u =3D + { .daddr =3D iph->daddr, + .tos =3D RT_TOS(iph->tos) } }, + .proto =3D IPPROTO_IPIP }; + if (ip_route_output_key(&rt, &fl)) return; } =20 dev =3D rt->u.dst.dev; =20 - if (skb->len+encap > rt->u.dst.pmtu && (ntohs(iph->frag_off) & IP_DF)) { + if (skb->len+encap > dst_pmtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_D= F)) { /* Do not fragment multicasts. Alas, IPv4 does not allow to send ICMP, so that packets will disappear to blackhole. @@ -1162,7 +1178,7 @@ return; } =20 - encap +=3D dev->hard_header_len; + encap +=3D LL_RESERVED_SPACE(dev); =20 if (skb_headroom(skb) < encap || skb_cloned(skb) || !last) skb2 =3D skb_realloc_headroom(skb, (encap + 15)&~15); @@ -1239,7 +1255,7 @@ if (vif_table[vif].dev !=3D skb->dev) { int true_vifi; =20 - if (((struct rtable*)skb->dst)->key.iif =3D=3D 0) { + if (((struct rtable*)skb->dst)->fl.iif =3D=3D 0) { /* It is our own packet, looped back. Very complicated situation... =20 @@ -1727,15 +1743,8 @@ #endif=09 =20 #ifdef CONFIG_IP_PIMSM_V2 -struct inet_protocol pim_protocol =3D=20 -{ - pim_rcv, /* PIM handler */ - NULL, /* PIM error control */ - NULL, /* next */ - IPPROTO_PIM, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "PIM" /* name */ +static struct inet_protocol pim_protocol =3D { + .handler =3D pim_rcv, }; #endif =20 diff -Nru a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilt= er/ip_conntrack_standalone.c --- a/net/ipv4/netfilter/ip_conntrack_standalone.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c Thu May 8 10:41:37 2003 @@ -201,7 +201,7 @@ /* Local packets are never produced too large for their interface. We degfragment them at LOCAL_OUT, however, so we have to refragment them here. */ - if ((*pskb)->len > rt->u.dst.pmtu) { + if ((*pskb)->len > dst_pmtu(&rt->u.dst)) { /* No hook can be after us, so this should be OK. */ ip_fragment(*pskb, okfn); return NF_STOLEN; diff -Nru a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_= fw_compat_masq.c --- a/net/ipv4/netfilter/ip_fw_compat_masq.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/netfilter/ip_fw_compat_masq.c Thu May 8 10:41:37 2003 @@ -68,12 +68,13 @@ /* Setup the masquerade, if not already */ if (!info->initialized) { u_int32_t newsrc; + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D iph->daddr } }= }; struct rtable *rt; struct ip_nat_multi_range range; =20 /* Pass 0 instead of saddr, since it's going to be changed anyway. */ - if (ip_route_output(&rt, iph->daddr, 0, 0, 0) !=3D 0) { + if (ip_route_output_key(&rt, &fl) !=3D 0) { DEBUGP("ipnat_rule_masquerade: Can't reroute.\n"); return NF_DROP; } diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_co= re.c --- a/net/ipv4/netfilter/ip_nat_core.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/netfilter/ip_nat_core.c Thu May 8 10:41:36 2003 @@ -206,10 +206,11 @@ static int do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp) { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D var_ip } } }; struct rtable *rt; =20 /* FIXME: IPTOS_TOS(iph->tos) --RR */ - if (ip_route_output(&rt, var_ip, 0, 0, 0) !=3D 0) { + if (ip_route_output_key(&rt, &fl) !=3D 0) { DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n", NIPQUAD(var_ip)); return 0; diff -Nru a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MA= SQUERADE.c --- a/net/ipv4/netfilter/ipt_MASQUERADE.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c Thu May 8 10:41:36 2003 @@ -69,7 +69,6 @@ struct ip_nat_multi_range newrange; u_int32_t newsrc; struct rtable *rt; - struct rt_key key; =20 IP_NF_ASSERT(hooknum =3D=3D NF_IP_POST_ROUTING); =20 @@ -84,17 +83,21 @@ =20 mr =3D targinfo; =20 - key.dst =3D (*pskb)->nh.iph->daddr; - key.src =3D 0; /* Unknown: that's what we're trying to establish */ - key.tos =3D RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN; - key.oif =3D out->ifindex; + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D (*pskb)->nh.iph->daddr, + .tos =3D (RT_TOS((*pskb)->nh.iph->tos) | + RTO_CONN), #ifdef CONFIG_IP_ROUTE_FWMARK - key.fwmark =3D (*pskb)->nfmark; + .fwmark =3D (*pskb)->nfmark #endif - if (ip_route_output_key(&rt, &key) !=3D 0) { - /* Shouldn't happen */ - printk("MASQUERADE: No route: Rusty's brain broke!\n"); - return NF_DROP; + } }, + .oif =3D out->ifindex }; + if (ip_route_output_key(&rt, &fl) !=3D 0) { + /* Shouldn't happen */ + printk("MASQUERADE: No route: Rusty's brain broke!\n"); + return NF_DROP; + } } =20 newsrc =3D rt->rt_src; diff -Nru a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR= .c --- a/net/ipv4/netfilter/ipt_MIRROR.c Thu May 8 10:41:38 2003 +++ b/net/ipv4/netfilter/ipt_MIRROR.c Thu May 8 10:41:38 2003 @@ -44,12 +44,13 @@ static int route_mirror(struct sk_buff *skb) { struct iphdr *iph =3D skb->nh.iph; + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D iph->saddr, + .saddr =3D iph->daddr, + .tos =3D RT_TOS(iph->tos) | RTO_CONN } } }; struct rtable *rt; =20 /* Backwards */ - if (ip_route_output(&rt, iph->saddr, iph->daddr, - RT_TOS(iph->tos) | RTO_CONN, - 0)) { + if (ip_route_output_key(&rt, &fl)) { return 0; } =20 diff -Nru a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT= .c --- a/net/ipv4/netfilter/ipt_REJECT.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/netfilter/ipt_REJECT.c Thu May 8 10:41:37 2003 @@ -63,11 +63,18 @@ csum_partial((char *)otcph, otcplen, 0)) !=3D 0) return; =20 - /* Routing: if not headed for us, route won't like source */ - if (ip_route_output(&rt, oldskb->nh.iph->saddr, - local ? oldskb->nh.iph->daddr : 0, - RT_TOS(oldskb->nh.iph->tos), 0) !=3D 0) - return; + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D oldskb->nh.iph->daddr, + .saddr =3D (local ? + oldskb->nh.iph->saddr : + 0), + .tos =3D RT_TOS(oldskb->nh.iph->tos) } } }; + + /* Routing: if not headed for us, route won't like source */ + if (ip_route_output_key(&rt, &fl)) + return; + } =20 hh_len =3D (rt->u.dst.dev->hard_header_len + 15)&~15; =20 @@ -149,7 +156,7 @@ nskb->nh.iph->ihl); =20 /* "Never happens" */ - if (nskb->len > nskb->dst->pmtu) + if (nskb->len > dst_pmtu(nskb->dst)) goto free_nskb; =20 connection_attach(nskb, oldskb->nfct); @@ -229,14 +236,19 @@ =20 tos =3D (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL; =20 - if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) - return; - + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D iph->saddr, + .saddr =3D saddr, + .tos =3D RT_TOS(tos) } } }; + if (ip_route_output_key(&rt, &fl)) + return; + } /* RFC says return as much as we can without exceeding 576 bytes. */ length =3D skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr); =20 - if (length > rt->u.dst.pmtu) - length =3D rt->u.dst.pmtu; + if (length > dst_pmtu(&rt->u.dst)) + length =3D dst_pmtu(&rt->u.dst); if (length > 576) length =3D 576; =20 diff -Nru a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS= .c --- a/net/ipv4/netfilter/ipt_TCPMSS.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/netfilter/ipt_TCPMSS.c Thu May 8 10:41:37 2003 @@ -85,14 +85,14 @@ return NF_DROP; /* or IPT_CONTINUE ?? */ } =20 - if((*pskb)->dst->pmtu <=3D (sizeof(struct iphdr) + sizeof(struct tcphdr)= )) { + if(dst_pmtu((*pskb)->dst) <=3D (sizeof(struct iphdr) + sizeof(struct tcp= hdr))) { if (net_ratelimit()) printk(KERN_ERR - "ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", (*psk= b)->dst->pmtu); + "ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_p= mtu((*pskb)->dst)); return NF_DROP; /* or IPT_CONTINUE ?? */ } =20 - newmss =3D (*pskb)->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcp= hdr); + newmss =3D dst_pmtu((*pskb)->dst) - sizeof(struct iphdr) - sizeof(struct= tcphdr); } else newmss =3D tcpmssinfo->mss; =20 diff -Nru a/net/ipv4/protocol.c b/net/ipv4/protocol.c --- a/net/ipv4/protocol.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/protocol.c Thu May 8 10:41:36 2003 @@ -48,134 +48,52 @@ #include #include =20 -#define IPPROTO_PREVIOUS NULL - -#ifdef CONFIG_IP_MULTICAST - -static struct inet_protocol igmp_protocol =3D { - handler: igmp_rcv, - next: IPPROTO_PREVIOUS, - protocol: IPPROTO_IGMP, - name: "IGMP" -}; - -#undef IPPROTO_PREVIOUS -#define IPPROTO_PREVIOUS &igmp_protocol - -#endif - -static struct inet_protocol tcp_protocol =3D { - handler: tcp_v4_rcv, - err_handler: tcp_v4_err, - next: IPPROTO_PREVIOUS, - protocol: IPPROTO_TCP, - name: "TCP" -}; - -#undef IPPROTO_PREVIOUS -#define IPPROTO_PREVIOUS &tcp_protocol - -static struct inet_protocol udp_protocol =3D { - handler: udp_rcv, - err_handler: udp_err, - next: IPPROTO_PREVIOUS, - protocol: IPPROTO_UDP, - name: "UDP" -}; - -#undef IPPROTO_PREVIOUS -#define IPPROTO_PREVIOUS &udp_protocol - -static struct inet_protocol icmp_protocol =3D { - handler: icmp_rcv, - next: IPPROTO_PREVIOUS, - protocol: IPPROTO_ICMP, - name: "ICMP" -}; - -#undef IPPROTO_PREVIOUS -#define IPPROTO_PREVIOUS &icmp_protocol - - -struct inet_protocol *inet_protocol_base =3D IPPROTO_PREVIOUS; - struct inet_protocol *inet_protos[MAX_INET_PROTOS]; =20 /* * Add a protocol handler to the hash tables */ =20 -void inet_add_protocol(struct inet_protocol *prot) +int inet_add_protocol(struct inet_protocol *prot, unsigned char protocol) { - unsigned char hash; - struct inet_protocol *p2; + int hash, ret; + + hash =3D protocol & (MAX_INET_PROTOS - 1); =20 - hash =3D prot->protocol & (MAX_INET_PROTOS - 1); br_write_lock_bh(BR_NETPROTO_LOCK); - prot ->next =3D inet_protos[hash]; - inet_protos[hash] =3D prot; - prot->copy =3D 0; - - /* - * Set the copy bit if we need to.=20 - */ - =20 - p2 =3D (struct inet_protocol *) prot->next; - while (p2) { - if (p2->protocol =3D=3D prot->protocol) { - prot->copy =3D 1; - break; - } - p2 =3D (struct inet_protocol *) p2->next; + + if (inet_protos[hash]) { + ret =3D -1; + } else { + inet_protos[hash] =3D prot; + ret =3D 0; } + br_write_unlock_bh(BR_NETPROTO_LOCK); + + return ret; } =20 /* * Remove a protocol from the hash tables. */ =20 -int inet_del_protocol(struct inet_protocol *prot) +int inet_del_protocol(struct inet_protocol *prot, unsigned char protocol) { - struct inet_protocol *p; - struct inet_protocol *lp =3D NULL; - unsigned char hash; - - hash =3D prot->protocol & (MAX_INET_PROTOS - 1); - br_write_lock_bh(BR_NETPROTO_LOCK); - if (prot =3D=3D inet_protos[hash]) { - inet_protos[hash] =3D (struct inet_protocol *) inet_protos[hash]->next; - br_write_unlock_bh(BR_NETPROTO_LOCK); - return 0; - } + int hash, ret; =20 - p =3D (struct inet_protocol *) inet_protos[hash]; + hash =3D protocol & (MAX_INET_PROTOS - 1); =20 - if (p !=3D NULL && p->protocol =3D=3D prot->protocol) - lp =3D p; - - while (p) { - /* - * We have to worry if the protocol being deleted is - * the last one on the list, then we may need to reset - * someone's copied bit. - */ - if (p->next && p->next =3D=3D prot) { - /* - * if we are the last one with this protocol and - * there is a previous one, reset its copy bit. - */ - if (prot->copy =3D=3D 0 && lp !=3D NULL) - lp->copy =3D 0; - p->next =3D prot->next; - br_write_unlock_bh(BR_NETPROTO_LOCK); - return 0; - } - if (p->next !=3D NULL && p->next->protocol =3D=3D prot->protocol)=20 - lp =3D p->next; + br_write_lock_bh(BR_NETPROTO_LOCK); =20 - p =3D (struct inet_protocol *) p->next; + if (inet_protos[hash] =3D=3D prot) { + inet_protos[hash] =3D NULL; + ret =3D 0; + } else { + ret =3D -1; } + br_write_unlock_bh(BR_NETPROTO_LOCK); - return -1; + + return ret; } diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c --- a/net/ipv4/raw.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/raw.c Thu May 8 10:41:36 2003 @@ -64,6 +64,8 @@ #include #include #include +#include +#include =20 struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE]; rwlock_t raw_v4_lock =3D RW_LOCK_UNLOCKED; @@ -132,13 +134,12 @@ } =20 /* IP input processing comes here for RAW socket delivery. - * This is fun as to avoid copies we want to make no surplus - * copies. + * Caller owns SKB, so we must make clones. * * RFC 1122: SHOULD pass TOS value up to the transport layer. * -> It does. And not only TOS, but all IP header. */ -struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash= ) +void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) { struct sock *sk; =20 @@ -150,28 +151,19 @@ skb->dev->ifindex); =20 while (sk) { - struct sock *sknext =3D __raw_v4_lookup(sk->next, iph->protocol, - iph->saddr, iph->daddr, - skb->dev->ifindex); - if (iph->protocol !=3D IPPROTO_ICMP || - !icmp_filter(sk, skb)) { - struct sk_buff *clone; - - if (!sknext) - break; - clone =3D skb_clone(skb, GFP_ATOMIC); + if (iph->protocol !=3D IPPROTO_ICMP || !icmp_filter(sk, skb)) { + struct sk_buff *clone =3D skb_clone(skb, GFP_ATOMIC); + /* Not releasing hash table! */ if (clone) raw_rcv(sk, clone); } - sk =3D sknext; + sk =3D __raw_v4_lookup(sk->next, iph->protocol, + iph->saddr, iph->daddr, + skb->dev->ifindex); } out: - if (sk) - sock_hold(sk); read_unlock(&raw_v4_lock); - - return sk; } =20 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) @@ -244,71 +236,92 @@ =20 int raw_rcv(struct sock *sk, struct sk_buff *skb) { + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } + skb_push(skb, skb->data - skb->nh.raw); =20 raw_rcv_skb(sk, skb); return 0; } =20 -struct rawfakehdr=20 -{ - struct iovec *iov; - u32 saddr; - struct dst_entry *dst; -}; +static int raw_send_hdrinc(struct sock *sk, void *from, int length, + struct rtable *rt,=20 + unsigned int flags) +{ + struct inet_opt *inet =3D inet_sk(sk); + int hh_len; + struct iphdr *iph; + struct sk_buff *skb; + int err; =20 -/* - * Send a RAW IP packet. - */ + if (length > rt->u.dst.dev->mtu) { + ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, + rt->u.dst.dev->mtu); + return -EMSGSIZE; + } + if (flags&MSG_PROBE) + goto out; =20 -/* - * Callback support is trivial for SOCK_RAW - */ - =20 -static int raw_getfrag(const void *p, char *to, unsigned int offset, - unsigned int fraglen) -{ - struct rawfakehdr *rfh =3D (struct rawfakehdr *) p; - return memcpy_fromiovecend(to, rfh->iov, offset, fraglen); -} + hh_len =3D LL_RESERVED_SPACE(rt->u.dst.dev); =20 -/* - * IPPROTO_RAW needs extra work. - */ -=20 -static int raw_getrawfrag(const void *p, char *to, unsigned int offset, - unsigned int fraglen) -{ - struct rawfakehdr *rfh =3D (struct rawfakehdr *) p; + skb =3D sock_alloc_send_skb(sk, length+hh_len+15, + flags&MSG_DONTWAIT, &err); + if (skb =3D=3D NULL) + goto error;=20 + skb_reserve(skb, hh_len); + + skb->priority =3D sk->priority; + skb->dst =3D dst_clone(&rt->u.dst); + + skb->nh.iph =3D iph =3D (struct iphdr *)skb_put(skb, length); =20 - if (memcpy_fromiovecend(to, rfh->iov, offset, fraglen)) - return -EFAULT; + skb->ip_summed =3D CHECKSUM_NONE; + + skb->h.raw =3D skb->nh.raw; + err =3D memcpy_fromiovecend((void *)iph, from, 0, length); + if (err) + goto error_fault; =20 - if (!offset) { - struct iphdr *iph =3D (struct iphdr *)to; + /* We don't modify invalid header */ + if (length >=3D sizeof(*iph) && iph->ihl * 4 <=3D length) { if (!iph->saddr) - iph->saddr =3D rfh->saddr; + iph->saddr =3D rt->rt_src; iph->check =3D 0; - iph->tot_len =3D htons(fraglen); /* This is right as you can't - frag RAW packets */ - /* - * Deliberate breach of modularity to keep=20 - * ip_build_xmit clean (well less messy). - */ + iph->tot_len =3D htons(length); if (!iph->id) - ip_select_ident(iph, rfh->dst, NULL); + ip_select_ident(iph, &rt->u.dst, NULL); + iph->check =3D ip_fast_csum((unsigned char *)iph, iph->ihl); } + + err =3D NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, + dst_output); + if (err > 0) + err =3D inet->recverr ? net_xmit_errno(err) : 0; + if (err) + goto error; +out: return 0; + +error_fault: + err =3D -EFAULT; + kfree_skb(skb); +error: + IP_INC_STATS(IpOutDiscards); + return err;=20 } =20 static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len) { + struct inet_opt *inet =3D inet_sk(sk); struct ipcm_cookie ipc; - struct rawfakehdr rfh; struct rtable *rt =3D NULL; int free =3D 0; u32 daddr; + u32 saddr; u8 tos; int err; =20 @@ -378,7 +391,7 @@ free =3D 1; } =20 - rfh.saddr =3D ipc.addr; + saddr =3D ipc.addr; ipc.addr =3D daddr; =20 if (!ipc.opt) @@ -404,12 +417,19 @@ if (MULTICAST(daddr)) { if (!ipc.oif) ipc.oif =3D sk->protinfo.af_inet.mc_index; - if (!rfh.saddr) - rfh.saddr =3D sk->protinfo.af_inet.mc_addr; + if (!saddr) + saddr =3D sk->protinfo.af_inet.mc_addr; } =20 - err =3D ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif); - + { + struct flowi fl =3D { .oif =3D ipc.oif, + .nl_u =3D { .ip4_u =3D + { .daddr =3D daddr, + .saddr =3D saddr, + .tos =3D tos } }, + .proto =3D inet->hdrincl ? IPPROTO_RAW : sk->protocol }; + err =3D ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT= )); + } if (err) goto done; =20 @@ -421,14 +441,22 @@ goto do_confirm; back_from_confirm: =20 - rfh.iov =3D msg->msg_iov; - rfh.saddr =3D rt->rt_src; - rfh.dst =3D &rt->u.dst; - if (!ipc.addr) - ipc.addr =3D rt->rt_dst; - err =3D ip_build_xmit(sk, sk->protinfo.af_inet.hdrincl ? raw_getrawfrag : - raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags); - + if (inet->hdrincl) + err =3D raw_send_hdrinc(sk, msg->msg_iov, len,=20 + rt, msg->msg_flags); +=09 + else { + if (!ipc.addr) + ipc.addr =3D rt->rt_dst; + lock_sock(sk); + err =3D ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, + &ipc, rt, msg->msg_flags); + if (err) + ip_flush_pending_frames(sk); + else if (!(msg->msg_flags & MSG_MORE)) + err =3D ip_push_pending_frames(sk); + release_sock(sk); + } done: if (free) kfree(ipc.opt); diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c Thu May 8 10:41:38 2003 +++ b/net/ipv4/route.c Thu May 8 10:41:38 2003 @@ -95,6 +95,7 @@ #include #include #include +#include #ifdef CONFIG_SYSCTL #include #endif @@ -132,11 +133,10 @@ */ =20 static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)= ; -static struct dst_entry *ipv4_dst_reroute(struct dst_entry *dst, - struct sk_buff *skb); static void ipv4_dst_destroy(struct dst_entry *dst); static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); static void ipv4_link_failure(struct sk_buff *skb); +static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); static int rt_garbage_collect(void); =20 =20 @@ -145,10 +145,10 @@ protocol: __constant_htons(ETH_P_IP), gc: rt_garbage_collect, check: ipv4_dst_check, - reroute: ipv4_dst_reroute, destroy: ipv4_dst_destroy, negative_advice: ipv4_negative_advice, link_failure: ipv4_link_failure, + update_pmtu: ip_rt_update_pmtu, entry_size: sizeof(struct rtable), }; =20 @@ -248,11 +248,12 @@ r->u.dst.__use, 0, (unsigned long)r->rt_src, - (r->u.dst.advmss ? - (int) r->u.dst.advmss + 40 : 0), - r->u.dst.window, - (int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar), - r->key.tos, + (dst_metric(&r->u.dst, RTAX_ADVMSS) ? + (int) dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0), + dst_metric(&r->u.dst, RTAX_WINDOW), + (int)((dst_metric(&r->u.dst, RTAX_RTT) >> 3) + + dst_metric(&r->u.dst, RTAX_RTTVAR)), + r->fl.fl4_tos, r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1, @@ -335,7 +336,7 @@ /* Kill broadcast/multicast entries very aggresively, if they collide in hash table with more useful entries */ return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) && - rth->key.iif && rth->u.rt_next; + rth->fl.iif && rth->u.rt_next; } =20 static __inline__ int rt_valuable(struct rtable *rth) @@ -623,6 +624,13 @@ out: return 0; } =20 +static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) +{ + return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)= ) =3D=3D 0 && + fl1->oif =3D=3D fl2->oif && + fl1->iif =3D=3D fl2->iif; +} + static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable = **rp) { struct rtable *rth, **rthp; @@ -634,7 +642,7 @@ =20 write_lock_bh(&rt_hash_table[hash].lock); while ((rth =3D *rthp) !=3D NULL) { - if (memcmp(&rth->key, &rt->key, sizeof(rt->key)) =3D=3D 0) { + if (compare_keys(&rth->fl, &rt->fl)) { /* Put it first */ *rthp =3D rth->u.rt_next; rth->u.rt_next =3D rt_hash_table[hash].chain; @@ -656,7 +664,7 @@ /* Try to bind route to arp only if it is output route or unicast forwarding path. */ - if (rt->rt_type =3D=3D RTN_UNICAST || rt->key.iif =3D=3D 0) { + if (rt->rt_type =3D=3D RTN_UNICAST || rt->fl.iif =3D=3D 0) { int err =3D arp_bind_neighbour(&rt->u.dst); if (err) { write_unlock_bh(&rt_hash_table[hash].lock); @@ -819,11 +827,11 @@ while ((rth =3D *rthp) !=3D NULL) { struct rtable *rt; =20 - if (rth->key.dst !=3D daddr || - rth->key.src !=3D skeys[i] || - rth->key.tos !=3D tos || - rth->key.oif !=3D ikeys[k] || - rth->key.iif !=3D 0) { + if (rth->fl.fl4_dst !=3D daddr || + rth->fl.fl4_src !=3D skeys[i] || + rth->fl.fl4_tos !=3D tos || + rth->fl.oif !=3D ikeys[k] || + rth->fl.iif !=3D 0) { rthp =3D &rth->u.rt_next; continue; } @@ -914,14 +922,14 @@ ret =3D NULL; } else if ((rt->rt_flags & RTCF_REDIRECTED) || rt->u.dst.expires) { - unsigned hash =3D rt_hash_code(rt->key.dst, - rt->key.src ^ - (rt->key.oif << 5), - rt->key.tos); + unsigned hash =3D rt_hash_code(rt->fl.fl4_dst, + rt->fl.fl4_src ^ + (rt->fl.oif << 5), + rt->fl.fl4_tos); #if RT_CACHE_DEBUG >=3D 1 printk(KERN_DEBUG "ip_rt_advice: redirect to " "%u.%u.%u.%u/%02x dropped\n", - NIPQUAD(rt->rt_dst), rt->key.tos); + NIPQUAD(rt->rt_dst), rt->fl.fl4_tos); #endif rt_del(hash, rt); ret =3D NULL; @@ -1065,34 +1073,34 @@ read_lock(&rt_hash_table[hash].lock); for (rth =3D rt_hash_table[hash].chain; rth; rth =3D rth->u.rt_next) { - if (rth->key.dst =3D=3D daddr && - rth->key.src =3D=3D skeys[i] && + if (rth->fl.fl4_dst =3D=3D daddr && + rth->fl.fl4_src =3D=3D skeys[i] && rth->rt_dst =3D=3D daddr && rth->rt_src =3D=3D iph->saddr && - rth->key.tos =3D=3D tos && - rth->key.iif =3D=3D 0 && - !(rth->u.dst.mxlock & (1 << RTAX_MTU))) { + rth->fl.fl4_tos =3D=3D tos && + rth->fl.iif =3D=3D 0 && + !(dst_metric_locked(&rth->u.dst, RTAX_MTU))) { unsigned short mtu =3D new_mtu; =20 if (new_mtu < 68 || new_mtu >=3D old_mtu) { =20 /* BSD 4.2 compatibility hack :-( */ if (mtu =3D=3D 0 && - old_mtu >=3D rth->u.dst.pmtu && + old_mtu >=3D rth->u.dst.metrics[RTAX_MTU-1] && old_mtu >=3D 68 + (iph->ihl << 2)) old_mtu -=3D iph->ihl << 2; =20 mtu =3D guess_mtu(old_mtu); } - if (mtu <=3D rth->u.dst.pmtu) { - if (mtu < rth->u.dst.pmtu) {=20 + if (mtu <=3D rth->u.dst.metrics[RTAX_MTU-1]) { + if (mtu < rth->u.dst.metrics[RTAX_MTU-1]) {=20 dst_confirm(&rth->u.dst); if (mtu < ip_rt_min_pmtu) { mtu =3D ip_rt_min_pmtu; - rth->u.dst.mxlock |=3D + rth->u.dst.metrics[RTAX_LOCK-1] |=3D (1 << RTAX_MTU); } - rth->u.dst.pmtu =3D mtu; + rth->u.dst.metrics[RTAX_MTU-1] =3D mtu; dst_set_expires(&rth->u.dst, ip_rt_mtu_expires); } @@ -1105,15 +1113,15 @@ return est_mtu ? : new_mtu; } =20 -void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu) +static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) { - if (dst->pmtu > mtu && mtu >=3D 68 && - !(dst->mxlock & (1 << RTAX_MTU))) { + if (dst->metrics[RTAX_MTU-1] > mtu && mtu >=3D 68 && + !(dst_metric_locked(dst, RTAX_MTU))) { if (mtu < ip_rt_min_pmtu) { mtu =3D ip_rt_min_pmtu; - dst->mxlock |=3D (1 << RTAX_MTU); + dst->metrics[RTAX_LOCK-1] |=3D (1 << RTAX_MTU); } - dst->pmtu =3D mtu; + dst->metrics[RTAX_MTU-1] =3D mtu; dst_set_expires(dst, ip_rt_mtu_expires); } } @@ -1124,12 +1132,6 @@ return NULL; } =20 -static struct dst_entry *ipv4_dst_reroute(struct dst_entry *dst, - struct sk_buff *skb) -{ - return NULL; -} - static void ipv4_dst_destroy(struct dst_entry *dst) { struct rtable *rt =3D (struct rtable *) dst; @@ -1175,9 +1177,9 @@ u32 src; struct fib_result res; =20 - if (rt->key.iif =3D=3D 0) + if (rt->fl.iif =3D=3D 0) src =3D rt->rt_src; - else if (fib_lookup(&rt->key, &res) =3D=3D 0) { + else if (fib_lookup(&rt->fl, &res) =3D=3D 0) { #ifdef CONFIG_IP_ROUTE_NAT if (res.type =3D=3D RTN_NAT) src =3D inet_select_addr(rt->u.dst.dev, rt->rt_gateway, @@ -1210,28 +1212,28 @@ if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope =3D=3D RT_SCOPE_LINK) rt->rt_gateway =3D FIB_RES_GW(*res); - memcpy(&rt->u.dst.mxlock, fi->fib_metrics, - sizeof(fi->fib_metrics)); + memcpy(rt->u.dst.metrics, fi->fib_metrics, + sizeof(rt->u.dst.metrics)); if (fi->fib_mtu =3D=3D 0) { - rt->u.dst.pmtu =3D rt->u.dst.dev->mtu; - if (rt->u.dst.mxlock & (1 << RTAX_MTU) && + rt->u.dst.metrics[RTAX_MTU-1] =3D rt->u.dst.dev->mtu; + if (rt->u.dst.metrics[RTAX_LOCK-1] & (1 << RTAX_MTU) && rt->rt_gateway !=3D rt->rt_dst && - rt->u.dst.pmtu > 576) - rt->u.dst.pmtu =3D 576; + rt->u.dst.dev->mtu > 576) + rt->u.dst.metrics[RTAX_MTU-1] =3D 576; } #ifdef CONFIG_NET_CLS_ROUTE rt->u.dst.tclassid =3D FIB_RES_NH(*res).nh_tclassid; #endif } else - rt->u.dst.pmtu =3D rt->u.dst.dev->mtu; + rt->u.dst.metrics[RTAX_MTU-1]=3D rt->u.dst.dev->mtu; =20 - if (rt->u.dst.pmtu > IP_MAX_MTU) - rt->u.dst.pmtu =3D IP_MAX_MTU; - if (rt->u.dst.advmss =3D=3D 0) - rt->u.dst.advmss =3D max_t(unsigned int, rt->u.dst.dev->mtu - 40, + if (rt->u.dst.metrics[RTAX_MTU-1] > IP_MAX_MTU) + rt->u.dst.metrics[RTAX_MTU-1] =3D IP_MAX_MTU; + if (rt->u.dst.metrics[RTAX_ADVMSS-1] =3D=3D 0) + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D max_t(unsigned int, rt->u.dst.dev->= mtu - 40, ip_rt_min_advmss); - if (rt->u.dst.advmss > 65535 - 40) - rt->u.dst.advmss =3D 65535 - 40; + if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535 - 40) + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D 65535 - 40; =20 #ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_IP_MULTIPLE_TABLES @@ -1276,13 +1278,15 @@ =20 atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags=3D DST_HOST; - rth->key.dst =3D daddr; + if (in_dev->cnf.no_policy) + rth->u.dst.flags |=3D DST_NOPOLICY; + rth->fl.fl4_dst =3D daddr; rth->rt_dst =3D daddr; - rth->key.tos =3D tos; + rth->fl.fl4_tos =3D tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark =3D skb->nfmark; + rth->fl.fl4_fwmark=3D skb->nfmark; #endif - rth->key.src =3D saddr; + rth->fl.fl4_src =3D saddr; rth->rt_src =3D saddr; #ifdef CONFIG_IP_ROUTE_NAT rth->rt_dst_map =3D daddr; @@ -1292,10 +1296,10 @@ rth->u.dst.tclassid =3D itag; #endif rth->rt_iif =3D - rth->key.iif =3D dev->ifindex; + rth->fl.iif =3D dev->ifindex; rth->u.dst.dev =3D &loopback_dev; dev_hold(rth->u.dst.dev); - rth->key.oif =3D 0; + rth->fl.oif =3D 0; rth->rt_gateway =3D daddr; rth->rt_spec_dst=3D spec_dst; rth->rt_type =3D RTN_MULTICAST; @@ -1337,10 +1341,19 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, u8 tos, struct net_device *dev) { - struct rt_key key; struct fib_result res; struct in_device *in_dev =3D in_dev_get(dev); struct in_device *out_dev =3D NULL; + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D daddr, + .saddr =3D saddr, + .tos =3D tos, + .scope =3D RT_SCOPE_UNIVERSE, +#ifdef CONFIG_IP_ROUTE_FWMARK + .fwmark =3D skb->nfmark +#endif + } }, + .iif =3D dev->ifindex }; unsigned flags =3D 0; u32 itag =3D 0; struct rtable * rth; @@ -1354,17 +1367,7 @@ if (!in_dev) goto out; =20 - key.dst =3D daddr; - key.src =3D saddr; - key.tos =3D tos; -#ifdef CONFIG_IP_ROUTE_FWMARK - key.fwmark =3D skb->nfmark; -#endif - key.iif =3D dev->ifindex; - key.oif =3D 0; - key.scope =3D RT_SCOPE_UNIVERSE; - - hash =3D rt_hash_code(daddr, saddr ^ (key.iif << 5), tos); + hash =3D rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos); =20 /* Check for the most weird martians, which can be not detected by fib_lookup. @@ -1388,7 +1391,7 @@ /* * Now we are ready to route packet. */ - if ((err =3D fib_lookup(&key, &res)) !=3D 0) { + if ((err =3D fib_lookup(&fl, &res)) !=3D 0) { if (!IN_DEV_FORWARD(in_dev)) goto e_inval; goto no_route; @@ -1408,17 +1411,17 @@ src_map =3D fib_rules_policy(saddr, &res, &flags); =20 if (res.type =3D=3D RTN_NAT) { - key.dst =3D fib_rules_map_destination(daddr, &res); + fl.fl4_dst =3D fib_rules_map_destination(daddr, &res); fib_res_put(&res); free_res =3D 0; - if (fib_lookup(&key, &res)) + if (fib_lookup(&fl, &res)) goto e_inval; free_res =3D 1; if (res.type !=3D RTN_UNICAST) goto e_inval; flags |=3D RTCF_DNAT; } - key.src =3D src_map; + fl.fl4_src =3D src_map; } #endif =20 @@ -1444,8 +1447,8 @@ goto martian_destination; =20 #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res.fi->fib_nhs > 1 && key.oif =3D=3D 0) - fib_select_multipath(&key, &res); + if (res.fi->fib_nhs > 1 && fl.oif =3D=3D 0) + fib_select_multipath(&fl, &res); #endif out_dev =3D in_dev_get(FIB_RES_DEV(res)); if (out_dev =3D=3D NULL) { @@ -1482,26 +1485,30 @@ =20 atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags=3D DST_HOST; - rth->key.dst =3D daddr; + if (in_dev->cnf.no_policy) + rth->u.dst.flags |=3D DST_NOPOLICY; + if (in_dev->cnf.no_xfrm) + rth->u.dst.flags |=3D DST_NOXFRM; + rth->fl.fl4_dst =3D daddr; rth->rt_dst =3D daddr; - rth->key.tos =3D tos; + rth->fl.fl4_tos =3D tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark =3D skb->nfmark; + rth->fl.fl4_fwmark=3D skb->nfmark; #endif - rth->key.src =3D saddr; + rth->fl.fl4_src =3D saddr; rth->rt_src =3D saddr; rth->rt_gateway =3D daddr; #ifdef CONFIG_IP_ROUTE_NAT - rth->rt_src_map =3D key.src; - rth->rt_dst_map =3D key.dst; + rth->rt_src_map =3D fl.fl4_src; + rth->rt_dst_map =3D fl.fl4_dst; if (flags&RTCF_DNAT) - rth->rt_gateway =3D key.dst; + rth->rt_gateway =3D fl.fl4_dst; #endif rth->rt_iif =3D - rth->key.iif =3D dev->ifindex; + rth->fl.iif =3D dev->ifindex; rth->u.dst.dev =3D out_dev->dev; dev_hold(rth->u.dst.dev); - rth->key.oif =3D 0; + rth->fl.oif =3D 0; rth->rt_spec_dst=3D spec_dst; =20 rth->u.dst.input =3D ip_forward; @@ -1559,26 +1566,27 @@ =20 atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags=3D DST_HOST; - rth->key.dst =3D daddr; + if (in_dev->cnf.no_policy) + rth->u.dst.flags |=3D DST_NOPOLICY; + rth->fl.fl4_dst =3D daddr; rth->rt_dst =3D daddr; - rth->key.tos =3D tos; + rth->fl.fl4_tos =3D tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark =3D skb->nfmark; + rth->fl.fl4_fwmark=3D skb->nfmark; #endif - rth->key.src =3D saddr; + rth->fl.fl4_src =3D saddr; rth->rt_src =3D saddr; #ifdef CONFIG_IP_ROUTE_NAT - rth->rt_dst_map =3D key.dst; - rth->rt_src_map =3D key.src; + rth->rt_dst_map =3D fl.fl4_dst; + rth->rt_src_map =3D fl.fl4_src; #endif #ifdef CONFIG_NET_CLS_ROUTE rth->u.dst.tclassid =3D itag; #endif rth->rt_iif =3D - rth->key.iif =3D dev->ifindex; + rth->fl.iif =3D dev->ifindex; rth->u.dst.dev =3D &loopback_dev; dev_hold(rth->u.dst.dev); - rth->key.oif =3D 0; rth->rt_gateway =3D daddr; rth->rt_spec_dst=3D spec_dst; rth->u.dst.input=3D ip_local_deliver; @@ -1656,14 +1664,14 @@ =20 read_lock(&rt_hash_table[hash].lock); for (rth =3D rt_hash_table[hash].chain; rth; rth =3D rth->u.rt_next) { - if (rth->key.dst =3D=3D daddr && - rth->key.src =3D=3D saddr && - rth->key.iif =3D=3D iif && - rth->key.oif =3D=3D 0 && + if (rth->fl.fl4_dst =3D=3D daddr && + rth->fl.fl4_src =3D=3D saddr && + rth->fl.iif =3D=3D iif && + rth->fl.oif =3D=3D 0 && #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark =3D=3D skb->nfmark && + rth->fl.fl4_fwmark =3D=3D skb->nfmark && #endif - rth->key.tos =3D=3D tos) { + rth->fl.fl4_tos =3D=3D tos) { rth->u.dst.lastuse =3D jiffies; dst_hold(&rth->u.dst); rth->u.dst.__use++; @@ -1712,43 +1720,45 @@ * Major route resolver routine. */ =20 -int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) +int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) { - struct rt_key key; + u32 tos =3D oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK); + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D oldflp->fl4_dst, + .saddr =3D oldflp->fl4_src, + .tos =3D tos & IPTOS_RT_MASK, + .scope =3D ((tos & RTO_ONLINK) ? + RT_SCOPE_LINK : + RT_SCOPE_UNIVERSE), +#ifdef CONFIG_IP_ROUTE_FWMARK + .fwmark =3D oldflp->fl4_fwmark +#endif + } }, + .iif =3D loopback_dev.ifindex, + .oif =3D oldflp->oif }; struct fib_result res; unsigned flags =3D 0; struct rtable *rth; struct net_device *dev_out =3D NULL; + struct in_device *in_dev =3D NULL; unsigned hash; int free_res =3D 0; int err; - u32 tos; =20 - tos =3D oldkey->tos & (IPTOS_RT_MASK | RTO_ONLINK); - key.dst =3D oldkey->dst; - key.src =3D oldkey->src; - key.tos =3D tos & IPTOS_RT_MASK; - key.iif =3D loopback_dev.ifindex; - key.oif =3D oldkey->oif; -#ifdef CONFIG_IP_ROUTE_FWMARK - key.fwmark =3D oldkey->fwmark; -#endif - key.scope =3D (tos & RTO_ONLINK) ? RT_SCOPE_LINK : - RT_SCOPE_UNIVERSE; res.fi =3D NULL; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r =3D NULL; #endif =20 - if (oldkey->src) { + if (oldflp->fl4_src) { err =3D -EINVAL; - if (MULTICAST(oldkey->src) || - BADCLASS(oldkey->src) || - ZERONET(oldkey->src)) + if (MULTICAST(oldflp->fl4_src) || + BADCLASS(oldflp->fl4_src) || + ZERONET(oldflp->fl4_src)) goto out; =20 /* It is equivalent to inet_addr_type(saddr) =3D=3D RTN_LOCAL */ - dev_out =3D ip_dev_find(oldkey->src); + dev_out =3D ip_dev_find(oldflp->fl4_src); if (dev_out =3D=3D NULL) goto out; =20 @@ -1760,8 +1770,8 @@ of another iface. --ANK */ =20 - if (oldkey->oif =3D=3D 0 - && (MULTICAST(oldkey->dst) || oldkey->dst =3D=3D 0xFFFFFFFF)) { + if (oldflp->oif =3D=3D 0 + && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst =3D=3D 0xFFFFFFFF)= ) { /* Special hack: user can direct multicasts and limited broadcast via necessary interface without fiddling with IP_MULTICAST_IF or IP_PKTINFO. @@ -1777,15 +1787,15 @@ Luckily, this hack is good workaround. */ =20 - key.oif =3D dev_out->ifindex; + fl.oif =3D dev_out->ifindex; goto make_route; } if (dev_out) dev_put(dev_out); dev_out =3D NULL; } - if (oldkey->oif) { - dev_out =3D dev_get_by_index(oldkey->oif); + if (oldflp->oif) { + dev_out =3D dev_get_by_index(oldflp->oif); err =3D -ENODEV; if (dev_out =3D=3D NULL) goto out; @@ -1794,39 +1804,39 @@ goto out; /* Wrong error code */ } =20 - if (LOCAL_MCAST(oldkey->dst) || oldkey->dst =3D=3D 0xFFFFFFFF) { - if (!key.src) - key.src =3D inet_select_addr(dev_out, 0, - RT_SCOPE_LINK); + if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst =3D=3D 0xFFFFFFFF) { + if (!fl.fl4_src) + fl.fl4_src =3D inet_select_addr(dev_out, 0, + RT_SCOPE_LINK); goto make_route; } - if (!key.src) { - if (MULTICAST(oldkey->dst)) - key.src =3D inet_select_addr(dev_out, 0, - key.scope); - else if (!oldkey->dst) - key.src =3D inet_select_addr(dev_out, 0, - RT_SCOPE_HOST); + if (!fl.fl4_src) { + if (MULTICAST(oldflp->fl4_dst)) + fl.fl4_src =3D inet_select_addr(dev_out, 0, + fl.fl4_scope); + else if (!oldflp->fl4_dst) + fl.fl4_src =3D inet_select_addr(dev_out, 0, + RT_SCOPE_HOST); } } =20 - if (!key.dst) { - key.dst =3D key.src; - if (!key.dst) - key.dst =3D key.src =3D htonl(INADDR_LOOPBACK); + if (!fl.fl4_dst) { + fl.fl4_dst =3D fl.fl4_src; + if (!fl.fl4_dst) + fl.fl4_dst =3D fl.fl4_src =3D htonl(INADDR_LOOPBACK); if (dev_out) dev_put(dev_out); dev_out =3D &loopback_dev; dev_hold(dev_out); - key.oif =3D loopback_dev.ifindex; + fl.oif =3D loopback_dev.ifindex; res.type =3D RTN_LOCAL; flags |=3D RTCF_LOCAL; goto make_route; } =20 - if (fib_lookup(&key, &res)) { + if (fib_lookup(&fl, &res)) { res.fi =3D NULL; - if (oldkey->oif) { + if (oldflp->oif) { /* Apparently, routing tables are wrong. Assume, that the destination is on link. =20 @@ -1845,9 +1855,9 @@ likely IPv6, but we do not. */ =20 - if (key.src =3D=3D 0) - key.src =3D inet_select_addr(dev_out, 0, - RT_SCOPE_LINK); + if (fl.fl4_src =3D=3D 0) + fl.fl4_src =3D inet_select_addr(dev_out, 0, + RT_SCOPE_LINK); res.type =3D RTN_UNICAST; goto make_route; } @@ -1862,13 +1872,13 @@ goto e_inval; =20 if (res.type =3D=3D RTN_LOCAL) { - if (!key.src) - key.src =3D key.dst; + if (!fl.fl4_src) + fl.fl4_src =3D fl.fl4_dst; if (dev_out) dev_put(dev_out); dev_out =3D &loopback_dev; dev_hold(dev_out); - key.oif =3D dev_out->ifindex; + fl.oif =3D dev_out->ifindex; if (res.fi) fib_info_put(res.fi); res.fi =3D NULL; @@ -1877,36 +1887,40 @@ } =20 #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res.fi->fib_nhs > 1 && key.oif =3D=3D 0) - fib_select_multipath(&key, &res); + if (res.fi->fib_nhs > 1 && fl.oif =3D=3D 0) + fib_select_multipath(&fl, &res); else #endif - if (!res.prefixlen && res.type =3D=3D RTN_UNICAST && !key.oif) - fib_select_default(&key, &res); + if (!res.prefixlen && res.type =3D=3D RTN_UNICAST && !fl.oif) + fib_select_default(&fl, &res); =20 - if (!key.src) - key.src =3D FIB_RES_PREFSRC(res); + if (!fl.fl4_src) + fl.fl4_src =3D FIB_RES_PREFSRC(res); =20 if (dev_out) dev_put(dev_out); dev_out =3D FIB_RES_DEV(res); dev_hold(dev_out); - key.oif =3D dev_out->ifindex; + fl.oif =3D dev_out->ifindex; =20 make_route: - if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK)) + if (LOOPBACK(fl.fl4_src) && !(dev_out->flags&IFF_LOOPBACK)) goto e_inval; =20 - if (key.dst =3D=3D 0xFFFFFFFF) + if (fl.fl4_dst =3D=3D 0xFFFFFFFF) res.type =3D RTN_BROADCAST; - else if (MULTICAST(key.dst)) + else if (MULTICAST(fl.fl4_dst)) res.type =3D RTN_MULTICAST; - else if (BADCLASS(key.dst) || ZERONET(key.dst)) + else if (BADCLASS(fl.fl4_dst) || ZERONET(fl.fl4_dst)) goto e_inval; =20 if (dev_out->flags & IFF_LOOPBACK) flags |=3D RTCF_LOCAL; =20 + in_dev =3D in_dev_get(dev_out); + if (!in_dev) + goto e_inval; + if (res.type =3D=3D RTN_BROADCAST) { flags |=3D RTCF_BROADCAST | RTCF_LOCAL; if (res.fi) { @@ -1915,11 +1929,8 @@ } } else if (res.type =3D=3D RTN_MULTICAST) { flags |=3D RTCF_MULTICAST|RTCF_LOCAL; - read_lock(&inetdev_lock); - if (!__in_dev_get(dev_out) || - !ip_check_mc(__in_dev_get(dev_out), oldkey->dst)) + if (!ip_check_mc(in_dev, oldflp->fl4_dst)) flags &=3D ~RTCF_LOCAL; - read_unlock(&inetdev_lock); /* If multicast route do not exist use default one, but do not gateway in this case. Yes, it is hack. @@ -1936,25 +1947,28 @@ =20 atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags=3D DST_HOST; - rth->key.dst =3D oldkey->dst; - rth->key.tos =3D tos; - rth->key.src =3D oldkey->src; - rth->key.iif =3D 0; - rth->key.oif =3D oldkey->oif; + if (in_dev->cnf.no_xfrm) + rth->u.dst.flags |=3D DST_NOXFRM; + if (in_dev->cnf.no_policy) + rth->u.dst.flags |=3D DST_NOPOLICY; + rth->fl.fl4_dst =3D oldflp->fl4_dst; + rth->fl.fl4_tos =3D tos; + rth->fl.fl4_src =3D oldflp->fl4_src; + rth->fl.oif =3D oldflp->oif; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark =3D oldkey->fwmark; + rth->fl.fl4_fwmark=3D oldflp->fl4_fwmark; #endif - rth->rt_dst =3D key.dst; - rth->rt_src =3D key.src; + rth->rt_dst =3D fl.fl4_dst; + rth->rt_src =3D fl.fl4_src; #ifdef CONFIG_IP_ROUTE_NAT - rth->rt_dst_map =3D key.dst; - rth->rt_src_map =3D key.src; + rth->rt_dst_map =3D fl.fl4_dst; + rth->rt_src_map =3D fl.fl4_src; #endif - rth->rt_iif =3D oldkey->oif ? : dev_out->ifindex; + rth->rt_iif =3D oldflp->oif ? : dev_out->ifindex; rth->u.dst.dev =3D dev_out; dev_hold(dev_out); - rth->rt_gateway =3D key.dst; - rth->rt_spec_dst=3D key.src; + rth->rt_gateway =3D fl.fl4_dst; + rth->rt_spec_dst=3D fl.fl4_src; =20 rth->u.dst.output=3Dip_output; =20 @@ -1962,40 +1976,39 @@ =20 if (flags & RTCF_LOCAL) { rth->u.dst.input =3D ip_local_deliver; - rth->rt_spec_dst =3D key.dst; + rth->rt_spec_dst =3D fl.fl4_dst; } if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { - rth->rt_spec_dst =3D key.src; + rth->rt_spec_dst =3D fl.fl4_src; if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) { rth->u.dst.output =3D ip_mc_output; rt_cache_stat[smp_processor_id()].out_slow_mc++; } #ifdef CONFIG_IP_MROUTE if (res.type =3D=3D RTN_MULTICAST) { - struct in_device *in_dev =3D in_dev_get(dev_out); - if (in_dev) { - if (IN_DEV_MFORWARD(in_dev) && - !LOCAL_MCAST(oldkey->dst)) { - rth->u.dst.input =3D ip_mr_input; - rth->u.dst.output =3D ip_mc_output; - } - in_dev_put(in_dev); + if (IN_DEV_MFORWARD(in_dev) && + !LOCAL_MCAST(oldflp->fl4_dst)) { + rth->u.dst.input =3D ip_mr_input; + rth->u.dst.output =3D ip_mc_output; } } #endif } =20 rt_set_nexthop(rth, &res, 0); +=09 =20 rth->rt_flags =3D flags; =20 - hash =3D rt_hash_code(oldkey->dst, oldkey->src ^ (oldkey->oif << 5), tos)= ; + hash =3D rt_hash_code(oldflp->fl4_dst, oldflp->fl4_src ^ (oldflp->oif << = 5), tos); err =3D rt_intern_hash(hash, rth, rp); done: if (free_res) fib_res_put(&res); if (dev_out) dev_put(dev_out); + if (in_dev) + in_dev_put(in_dev); out: return err; =20 e_inval: @@ -2006,23 +2019,23 @@ goto done; } =20 -int ip_route_output_key(struct rtable **rp, const struct rt_key *key) +int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) { unsigned hash; struct rtable *rth; =20 - hash =3D rt_hash_code(key->dst, key->src ^ (key->oif << 5), key->tos); + hash =3D rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->= fl4_tos); =20 read_lock_bh(&rt_hash_table[hash].lock); for (rth =3D rt_hash_table[hash].chain; rth; rth =3D rth->u.rt_next) { - if (rth->key.dst =3D=3D key->dst && - rth->key.src =3D=3D key->src && - rth->key.iif =3D=3D 0 && - rth->key.oif =3D=3D key->oif && + if (rth->fl.fl4_dst =3D=3D flp->fl4_dst && + rth->fl.fl4_src =3D=3D flp->fl4_src && + rth->fl.iif =3D=3D 0 && + rth->fl.oif =3D=3D flp->oif && #ifdef CONFIG_IP_ROUTE_FWMARK - rth->key.fwmark =3D=3D key->fwmark && + rth->fl.fl4_fwmark =3D=3D flp->fl4_fwmark && #endif - !((rth->key.tos ^ key->tos) & + !((rth->fl.fl4_tos ^ flp->fl4_tos) & (IPTOS_RT_MASK | RTO_ONLINK))) { rth->u.dst.lastuse =3D jiffies; dst_hold(&rth->u.dst); @@ -2035,8 +2048,26 @@ } read_unlock_bh(&rt_hash_table[hash].lock); =20 - return ip_route_output_slow(rp, key); -}=09 + return ip_route_output_slow(rp, flp); +} + +int ip_route_output_key(struct rtable **rp, struct flowi *flp) +{ + int err; + + if ((err =3D __ip_route_output_key(rp, flp)) !=3D 0) + return err; + return flp->proto ? xfrm_lookup((struct dst_entry**)rp, flp, NULL, 0) : 0= ; +} + +int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct soc= k *sk, int flags) +{ + int err; + + if ((err =3D __ip_route_output_key(rp, flp)) !=3D 0) + return err; + return flp->proto ? xfrm_lookup((struct dst_entry**)rp, flp, sk, flags) := 0; +} =20 static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait) @@ -2055,7 +2086,7 @@ r->rtm_family =3D AF_INET; r->rtm_dst_len =3D 32; r->rtm_src_len =3D 0; - r->rtm_tos =3D rt->key.tos; + r->rtm_tos =3D rt->fl.fl4_tos; r->rtm_table =3D RT_TABLE_MAIN; r->rtm_type =3D rt->rt_type; r->rtm_scope =3D RT_SCOPE_UNIVERSE; @@ -2064,9 +2095,9 @@ if (rt->rt_flags & RTCF_NOTIFY) r->rtm_flags |=3D RTM_F_NOTIFY; RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst); - if (rt->key.src) { + if (rt->fl.fl4_src) { r->rtm_src_len =3D 32; - RTA_PUT(skb, RTA_SRC, 4, &rt->key.src); + RTA_PUT(skb, RTA_SRC, 4, &rt->fl.fl4_src); } if (rt->u.dst.dev) RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); @@ -2074,13 +2105,13 @@ if (rt->u.dst.tclassid) RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid); #endif - if (rt->key.iif) + if (rt->fl.iif) RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); - else if (rt->rt_src !=3D rt->key.src) + else if (rt->rt_src !=3D rt->fl.fl4_src) RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); if (rt->rt_dst !=3D rt->rt_gateway) RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); - if (rtnetlink_put_metrics(skb, &rt->u.dst.mxlock) < 0) + if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto rtattr_failure; ci.rta_lastuse =3D jiffies - rt->u.dst.lastuse; ci.rta_used =3D rt->u.dst.__use; @@ -2102,7 +2133,7 @@ eptr =3D (struct rtattr*)skb->tail; #endif RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); - if (rt->key.iif) { + if (rt->fl.iif) { #ifdef CONFIG_IP_MROUTE u32 dst =3D rt->rt_dst; =20 @@ -2122,7 +2153,7 @@ } } else #endif - RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->key.iif); + RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); } =20 nlh->nlmsg_len =3D skb->tail - b; @@ -2176,10 +2207,14 @@ if (!err && rt->u.dst.error) err =3D -rt->u.dst.error; } else { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D { .daddr =3D dst, + .saddr =3D src, + .tos =3D rtm->rtm_tos } } }; int oif =3D 0; if (rta[RTA_OIF - 1]) memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); - err =3D ip_route_output(&rt, dst, src, rtm->rtm_tos, oif); + fl.oif =3D oif; + err =3D ip_route_output_key(&rt, &fl); } if (err) goto out_free; @@ -2568,4 +2603,6 @@ #ifdef CONFIG_NET_CLS_ROUTE create_proc_read_entry("net/rt_acct", 0, 0, ip_rt_acct_read, NULL); #endif + xfrm_init(); + xfrm4_init(); } diff -Nru a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c --- a/net/ipv4/syncookies.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/syncookies.c Thu May 8 10:41:36 2003 @@ -169,18 +169,25 @@ * hasn't changed since we received the original syn, but I see * no easy way to do this.=20 */ - if (ip_route_output(&rt, - opt &&=20 - opt->srr ? opt->faddr : req->af.v4_req.rmt_addr, - req->af.v4_req.loc_addr, - RT_CONN_FLAGS(sk), - 0)) {=20 - tcp_openreq_free(req); - goto out;=20 + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D ((opt && opt->srr) ? + opt->faddr : + req->af.v4_req.rmt_addr), + .saddr =3D req->af.v4_req.loc_addr, + .tos =3D RT_CONN_FLAGS(sk) } }, + .proto =3D IPPROTO_TCP, + .uli_u =3D { .ports =3D + { .sport =3D skb->h.th->dest, + .dport =3D skb->h.th->source } } }; + if (ip_route_output_key(&rt, &fl)) { + tcp_openreq_free(req); + goto out;=20 + } } =20 /* Try to redo what tcp_v4_send_synack did. */ - req->window_clamp =3D rt->u.dst.window; =20 + req->window_clamp =3D dst_metric(&rt->u.dst, RTAX_WINDOW); tcp_select_initial_window(tcp_full_space(sk), req->mss, &req->rcv_wnd, &req->window_clamp,=20 0, &rcv_wscale); diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c --- a/net/ipv4/sysctl_net_ipv4.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/sysctl_net_ipv4.c Thu May 8 10:41:37 2003 @@ -77,14 +77,39 @@ void *newval, size_t newlen,=20 void **context) { + int *valp =3D table->data; int new; + + if (!newval || !newlen) + return 0; + if (newlen !=3D sizeof(int)) return -EINVAL; - if (get_user(new,(int *)newval)) - return -EFAULT;=20 - if (new !=3D ipv4_devconf.forwarding)=20 - inet_forward_change();=20 - return 0; /* caller does change again and handles handles oldval */=20 + + if (get_user(new, (int *)newval)) + return -EFAULT; + + if (new =3D=3D *valp) + return 0; + + if (oldval && oldlenp) { + size_t len; + + if (get_user(len, oldlenp)) + return -EFAULT; + + if (len) { + if (len > table->maxlen) + len =3D table->maxlen; + if (copy_to_user(oldval, valp, len)) + return -EFAULT; + if (put_user(len, oldlenp)) + return -EFAULT; + } + } + + inet_forward_change(); + return 1; } =20 ctl_table ipv4_table[] =3D { diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/tcp.c Thu May 8 10:41:37 2003 @@ -204,6 +204,8 @@ * Andi Kleen : Make poll agree with SIGIO * Salvatore Sanfilippo : Support SO_LINGER with linger =3D=3D 1 and * lingertime =3D=3D 0 (RFC 793 ABORT Call) + * Hirokazu Takahashi : Use copy_from_user() instead of + * csum_and_copy_from_user() if possible. * =09 * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -256,6 +258,7 @@ =20 #include #include +#include =20 #include #include @@ -953,8 +956,8 @@ return res; } =20 -#define TCP_PAGE(sk) (sk->tp_pinfo.af_tcp.sndmsg_page) -#define TCP_OFF(sk) (sk->tp_pinfo.af_tcp.sndmsg_off) +#define TCP_PAGE(sk) (inet_sk(sk)->sndmsg_page) +#define TCP_OFF(sk) (inet_sk(sk)->sndmsg_off) =20 static inline int tcp_copy_to_page(struct sock *sk, char *from, struct sk_buff *skb, @@ -963,18 +966,22 @@ int err =3D 0; unsigned int csum; =20 - csum =3D csum_and_copy_from_user(from, page_address(page)+off, + if (skb->ip_summed =3D=3D CHECKSUM_NONE) { + csum =3D csum_and_copy_from_user(from, page_address(page) + off, copy, 0, &err); - if (!err) { - if (skb->ip_summed =3D=3D CHECKSUM_NONE) - skb->csum =3D csum_block_add(skb->csum, csum, skb->len); - skb->len +=3D copy; - skb->data_len +=3D copy; - skb->truesize +=3D copy; - sk->wmem_queued +=3D copy; - sk->forward_alloc -=3D copy; + if (err) return err; + skb->csum =3D csum_block_add(skb->csum, csum, skb->len); + } else { + if (copy_from_user(page_address(page) + off, from, copy)) + return -EFAULT; } - return err; + + skb->len +=3D copy; + skb->data_len +=3D copy; + skb->truesize +=3D copy; + sk->wmem_queued +=3D copy; + sk->forward_alloc -=3D copy; + return 0; } =20 static inline int @@ -984,11 +991,16 @@ unsigned int csum; int off =3D skb->len; =20 - csum =3D csum_and_copy_from_user(from, skb_put(skb, copy), + if (skb->ip_summed =3D=3D CHECKSUM_NONE) { + csum =3D csum_and_copy_from_user(from, skb_put(skb, copy), copy, 0, &err); - if (!err) { - skb->csum =3D csum_block_add(skb->csum, csum, off); - return 0; + if (!err) { + skb->csum =3D csum_block_add(skb->csum, csum, off); + return 0; + } + } else { + if (!copy_from_user(skb_put(skb, copy), from, copy)) + return 0; } =20 __skb_trim(skb, off); @@ -1070,6 +1082,12 @@ if (skb =3D=3D NULL) goto wait_for_memory; =20 + /* + * Check whether we can use HW checksum. + */ + if (sk->route_caps & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)= ) + skb->ip_summed =3D CHECKSUM_HW; + skb_entail(sk, tp, skb); copy =3D mss_now; } @@ -1888,6 +1906,8 @@ sk->prot->destroy(sk); =20 tcp_kill_sk_queues(sk); + + xfrm_sk_free_policy(sk); =20 #ifdef INET_REFCNT_DEBUG if (atomic_read(&sk->refcnt) !=3D 1) { diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c --- a/net/ipv4/tcp_input.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/tcp_input.c Thu May 8 10:41:37 2003 @@ -524,25 +524,25 @@ * Probably, no packets returned in time. * Reset our results. */ - if (!(dst->mxlock&(1<rtt =3D 0; + if (!(dst_metric_locked(dst, RTAX_RTT))) + dst->metrics[RTAX_RTT-1] =3D 0; return; } =20 - m =3D dst->rtt - tp->srtt; + m =3D dst_metric(dst, RTAX_RTT) - tp->srtt; =20 /* If newly calculated rtt larger than stored one, * store new one. Otherwise, use EWMA. Remember, * rtt overestimation is always better than underestimation. */ - if (!(dst->mxlock&(1<rtt =3D tp->srtt; + dst->metrics[RTAX_RTT-1] =3D tp->srtt; else - dst->rtt -=3D (m>>3); + dst->metrics[RTAX_RTT-1] -=3D (m>>3); } =20 - if (!(dst->mxlock&(1<mdev) m =3D tp->mdev; =20 - if (m >=3D dst->rttvar) - dst->rttvar =3D m; + if (m >=3D dst_metric(dst, RTAX_RTTVAR)) + dst->metrics[RTAX_RTTVAR-1] =3D m; else - dst->rttvar -=3D (dst->rttvar - m)>>2; + dst->metrics[RTAX_RTT-1] -=3D + (dst->metrics[RTAX_RTT-1] - m)>>2; } =20 if (tp->snd_ssthresh >=3D 0xFFFF) { /* Slow start still did not finish. */ - if (dst->ssthresh && - !(dst->mxlock&(1<snd_cwnd>>1) > dst->ssthresh) - dst->ssthresh =3D (tp->snd_cwnd>>1); - if (!(dst->mxlock&(1<snd_cwnd > dst->cwnd) - dst->cwnd =3D tp->snd_cwnd; + if (dst_metric(dst, RTAX_SSTHRESH) && + !dst_metric_locked(dst, RTAX_SSTHRESH) && + (tp->snd_cwnd >> 1) > dst_metric(dst, RTAX_SSTHRESH)) + dst->metrics[RTAX_SSTHRESH-1] =3D tp->snd_cwnd >> 1; + if (!dst_metric_locked(dst, RTAX_CWND) && + tp->snd_cwnd > dst_metric(dst, RTAX_CWND)) + dst->metrics[RTAX_CWND-1] =3D tp->snd_cwnd; } else if (tp->snd_cwnd > tp->snd_ssthresh && tp->ca_state =3D=3D TCP_CA_Open) { /* Cong. avoidance phase, cwnd is reliable. */ - if (!(dst->mxlock&(1<ssthresh =3D max(tp->snd_cwnd>>1, tp->snd_ssthresh); - if (!(dst->mxlock&(1<cwnd =3D (dst->cwnd + tp->snd_cwnd)>>1; + if (!dst_metric_locked(dst, RTAX_SSTHRESH)) + dst->metrics[RTAX_SSTHRESH-1] =3D + max(tp->snd_cwnd >> 1, tp->snd_ssthresh); + if (!dst_metric_locked(dst, RTAX_CWND)) + dst->metrics[RTAX_CWND-1] =3D (dst->metrics[RTAX_CWND-1] + tp->snd_cwn= d) >> 1; } else { /* Else slow start did not finish, cwnd is non-sense, ssthresh may be also invalid. */ - if (!(dst->mxlock&(1<cwnd =3D (dst->cwnd + tp->snd_ssthresh)>>1; - if (dst->ssthresh && - !(dst->mxlock&(1<snd_ssthresh > dst->ssthresh) - dst->ssthresh =3D tp->snd_ssthresh; + if (!dst_metric_locked(dst, RTAX_CWND)) + dst->metrics[RTAX_CWND-1] =3D (dst->metrics[RTAX_CWND-1] + tp->snd_sst= hresh) >> 1; + if (dst->metrics[RTAX_SSTHRESH-1] && + !dst_metric_locked(dst, RTAX_SSTHRESH) && + tp->snd_ssthresh > dst->metrics[RTAX_SSTHRESH-1]) + dst->metrics[RTAX_SSTHRESH-1] =3D tp->snd_ssthresh; } =20 - if (!(dst->mxlock&(1<reordering < tp->reordering && + if (!dst_metric_locked(dst, RTAX_REORDERING)) { + if (dst->metrics[RTAX_REORDERING-1] < tp->reordering && tp->reordering !=3D sysctl_tcp_reordering) - dst->reordering =3D tp->reordering; + dst->metrics[RTAX_REORDERING-1] =3D tp->reordering; } } } @@ -627,22 +629,23 @@ =20 dst_confirm(dst); =20 - if (dst->mxlock&(1<snd_cwnd_clamp =3D dst->cwnd; - if (dst->ssthresh) { - tp->snd_ssthresh =3D dst->ssthresh; + if (dst_metric_locked(dst, RTAX_CWND)) + tp->snd_cwnd_clamp =3D dst_metric(dst, RTAX_CWND); + if (dst_metric(dst, RTAX_SSTHRESH)) { + tp->snd_ssthresh =3D dst_metric(dst, RTAX_SSTHRESH); if (tp->snd_ssthresh > tp->snd_cwnd_clamp) tp->snd_ssthresh =3D tp->snd_cwnd_clamp; } - if (dst->reordering && tp->reordering !=3D dst->reordering) { + if (dst_metric(dst, RTAX_REORDERING) && + tp->reordering !=3D dst_metric(dst, RTAX_REORDERING)) { tp->sack_ok &=3D ~2; - tp->reordering =3D dst->reordering; + tp->reordering =3D dst_metric(dst, RTAX_REORDERING); } =20 - if (dst->rtt =3D=3D 0) + if (dst_metric(dst, RTAX_RTT) =3D=3D 0) goto reset; =20 - if (!tp->srtt && dst->rtt < (TCP_TIMEOUT_INIT<<3)) + if (!tp->srtt && dst_metric(dst, RTAX_RTT) < (TCP_TIMEOUT_INIT << 3)) goto reset; =20 /* Initial rtt is determined from SYN,SYN-ACK. @@ -659,10 +662,10 @@ * to low value, and then abruptly stops to do it and starts to delay * ACKs, wait for troubles. */ - if (dst->rtt > tp->srtt) - tp->srtt =3D dst->rtt; - if (dst->rttvar > tp->mdev) { - tp->mdev =3D dst->rttvar; + if (dst_metric(dst, RTAX_RTT) > tp->srtt) + tp->srtt =3D dst_metric(dst, RTAX_RTT); + if (dst_metric(dst, RTAX_RTTVAR) > tp->mdev) { + tp->mdev =3D dst_metric(dst, RTAX_RTTVAR); tp->mdev_max =3D tp->rttvar =3D max(tp->mdev, TCP_RTO_MIN); } tcp_set_rto(tp); diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/tcp_ipv4.c Thu May 8 10:41:37 2003 @@ -63,10 +63,10 @@ #include #include #include +#include =20 #include #include -#include =20 extern int sysctl_ip_dynaddr; extern int sysctl_ip_default_ttl; @@ -783,7 +783,9 @@ } =20 tmp =3D ip_route_connect(&rt, nexthop, sk->saddr, - RT_CONN_FLAGS(sk), sk->bound_dev_if); + RT_CONN_FLAGS(sk), sk->bound_dev_if, + IPPROTO_TCP, + sk->sport, usin->sin_port, sk); if (tmp < 0) return tmp; =20 @@ -792,9 +794,6 @@ return -ENETUNREACH; } =20 - __sk_dst_set(sk, &rt->u.dst); - sk->route_caps =3D rt->u.dst.dev->features; - if (!sk->protinfo.af_inet.opt || !sk->protinfo.af_inet.opt->srr) daddr =3D rt->rt_dst; =20 @@ -844,6 +843,15 @@ if (err) goto failure; =20 + err =3D ip_route_newports(&rt, sk->sport, sk->dport, sk); + if (err) + goto failure; + + /* OK, now commit destination to socket. */ + __sk_dst_set(sk, &rt->u.dst); + sk->route_caps =3D rt->u.dst.dev->features; + tp->ext2_header_len =3D rt->u.dst.header_len; + if (!tp->write_seq) tp->write_seq =3D secure_tcp_sequence_number(sk->saddr, sk->daddr, sk->sport, usin->sin_port); @@ -851,14 +859,16 @@ sk->protinfo.af_inet.id =3D tp->write_seq^jiffies; =20 err =3D tcp_connect(sk); + rt =3D NULL; if (err) goto failure; =20 return 0; =20 failure: + /* This unhashes the socket and releases the local port, if necessary. */ tcp_set_state(sk, TCP_CLOSE); - __sk_dst_reset(sk); + ip_rt_put(rt); sk->route_caps =3D 0; sk->dport =3D 0; return err; @@ -920,7 +930,7 @@ /*=20 * This routine does path mtu discovery as defined in RFC1191. */ -static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip, un= signed mtu) +static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip, u3= 2 mtu) { struct dst_entry *dst; struct tcp_opt *tp =3D &sk->tp_pinfo.af_tcp; @@ -941,17 +951,19 @@ if ((dst =3D __sk_dst_check(sk, 0)) =3D=3D NULL) return; =20 - ip_rt_update_pmtu(dst, mtu); + dst->ops->update_pmtu(dst, mtu); =20 /* Something is about to be wrong... Remember soft error * for the case, if this connection will not able to recover. */ - if (mtu < dst->pmtu && ip_dont_fragment(sk, dst)) + if (mtu < dst_pmtu(dst) && ip_dont_fragment(sk, dst)) sk->err_soft =3D EMSGSIZE; =20 + mtu =3D dst_pmtu(dst); + if (sk->protinfo.af_inet.pmtudisc !=3D IP_PMTUDISC_DONT && - tp->pmtu_cookie > dst->pmtu) { - tcp_sync_mss(sk, dst->pmtu); + tp->pmtu_cookie > mtu) { + tcp_sync_mss(sk, mtu); =20 /* Resend the TCP packet because it's =20 * clear that the old packet has been @@ -1189,7 +1201,6 @@ sizeof(struct tcphdr), IPPROTO_TCP, 0);=20 - arg.n_iov =3D 1; arg.csumoffset =3D offsetof(struct tcphdr, check) / 2;=20 =20 tcp_socket->sk->protinfo.af_inet.ttl =3D sysctl_ip_default_ttl; @@ -1217,7 +1228,6 @@ =20 arg.iov[0].iov_base =3D (unsigned char *)&rep;=20 arg.iov[0].iov_len =3D sizeof(rep.th); - arg.n_iov =3D 1; if (ts) { rep.tsopt[0] =3D htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -1268,14 +1278,20 @@ static struct dst_entry* tcp_v4_route_req(struct sock *sk, struct open_req= uest *req) { struct rtable *rt; - struct ip_options *opt; + struct ip_options *opt =3D req->af.v4_req.opt; + struct flowi fl =3D { .oif =3D sk->bound_dev_if, + .nl_u =3D { .ip4_u =3D + { .daddr =3D ((opt && opt->srr) ? + opt->faddr : + req->af.v4_req.rmt_addr), + .saddr =3D req->af.v4_req.loc_addr, + .tos =3D RT_CONN_FLAGS(sk) } }, + .proto =3D IPPROTO_TCP, + .uli_u =3D { .ports =3D + { .sport =3D sk->sport, + .dport =3D req->rmt_port } } }; =20 - opt =3D req->af.v4_req.opt; - if(ip_route_output(&rt, ((opt && opt->srr) ? - opt->faddr : - req->af.v4_req.rmt_addr), - req->af.v4_req.loc_addr, - RT_CONN_FLAGS(sk), sk->bound_dev_if)) { + if (ip_route_output_flow(&rt, &fl, sk, 0)) { IP_INC_STATS_BH(IpOutNoRoutes); return NULL; } @@ -1498,7 +1514,7 @@ (sysctl_max_syn_backlog - tcp_synq_len(sk) < (sysctl_max_syn_backlog>>2)) && (!peer || !peer->tcp_ts_stamp) && - (!dst || !dst->rtt)) { + (!dst || !dst_metric(dst, RTAX_RTT))) { /* Without syncookies last quarter of * backlog is filled with destinations, proven to be alive. * It means that we continue to communicate @@ -1570,10 +1586,11 @@ newtp->ext_header_len =3D 0; if (newsk->protinfo.af_inet.opt) newtp->ext_header_len =3D newsk->protinfo.af_inet.opt->optlen; + newtp->ext2_header_len =3D dst->header_len; newsk->protinfo.af_inet.id =3D newtp->write_seq^jiffies; =20 - tcp_sync_mss(newsk, dst->pmtu); - newtp->advmss =3D dst->advmss; + tcp_sync_mss(newsk, dst_pmtu(dst)); + newtp->advmss =3D dst_metric(dst, RTAX_ADVMSS);; tcp_initialize_rcv_mss(newsk); =20 __tcp_v4_hash(newsk, 0); @@ -1758,12 +1775,12 @@ goto no_tcp_socket; =20 process: - if(!ipsec_sk_policy(sk,skb)) - goto discard_and_relse; - if (sk->state =3D=3D TCP_TIME_WAIT) goto do_time_wait; =20 + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) + goto discard_and_relse; + if (sk_filter(sk, skb, 0)) goto discard_and_relse; =20 @@ -1783,6 +1800,9 @@ return ret; =20 no_tcp_socket: + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard_it; + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); @@ -1800,6 +1820,9 @@ goto discard_it; =20 do_time_wait: + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard_and_relse; + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); goto discard_and_relse; @@ -1853,7 +1876,9 @@ /* Query new route. */ err =3D ip_route_connect(&rt, daddr, 0, RT_TOS(sk->protinfo.af_inet.tos)|sk->localroute, - sk->bound_dev_if); + sk->bound_dev_if, + IPPROTO_TCP, + sk->sport, sk->dport, sk); if (err) return err; =20 @@ -1901,8 +1926,19 @@ if(sk->protinfo.af_inet.opt && sk->protinfo.af_inet.opt->srr) daddr =3D sk->protinfo.af_inet.opt->faddr; =20 - err =3D ip_route_output(&rt, daddr, sk->saddr, - RT_CONN_FLAGS(sk), sk->bound_dev_if); + { + struct flowi fl =3D { .oif =3D sk->bound_dev_if, + .nl_u =3D { .ip4_u =3D + { .daddr =3D daddr, + .saddr =3D sk->saddr, + .tos =3D RT_CONN_FLAGS(sk) } }, + .proto =3D IPPROTO_TCP, + .uli_u =3D { .ports =3D + { .sport =3D sk->sport, + .dport =3D sk->dport } } }; + =09 + err =3D ip_route_output_flow(&rt, &fl, sk, 0); + } if (!err) { __sk_dst_set(sk, &rt->u.dst); sk->route_caps =3D rt->u.dst.dev->features; @@ -2067,8 +2103,8 @@ tcp_put_port(sk); =20 /* If sendmsg cached page exists, toss it. */ - if (tp->sndmsg_page !=3D NULL) - __free_page(tp->sndmsg_page); + if (inet_sk(sk)->sndmsg_page) + __free_page(inet_sk(sk)->sndmsg_page); =20 atomic_dec(&tcp_sockets_allocated); =20 diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c --- a/net/ipv4/tcp_minisocks.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/tcp_minisocks.c Thu May 8 10:41:37 2003 @@ -25,6 +25,7 @@ #include #include #include +#include =20 #ifdef CONFIG_SYSCTL #define SYNC_INIT 0 /* let the user enable it */ @@ -681,6 +682,13 @@ if ((filter =3D newsk->filter) !=3D NULL) sk_filter_charge(newsk, filter); #endif + if (unlikely(xfrm_sk_clone_policy(newsk))) { + /* It is still raw copy of parent, so invalidate + * destructor and make plain sk_free() */ + newsk->destruct =3D NULL; + sk_free(newsk); + return NULL; + } =20 /* Now setup tcp_opt */ newtp =3D &(newsk->tp_pinfo.af_tcp); diff -Nru a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c --- a/net/ipv4/tcp_output.c Thu May 8 10:41:37 2003 +++ b/net/ipv4/tcp_output.c Thu May 8 10:41:37 2003 @@ -89,8 +89,8 @@ struct dst_entry *dst =3D __sk_dst_get(sk); int mss =3D tp->advmss; =20 - if (dst && dst->advmss < mss) { - mss =3D dst->advmss; + if (dst && dst_metric(dst, RTAX_ADVMSS) < mss) { + mss =3D dst_metric(dst, RTAX_ADVMSS); tp->advmss =3D mss; } =20 @@ -502,13 +502,16 @@ =20 int tcp_sync_mss(struct sock *sk, u32 pmtu) { - struct tcp_opt *tp =3D &sk->tp_pinfo.af_tcp; + struct tcp_opt *tp =3D tcp_sk(sk); + struct dst_entry *dst =3D __sk_dst_get(sk); int mss_now; =20 + if (dst && dst->ops->get_mss) + pmtu =3D dst->ops->get_mss(dst, pmtu); + /* Calculate base mss without TCP options: It is MMS_S - sizeof(tcphdr) of rfc1122 */ - mss_now =3D pmtu - tp->af_specific->net_header_len - sizeof(struct tcphdr= ); =20 /* Clamp it (mss_clamp does not include tcp options) */ @@ -516,7 +519,7 @@ mss_now =3D tp->mss_clamp; =20 /* Now subtract optional transport overhead */ - mss_now -=3D tp->ext_header_len; + mss_now -=3D tp->ext_header_len + tp->ext2_header_len; =20 /* Then reserve room for full set of TCP options and 8 bytes of data */ if (mss_now < 48) @@ -1131,10 +1134,10 @@ if (req->rcv_wnd =3D=3D 0) { /* ignored for retransmitted syns */ __u8 rcv_wscale;=20 /* Set this up on the first call only */ - req->window_clamp =3D tp->window_clamp ? : dst->window; + req->window_clamp =3D tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW); /* tcp_full_space because it is guaranteed to be the first packet */ tcp_select_initial_window(tcp_full_space(sk),=20 - dst->advmss - (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), + dst_metric(dst, RTAX_ADVMSS) - (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED= : 0), &req->rcv_wnd, &req->window_clamp, req->wscale_ok, @@ -1146,7 +1149,7 @@ th->window =3D htons(req->rcv_wnd); =20 TCP_SKB_CB(skb)->when =3D tcp_time_stamp; - tcp_syn_build_options((__u32 *)(th + 1), dst->advmss, req->tstamp_ok, + tcp_syn_build_options((__u32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), re= q->tstamp_ok, req->sack_ok, req->wscale_ok, req->rcv_wscale, TCP_SKB_CB(skb)->when, req->ts_recent); @@ -1175,11 +1178,11 @@ if (tp->user_mss) tp->mss_clamp =3D tp->user_mss; tp->max_window =3D 0; - tcp_sync_mss(sk, dst->pmtu); + tcp_sync_mss(sk, dst_pmtu(dst)); =20 if (!tp->window_clamp) - tp->window_clamp =3D dst->window; - tp->advmss =3D dst->advmss; + tp->window_clamp =3D dst_metric(dst, RTAX_WINDOW); + tp->advmss =3D dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(sk); =20 tcp_select_initial_window(tcp_full_space(sk), diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c --- a/net/ipv4/udp.c Thu May 8 10:41:36 2003 +++ b/net/ipv4/udp.c Thu May 8 10:41:36 2003 @@ -11,6 +11,7 @@ * Fred N. van Kempen, * Arnt Gulbrandsen, * Alan Cox, + * Hirokazu Takahashi, * * Fixes: * Alan Cox : verify_area() calls @@ -64,6 +65,10 @@ * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which * Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind * a single port at the same time. + * Hirokazu Takahashi : HW checksumming for outgoing UDP + * datagrams. + * Hirokazu Takahashi : sendfile() on UDP works now. + * Derek Atkins : Add Encapulation Support * * * This program is free software; you can redistribute it and/or @@ -97,6 +102,7 @@ #include #include #include +#include =20 /* * Snmp MIB for the UDP layer @@ -365,80 +371,118 @@ sock_put(sk); } =20 - -static unsigned short udp_check(struct udphdr *uh, int len, unsigned long = saddr, unsigned long daddr, unsigned long base) -{ - return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); -} - -struct udpfakehdr=20 -{ - struct udphdr uh; - u32 saddr; - u32 daddr; - struct iovec *iov; - u32 wcheck; -}; - /* - * Copy and checksum a UDP packet from user space into a buffer. + * Throw away all pending data and cancel the corking. Socket is locked. */ -=20 -static int udp_getfrag(const void *p, char * to, unsigned int offset, unsi= gned int fraglen)=20 +static void udp_flush_pending_frames(struct sock *sk) { - struct udpfakehdr *ufh =3D (struct udpfakehdr *)p; - if (offset=3D=3D0) { - if (csum_partial_copy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, o= ffset, - fraglen-sizeof(struct udphdr), &ufh->wcheck)) - return -EFAULT; - ufh->wcheck =3D csum_partial((char *)ufh, sizeof(struct udphdr), - ufh->wcheck); - ufh->uh.check =3D csum_tcpudp_magic(ufh->saddr, ufh->daddr,=20 - ntohs(ufh->uh.len), - IPPROTO_UDP, ufh->wcheck); - if (ufh->uh.check =3D=3D 0) - ufh->uh.check =3D -1; - memcpy(to, ufh, sizeof(struct udphdr)); - return 0; + struct udp_opt *up =3D udp_sk(sk); + + if (up->pending) { + up->pending =3D 0; + ip_flush_pending_frames(sk); } - if (csum_partial_copy_fromiovecend(to, ufh->iov, offset-sizeof(struct udp= hdr), - fraglen, &ufh->wcheck)) - return -EFAULT; - return 0; } =20 /* - * Copy a UDP packet from user space into a buffer without checksumming. + * Push out all pending data as one UDP datagram. Socket is locked. */ -=20 -static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset= , unsigned int fraglen)=20 +static int udp_push_pending_frames(struct sock *sk, struct udp_opt *up) { - struct udpfakehdr *ufh =3D (struct udpfakehdr *)p; + struct sk_buff *skb; + struct udphdr *uh; + int err =3D 0; =20 - if (offset=3D=3D0) { - memcpy(to, ufh, sizeof(struct udphdr)); - return memcpy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset, - fraglen-sizeof(struct udphdr)); + /* Grab the skbuff where UDP header space exists. */ + if ((skb =3D skb_peek(&sk->write_queue)) =3D=3D NULL) + goto out; + + /* + * Create a UDP header + */ + uh =3D skb->h.uh; + uh->source =3D up->sport; + uh->dest =3D up->dport; + uh->len =3D htons(up->len); + uh->check =3D 0; + + if (sk->no_check =3D=3D UDP_CSUM_NOXMIT) { + skb->ip_summed =3D CHECKSUM_NONE; + goto send; + } + + if (skb_queue_len(&sk->write_queue) =3D=3D 1) { + /* + * Only one fragment on the socket. + */ + if (skb->ip_summed =3D=3D CHECKSUM_HW) { + skb->csum =3D offsetof(struct udphdr, check); + uh->check =3D ~csum_tcpudp_magic(up->saddr, up->daddr, + up->len, IPPROTO_UDP, 0); + } else { + skb->csum =3D csum_partial((char *)uh, + sizeof(struct udphdr), skb->csum); + uh->check =3D csum_tcpudp_magic(up->saddr, up->daddr, + up->len, IPPROTO_UDP, skb->csum); + if (uh->check =3D=3D 0) + uh->check =3D -1; + } + } else { + unsigned int csum =3D 0; + /* + * HW-checksum won't work as there are two or more=20 + * fragments on the socket so that all csums of sk_buffs + * should be together. + */ + if (skb->ip_summed =3D=3D CHECKSUM_HW) { + int offset =3D (unsigned char *)uh - skb->data; + skb->csum =3D skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed =3D CHECKSUM_NONE; + } else { + skb->csum =3D csum_partial((char *)uh, + sizeof(struct udphdr), skb->csum); + } + + skb_queue_walk(&sk->write_queue, skb) { + csum =3D csum_add(csum, skb->csum); + } + uh->check =3D csum_tcpudp_magic(up->saddr, up->daddr, + up->len, IPPROTO_UDP, csum); + if (uh->check =3D=3D 0) + uh->check =3D -1; } - return memcpy_fromiovecend(to, ufh->iov, offset-sizeof(struct udphdr), - fraglen); +send: + err =3D ip_push_pending_frames(sk); +out: + up->len =3D 0; + up->pending =3D 0; + return err; +} + + +static unsigned short udp_check(struct udphdr *uh, int len, unsigned long = saddr, unsigned long daddr, unsigned long base) +{ + return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); } =20 int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) { - int ulen =3D len + sizeof(struct udphdr); + struct udp_opt *up =3D udp_sk(sk); + int ulen =3D len; struct ipcm_cookie ipc; - struct udpfakehdr ufh; struct rtable *rt =3D NULL; int free =3D 0; int connected =3D 0; - u32 daddr; + u32 daddr, faddr, saddr; + u16 dport; u8 tos; int err; + int corkreq =3D up->corkflag || msg->msg_flags&MSG_MORE; =20 /* This check is ONLY to check for arithmetic overflow on integer(!) len. Not more! Real check will be made - in ip_build_xmit --ANK + in ip_append_* --ANK =20 BTW socket.c -> af_*.c -> ... make multiple invalid conversions size_t -> int. We MUST repair it f.e. @@ -457,10 +501,23 @@ if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; =20 + ipc.opt =3D NULL; + + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) + goto do_append_data; + release_sock(sk); + } + ulen +=3D sizeof(struct udphdr); + /* * Get and verify the address.=20 */ - =20 if (msg->msg_name) { struct sockaddr_in * usin =3D (struct sockaddr_in*)msg->msg_name; if (msg->msg_namelen < sizeof(*usin)) @@ -470,24 +527,22 @@ return -EINVAL; } =20 - ufh.daddr =3D usin->sin_addr.s_addr; - ufh.uh.dest =3D usin->sin_port; - if (ufh.uh.dest =3D=3D 0) + daddr =3D usin->sin_addr.s_addr; + dport =3D usin->sin_port; + if (dport =3D=3D 0) return -EINVAL; } else { if (sk->state !=3D TCP_ESTABLISHED) return -ENOTCONN; - ufh.daddr =3D sk->daddr; - ufh.uh.dest =3D sk->dport; + daddr =3D sk->daddr; + dport =3D sk->dport; /* Open fast path for connected socket. Route will not be used, if at least one option is set. */ connected =3D 1; } ipc.addr =3D sk->saddr; - ufh.uh.source =3D sk->sport; =20 - ipc.opt =3D NULL; ipc.oif =3D sk->bound_dev_if; if (msg->msg_controllen) { err =3D ip_cmsg_send(msg, &ipc); @@ -500,13 +555,13 @@ if (!ipc.opt) ipc.opt =3D sk->protinfo.af_inet.opt; =20 - ufh.saddr =3D ipc.addr; - ipc.addr =3D daddr =3D ufh.daddr; + saddr =3D ipc.addr; + ipc.addr =3D faddr =3D daddr; =20 if (ipc.opt && ipc.opt->srr) { if (!daddr) return -EINVAL; - daddr =3D ipc.opt->faddr; + faddr =3D ipc.opt->faddr; connected =3D 0; } tos =3D RT_TOS(sk->protinfo.af_inet.tos); @@ -519,8 +574,8 @@ if (MULTICAST(daddr)) { if (!ipc.oif) ipc.oif =3D sk->protinfo.af_inet.mc_index; - if (!ufh.saddr) - ufh.saddr =3D sk->protinfo.af_inet.mc_addr; + if (!saddr) + saddr =3D sk->protinfo.af_inet.mc_addr; connected =3D 0; } =20 @@ -528,7 +583,16 @@ rt =3D (struct rtable*)sk_dst_check(sk, 0); =20 if (rt =3D=3D NULL) { - err =3D ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif); + struct flowi fl =3D { .oif =3D ipc.oif, + .nl_u =3D { .ip4_u =3D + { .daddr =3D faddr, + .saddr =3D saddr, + .tos =3D tos } }, + .proto =3D IPPROTO_UDP, + .uli_u =3D { .ports =3D + { .sport =3D sk->sport, + .dport =3D dport } } }; + err =3D ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT= )); if (err) goto out; =20 @@ -543,23 +607,39 @@ goto do_confirm; back_from_confirm: =20 - ufh.saddr =3D rt->rt_src; + saddr =3D rt->rt_src; if (!ipc.addr) - ufh.daddr =3D ipc.addr =3D rt->rt_dst; - ufh.uh.len =3D htons(ulen); - ufh.uh.check =3D 0; - ufh.iov =3D msg->msg_iov; - ufh.wcheck =3D 0; - - /* RFC1122: OK. Provides the checksumming facility (MUST) as per */ - /* 4.1.3.4. It's configurable by the application via setsockopt() */ - /* (MAY) and it defaults to on (MUST). */ - - err =3D ip_build_xmit(sk, - (sk->no_check =3D=3D UDP_CSUM_NOXMIT ? - udp_getfrag_nosum : - udp_getfrag), - &ufh, ulen, &ipc, rt, msg->msg_flags); + daddr =3D ipc.addr =3D rt->rt_dst; + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp cork app bug 2\n"))= ; + err =3D -EINVAL; + goto out; + } + /* + * Now cork the socket to pend data. + */ + up->daddr =3D daddr; + up->dport =3D dport; + up->saddr =3D saddr; + up->sport =3D sk->sport; + up->pending =3D 1; + +do_append_data: + up->len +=3D ulen; + err =3D ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,=20 + sizeof(struct udphdr), &ipc, rt,=20 + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_flush_pending_frames(sk); + else if (!corkreq) + err =3D udp_push_pending_frames(sk, up); + release_sock(sk); =20 out: ip_rt_put(rt); @@ -579,6 +659,52 @@ goto out; } =20 +int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t si= ze, int flags) +{ + struct udp_opt *up =3D udp_sk(sk); + int ret; + + if (!up->pending) { + struct msghdr msg =3D { .msg_flags =3D flags|MSG_MORE }; + + /* Call udp_sendmsg to specify destination address which + * sendpage interface can't pass. + * This will succeed only when the socket is connected. + */ + ret =3D udp_sendmsg(sk, &msg, 0); + if (ret < 0) + return ret; + } + + lock_sock(sk); + + if (unlikely(!up->pending)) { + release_sock(sk); + + NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp cork app bug 3\n"))= ; + return -EINVAL; + } + + ret =3D ip_append_page(sk, page, offset, size, flags); + if (ret =3D=3D -EOPNOTSUPP) { + release_sock(sk); + return sock_no_sendpage(sk->socket, page, offset, size, flags); + } + if (ret < 0) { + udp_flush_pending_frames(sk); + goto out; + } + + up->len +=3D size; + if (!(up->corkflag || (flags&MSG_MORE))) + ret =3D udp_push_pending_frames(sk, up); + if (!ret) + ret =3D size; +out: + release_sock(sk); + return ret; +} + /* * IOCTL requests applicable to the UDP protocol */ @@ -745,7 +871,9 @@ saddr =3D sk->protinfo.af_inet.mc_addr; } err =3D ip_route_connect(&rt, usin->sin_addr.s_addr, saddr, - RT_CONN_FLAGS(sk), oif); + RT_CONN_FLAGS(sk), oif, + IPPROTO_UDP, + sk->sport, usin->sin_port, sk); if (err) return err; if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) { @@ -796,11 +924,124 @@ inet_sock_release(sk); } =20 +/* return: + * 1 if the the UDP system should process it + * 0 if we should drop this packet + * -1 if it should get processed by xfrm4_rcv_encap + */ +static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) +{ + struct udp_opt *up =3D udp_sk(sk); + struct udphdr *uh =3D skb->h.uh; + struct iphdr *iph; + int iphlen, len; + =20 + __u8 *udpdata =3D (__u8 *)uh + sizeof(struct udphdr); + __u32 *udpdata32 =3D (__u32 *)udpdata; + __u16 encap_type =3D up->encap_type; + + /* if we're overly short, let UDP handle it */ + if (udpdata > skb->tail) + return 1; + + /* if this is not encapsulated socket, then just return now */ + if (!encap_type) + return 1; + + len =3D skb->tail - udpdata; + + switch (encap_type) { + case UDP_ENCAP_ESPINUDP: + /* Check if this is a keepalive packet. If so, eat it. */ + if (len =3D=3D 1 && udpdata[0] =3D=3D 0xff) { + return 0; + } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] !=3D 0 ) { + /* ESP Packet without Non-ESP header */ + len =3D sizeof(struct udphdr); + } else + /* Must be an IKE packet.. pass it through */ + return 1; + + /* At this point we are sure that this is an ESPinUDP packet, + * so we need to remove 'len' bytes from the packet (the UDP + * header and optional ESP marker bytes) and then modify the + * protocol to ESP, and then call into the transform receiver. + */ + + /* Now we can update and verify the packet length... */ + iph =3D skb->nh.iph; + iphlen =3D iph->ihl << 2; + iph->tot_len =3D htons(ntohs(iph->tot_len) - len); + if (skb->len < iphlen + len) { + /* packet is too small!?! */ + return 0; + } + + /* pull the data buffer up to the ESP header and set the + * transport header to point to ESP. Keep UDP on the stack + * for later. + */ + skb->h.raw =3D skb_pull(skb, len); + + /* modify the protocol (it's ESP!) */ + iph->protocol =3D IPPROTO_ESP; + + /* and let the caller know to send this into the ESP processor... */ + return -1; + + default: + printk(KERN_INFO "udp_encap_rcv(): Unhandled UDP encap type: %u\n", + encap_type); + return 1; + } +} + +/* returns: + * -1: error + * 0: success + * >0: "udp encap" protocol resubmission + * + * Note that in the success and error cases, the skb is assumed to + * have either been requeued or freed. + */ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) { + struct udp_opt *up =3D udp_sk(sk); + /* * Charge it to the socket, dropping if the queue is full. */ + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + return -1; + } + + if (up->encap_type) { + /* + * This is an encapsulation socket, so let's see if this is + * an encapsulated packet. + * If it's a keepalive packet, then just eat it. + * If it's an encapsulateed packet, then pass it to the + * IPsec xfrm input and return the response + * appropriately. Otherwise, just fall through and + * pass this up the UDP socket. + */ + int ret; + + ret =3D udp_encap_rcv(sk, skb); + if (ret =3D=3D 0) { + /* Eat the packet .. */ + kfree_skb(skb); + return 0; + } + if (ret < 0) { + /* process the ESP packet */ + ret =3D xfrm4_rcv_encap(skb, up->encap_type); + UDP_INC_STATS_BH(UdpInDatagrams); + return -ret; + } + /* FALLTHROUGH -- it's a UDP Packet */ + } =20 #if defined(CONFIG_FILTER) if (sk->filter && skb->ip_summed !=3D CHECKSUM_UNNECESSARY) { @@ -853,8 +1094,13 @@ if(sknext) skb1 =3D skb_clone(skb, GFP_ATOMIC); =20 - if(skb1) - udp_queue_rcv_skb(sk, skb1); + if(skb1) { + int ret =3D udp_queue_rcv_skb(sk, skb1); + if (ret > 0) + /* we should probably re-process instead + * of dropping packets here. */ + kfree_skb(skb1); + } sk =3D sknext; } while(sknext); } else @@ -929,11 +1175,20 @@ sk =3D udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifinde= x); =20 if (sk !=3D NULL) { - udp_queue_rcv_skb(sk, skb); + int ret =3D udp_queue_rcv_skb(sk, skb); sock_put(sk); + + /* a return value > 0 means to resubmit the input, but + * it it wants the return to be -protocol, or 0 + */ + if (ret > 0) + return -ret; return 0; } =20 + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto drop; + /* No socket. Drop packet silently, if checksum is wrong */ if (udp_checksum_complete(skb)) goto csum_error; @@ -974,6 +1229,7 @@ NIPQUAD(daddr), ntohs(uh->dest), ulen)); +drop: UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); @@ -1038,16 +1294,107 @@ return len; } =20 +static int udp_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_flush_pending_frames(sk); + release_sock(sk); + return 0; +} + +/* + * Socket option code for UDP + */ +static int udp_setsockopt(struct sock *sk, int level, int optname,=20 + char *optval, int optlen) +{ + struct udp_opt *up =3D udp_sk(sk); + int val; + int err =3D 0; + + if (level !=3D SOL_UDP) + return ip_setsockopt(sk, level, optname, optval, optlen); + + if(optlencorkflag =3D 1; + } else { + up->corkflag =3D 0; + lock_sock(sk); + udp_push_pending_frames(sk, up); + release_sock(sk); + } + break; + =09 + case UDP_ENCAP: + up->encap_type =3D val; + break; + + default: + err =3D -ENOPROTOOPT; + break; + }; + + return err; +} + +static int udp_getsockopt(struct sock *sk, int level, int optname,=20 + char *optval, int *optlen) +{ + struct udp_opt *up =3D udp_sk(sk); + int val, len; + + if (level !=3D SOL_UDP) + return ip_getsockopt(sk, level, optname, optval, optlen); + + if(get_user(len,optlen)) + return -EFAULT; + + len =3D min_t(unsigned int, len, sizeof(int)); +=09 + if(len < 0) + return -EINVAL; + + switch(optname) { + case UDP_CORK: + val =3D up->corkflag; + break; + + case UDP_ENCAP: + val =3D up->encap_type; + break; + + default: + return -ENOPROTOOPT; + }; + + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval, &val,len)) + return -EFAULT; + return 0; +} + + struct proto udp_prot =3D { name: "UDP", close: udp_close, connect: udp_connect, disconnect: udp_disconnect, ioctl: udp_ioctl, - setsockopt: ip_setsockopt, - getsockopt: ip_getsockopt, + destroy: udp_destroy_sock, + setsockopt: udp_setsockopt, + getsockopt: udp_getsockopt, sendmsg: udp_sendmsg, recvmsg: udp_recvmsg, + sendpage: udp_sendpage, backlog_rcv: udp_queue_rcv_skb, hash: udp_v4_hash, unhash: udp_v4_unhash, diff -Nru a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/xfrm4_input.c Thu May 8 10:41:38 2003 @@ -0,0 +1,144 @@ +/* + * xfrm4_input.c + * + * Changes: + * YOSHIFUJI Hideaki @USAGI + * Split up af-specific portion + * Derek Atkins + * Add Encapsulation support + * =09 + */ + +#include +#include + +static kmem_cache_t *secpath_cachep; + +int xfrm4_rcv(struct sk_buff *skb) +{ + return xfrm4_rcv_encap(skb, 0); +} + +int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) +{ + int err; + u32 spi, seq; + struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH]; + struct xfrm_state *x; + int xfrm_nr =3D 0; + int decaps =3D 0; + + if ((err =3D xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) !=3D= 0) + goto drop; + + do { + struct iphdr *iph =3D skb->nh.iph; + + if (xfrm_nr =3D=3D XFRM_MAX_DEPTH) + goto drop; + + x =3D xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protoco= l, AF_INET); + if (x =3D=3D NULL) + goto drop; + + spin_lock(&x->lock); + if (unlikely(x->km.state !=3D XFRM_STATE_VALID)) + goto drop_unlock; + + if (x->props.replay_window && xfrm_replay_check(x, seq)) + goto drop_unlock; + + if (xfrm_state_check_expire(x)) + goto drop_unlock; + + xfrm_vec[xfrm_nr].decap.decap_type =3D encap_type; + if (x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb)) + goto drop_unlock; + + /* only the first xfrm gets the encap type */ + encap_type =3D 0; + + if (x->props.replay_window) + xfrm_replay_advance(x, seq); + + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + + spin_unlock(&x->lock); + + xfrm_vec[xfrm_nr++].xvec =3D x; + + iph =3D skb->nh.iph; + + if (x->props.mode) { + if (iph->protocol !=3D IPPROTO_IPIP) + goto drop; + skb->nh.raw =3D skb->data; + iph =3D skb->nh.iph; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + decaps =3D 1; + break; + } + + if ((err =3D xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0= ) + goto drop; + } while (!err); + + /* Allocate new secpath or COW existing one. */ + + if (!skb->sp || atomic_read(&skb->sp->refcnt) !=3D 1) { + kmem_cache_t *pool =3D skb->sp ? skb->sp->pool : secpath_cachep; + struct sec_path *sp; + sp =3D kmem_cache_alloc(pool, SLAB_ATOMIC); + if (!sp) + goto drop; + if (skb->sp) { + memcpy(sp, skb->sp, sizeof(struct sec_path)); + secpath_put(skb->sp); + } else { + sp->pool =3D pool; + sp->len =3D 0; + } + atomic_set(&sp->refcnt, 1); + skb->sp =3D sp; + } + if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) + goto drop; + + memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap= _state)); + skb->sp->len +=3D xfrm_nr; + + if (decaps) { + if (!(skb->dev->flags&IFF_LOOPBACK)) { + dst_release(skb->dst); + skb->dst =3D NULL; + } + netif_rx(skb); + return 0; + } else { + return -skb->nh.iph->protocol; + } + +drop_unlock: + spin_unlock(&x->lock); + xfrm_state_put(x); +drop: + while (--xfrm_nr >=3D 0) + xfrm_state_put(xfrm_vec[xfrm_nr].xvec); + + kfree_skb(skb); + return 0; +} + + +void __init xfrm4_input_init(void) +{ + secpath_cachep =3D kmem_cache_create("secpath4_cache", + sizeof(struct sec_path), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + + if (!secpath_cachep) + panic("IP: failed to allocate secpath4_cache\n"); +} + diff -Nru a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/xfrm4_policy.c Thu May 8 10:41:38 2003 @@ -0,0 +1,284 @@ +/*=20 + * xfrm4_policy.c + * + * Changes: + * Kazunori MIYAZAWA @USAGI + * YOSHIFUJI Hideaki @USAGI + * Split up af-specific portion + * =09 + */ + +#include +#include +#include + +extern struct dst_ops xfrm4_dst_ops; +extern struct xfrm_policy_afinfo xfrm4_policy_afinfo; + +static struct xfrm_type_map xfrm4_type_map =3D { .lock =3D RW_LOCK_UNLOCKE= D }; + +static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) +{ + return __ip_route_output_key((struct rtable**)dst, fl); +} + +/* Check that the bundle accepts the flow and its components are + * still valid. + */ + +static int __xfrm4_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl) +{ + do { + if (xdst->u.dst.ops !=3D &xfrm4_dst_ops) + return 1; + + if (!xfrm_selector_match(&xdst->u.dst.xfrm->sel, fl, AF_INET)) + return 0; + if (xdst->u.dst.xfrm->km.state !=3D XFRM_STATE_VALID || + xdst->u.dst.path->obsolete > 0) + return 0; + xdst =3D (struct xfrm_dst*)xdst->u.dst.child; + } while (xdst); + return 0; +} + +static struct dst_entry * +__xfrm4_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_polic= y *policy) +{ + struct dst_entry *dst; + + if (!fl->fl4_src) + fl->fl4_src =3D rt->rt_src; + if (!fl->fl4_dst) + fl->fl4_dst =3D rt->rt_dst; + read_lock_bh(&policy->lock); + for (dst =3D policy->bundles; dst; dst =3D dst->next) { + struct xfrm_dst *xdst =3D (struct xfrm_dst*)dst; + if (xdst->u.rt.fl.oif =3D=3D fl->oif && /*XXX*/ + xdst->u.rt.fl.fl4_dst =3D=3D fl->fl4_dst && + xdst->u.rt.fl.fl4_src =3D=3D fl->fl4_src && + __xfrm4_bundle_ok(xdst, fl)) { + dst_clone(dst); + break; + } + } + read_unlock_bh(&policy->lock); + return dst; +} + +/* Allocate chain of dst_entry's, attach known xfrm's, calculate + * all the metrics... Shortly, bundle a bundle. + */ + +static int +__xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm= , int nx, + struct flowi *fl, struct dst_entry **dst_p) +{ + struct dst_entry *dst, *dst_prev; + struct rtable *rt0 =3D (struct rtable*)(*dst_p); + struct rtable *rt =3D rt0; + u32 remote =3D fl->fl4_dst; + u32 local =3D fl->fl4_src; + int i; + int err; + int header_len =3D 0; + int trailer_len =3D 0; + + dst =3D dst_prev =3D NULL; + + for (i =3D 0; i < nx; i++) { + struct dst_entry *dst1 =3D dst_alloc(&xfrm4_dst_ops); + + if (unlikely(dst1 =3D=3D NULL)) { + err =3D -ENOBUFS; + goto error; + } + + dst1->xfrm =3D xfrm[i]; + if (!dst) + dst =3D dst1; + else { + dst_prev->child =3D dst1; + dst1->flags |=3D DST_NOHASH; + dst_clone(dst1); + } + dst_prev =3D dst1; + if (xfrm[i]->props.mode) { + remote =3D xfrm[i]->id.daddr.a4; + local =3D xfrm[i]->props.saddr.a4; + } + header_len +=3D xfrm[i]->props.header_len; + trailer_len +=3D xfrm[i]->props.trailer_len; + } + + if (remote !=3D fl->fl4_dst) { + struct flowi fl_tunnel =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D remote, + .saddr =3D local } + } + }; + err =3D xfrm_dst_lookup((struct xfrm_dst**)&rt, &fl_tunnel, AF_INET); + if (err) + goto error; + } else { + dst_hold(&rt->u.dst); + } + dst_prev->child =3D &rt->u.dst; + for (dst_prev =3D dst; dst_prev !=3D &rt->u.dst; dst_prev =3D dst_prev->c= hild) { + struct xfrm_dst *x =3D (struct xfrm_dst*)dst_prev; + x->u.rt.fl =3D *fl; + + dst_prev->dev =3D rt->u.dst.dev; + if (rt->u.dst.dev) + dev_hold(rt->u.dst.dev); + dst_prev->obsolete =3D -1; + dst_prev->flags |=3D DST_HOST; + dst_prev->lastuse =3D jiffies; + dst_prev->header_len =3D header_len; + dst_prev->trailer_len =3D trailer_len; + memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics)= ); + dst_prev->path =3D &rt->u.dst; + + /* Copy neighbout for reachability confirmation */ + dst_prev->neighbour =3D neigh_clone(rt->u.dst.neighbour); + dst_prev->input =3D rt->u.dst.input; + dst_prev->output =3D dst_prev->xfrm->type->output; + if (rt->peer) + atomic_inc(&rt->peer->refcnt); + x->u.rt.peer =3D rt->peer; + /* Sheit... I remember I did this right. Apparently, + * it was magically lost, so this code needs audit */ + x->u.rt.rt_flags =3D rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_L= OCAL); + x->u.rt.rt_type =3D rt->rt_type; + x->u.rt.rt_src =3D rt0->rt_src; + x->u.rt.rt_dst =3D rt0->rt_dst; + x->u.rt.rt_gateway =3D rt->rt_gateway; + x->u.rt.rt_spec_dst =3D rt0->rt_spec_dst; + header_len -=3D x->u.dst.xfrm->props.header_len; + trailer_len -=3D x->u.dst.xfrm->props.trailer_len; + } + *dst_p =3D dst; + return 0; + +error: + if (dst) + dst_free(dst); + return err; +} + +static void +_decode_session4(struct sk_buff *skb, struct flowi *fl) +{ + struct iphdr *iph =3D skb->nh.iph; + u8 *xprth =3D skb->nh.raw + iph->ihl*4; + + if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { + switch (iph->protocol) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + if (pskb_may_pull(skb, xprth + 4 - skb->data)) { + u16 *ports =3D (u16 *)xprth; + + fl->fl_ip_sport =3D ports[0]; + fl->fl_ip_dport =3D ports[1]; + } + break; + + case IPPROTO_ESP: + if (pskb_may_pull(skb, xprth + 4 - skb->data)) { + u32 *ehdr =3D (u32 *)xprth; + + fl->fl_ipsec_spi =3D ehdr[0]; + } + break; + + case IPPROTO_AH: + if (pskb_may_pull(skb, xprth + 8 - skb->data)) { + u32 *ah_hdr =3D (u32*)xprth; + + fl->fl_ipsec_spi =3D ah_hdr[1]; + } + break; + + case IPPROTO_COMP: + if (pskb_may_pull(skb, xprth + 4 - skb->data)) { + u16 *ipcomp_hdr =3D (u16 *)xprth; + + fl->fl_ipsec_spi =3D ntohl(ntohs(ipcomp_hdr[1])); + } + break; + default: + fl->fl_ipsec_spi =3D 0; + break; + }; + } else { + memset(fl, 0, sizeof(struct flowi)); + } + fl->proto =3D iph->protocol; + fl->fl4_dst =3D iph->daddr; + fl->fl4_src =3D iph->saddr; +} + +static inline int xfrm4_garbage_collect(void) +{ + read_lock(&xfrm4_policy_afinfo.lock); + xfrm4_policy_afinfo.garbage_collect(); + read_unlock(&xfrm4_policy_afinfo.lock); + return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2); +} + +static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) +{ + struct dst_entry *path =3D dst->path; + + if (mtu < 68 + dst->header_len) + return; + + path->ops->update_pmtu(path, mtu); +} + +struct dst_ops xfrm4_dst_ops =3D { + .family =3D AF_INET, + .protocol =3D __constant_htons(ETH_P_IP), + .gc =3D xfrm4_garbage_collect, + .update_pmtu =3D xfrm4_update_pmtu, + .gc_thresh =3D 1024, + .entry_size =3D sizeof(struct xfrm_dst), +}; + +struct xfrm_policy_afinfo xfrm4_policy_afinfo =3D { + .family =3D AF_INET, + .lock =3D RW_LOCK_UNLOCKED, + .type_map =3D &xfrm4_type_map, + .dst_ops =3D &xfrm4_dst_ops, + .dst_lookup =3D xfrm4_dst_lookup, + .find_bundle =3D __xfrm4_find_bundle, + .bundle_create =3D __xfrm4_bundle_create, + .decode_session =3D _decode_session4, +}; + +void __init xfrm4_policy_init(void) +{ + xfrm_policy_register_afinfo(&xfrm4_policy_afinfo); +} + +void __exit xfrm4_policy_fini(void) +{ + xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); +} + +void __init xfrm4_init(void) +{ + xfrm4_state_init(); + xfrm4_policy_init(); + xfrm4_input_init(); +} + +void __exit xfrm4_fini(void) +{ + //xfrm4_input_fini(); + xfrm4_policy_fini(); + xfrm4_state_fini(); +} + diff -Nru a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/xfrm4_state.c Thu May 8 10:41:38 2003 @@ -0,0 +1,128 @@ +/* + * xfrm4_state.c + * + * Changes: + * YOSHIFUJI Hideaki @USAGI + * Split up af-specific portion + * + */ + +#include +#include +#include + +extern struct xfrm_state_afinfo xfrm4_state_afinfo; + +static void +__xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, + struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + x->sel.daddr.a4 =3D fl->fl4_dst; + x->sel.saddr.a4 =3D fl->fl4_src; + x->sel.dport =3D fl->fl_ip_dport; + x->sel.dport_mask =3D ~0; + x->sel.sport =3D fl->fl_ip_sport; + x->sel.sport_mask =3D ~0; + x->sel.prefixlen_d =3D 32; + x->sel.prefixlen_s =3D 32; + x->sel.proto =3D fl->proto; + x->sel.ifindex =3D fl->oif; + x->id =3D tmpl->id; + if (x->id.daddr.a4 =3D=3D 0) + x->id.daddr.a4 =3D daddr->a4; + x->props.saddr =3D tmpl->saddr; + if (x->props.saddr.a4 =3D=3D 0) + x->props.saddr.a4 =3D saddr->a4; + x->props.mode =3D tmpl->mode; + x->props.reqid =3D tmpl->reqid; + x->props.family =3D AF_INET; +} + +static struct xfrm_state * +__xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) +{ + unsigned h =3D __xfrm4_spi_hash(daddr, spi, proto); + struct xfrm_state *x; + + list_for_each_entry(x, xfrm4_state_afinfo.state_byspi+h, byspi) { + if (x->props.family =3D=3D AF_INET && + spi =3D=3D x->id.spi && + daddr->a4 =3D=3D x->id.daddr.a4 && + proto =3D=3D x->id.proto) { + atomic_inc(&x->refcnt); + return x; + } + } + return NULL; +} + +static struct xfrm_state * +__xfrm4_find_acq(u8 mode, u16 reqid, u8 proto,=20 + xfrm_address_t *daddr, xfrm_address_t *saddr,=20 + int create) +{ + struct xfrm_state *x, *x0; + unsigned h =3D __xfrm4_dst_hash(daddr); + + x0 =3D NULL; + + list_for_each_entry(x, xfrm4_state_afinfo.state_bydst+h, bydst) { + if (x->props.family =3D=3D AF_INET && + daddr->a4 =3D=3D x->id.daddr.a4 && + mode =3D=3D x->props.mode && + proto =3D=3D x->id.proto && + saddr->a4 =3D=3D x->props.saddr.a4 && + reqid =3D=3D x->props.reqid && + x->km.state =3D=3D XFRM_STATE_ACQ) { + if (!x0) + x0 =3D x; + if (x->id.spi) + continue; + x0 =3D x; + break; + } + } + if (x0) { + atomic_inc(&x0->refcnt); + } else if (create && (x0 =3D xfrm_state_alloc()) !=3D NULL) { + x0->sel.daddr.a4 =3D daddr->a4; + x0->sel.saddr.a4 =3D saddr->a4; + x0->sel.prefixlen_d =3D 32; + x0->sel.prefixlen_s =3D 32; + x0->props.saddr.a4 =3D saddr->a4; + x0->km.state =3D XFRM_STATE_ACQ; + x0->id.daddr.a4 =3D daddr->a4; + x0->id.proto =3D proto; + x0->props.family =3D AF_INET; + x0->props.mode =3D mode; + x0->props.reqid =3D reqid; + x0->props.family =3D AF_INET; + x0->lft.hard_add_expires_seconds =3D XFRM_ACQ_EXPIRES; + atomic_inc(&x0->refcnt); + mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ); + atomic_inc(&x0->refcnt); + list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); + wake_up(&km_waitq); + } + return x0; +} + +static struct xfrm_state_afinfo xfrm4_state_afinfo =3D { + .family =3D AF_INET, + .lock =3D RW_LOCK_UNLOCKED, + .init_tempsel =3D __xfrm4_init_tempsel, + .state_lookup =3D __xfrm4_state_lookup, + .find_acq =3D __xfrm4_find_acq, +}; + +void __init xfrm4_state_init(void) +{ + xfrm_state_register_afinfo(&xfrm4_state_afinfo); +} + +void __exit xfrm4_state_fini(void) +{ + xfrm_state_unregister_afinfo(&xfrm4_state_afinfo); +} + diff -Nru a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/xfrm4_tunnel.c Thu May 8 10:41:38 2003 @@ -0,0 +1,264 @@ +/* xfrm4_tunnel.c: Generic IP tunnel transformer. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include + +int xfrm4_tunnel_check_size(struct sk_buff *skb) +{ + int mtu, ret =3D 0; + struct dst_entry *dst; + struct iphdr *iph =3D skb->nh.iph; + + if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) + goto out; + + IPCB(skb)->flags |=3D IPSKB_XFRM_TUNNEL_SIZE; +=09 + if (!(iph->frag_off & htons(IP_DF))) + goto out; + + dst =3D skb->dst; + mtu =3D dst_pmtu(dst) - dst->header_len - dst->trailer_len; + if (skb->len > mtu) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); + ret =3D -EMSGSIZE; + } +out: + return ret; +} + +static int ipip_output(struct sk_buff *skb) +{ + struct dst_entry *dst =3D skb->dst; + struct xfrm_state *x =3D dst->xfrm; + struct iphdr *iph, *top_iph; + int tos, err; + + if ((err =3D xfrm4_tunnel_check_size(skb)) !=3D 0) + goto error_nolock; + =09 + iph =3D skb->nh.iph; + + spin_lock_bh(&x->lock); + + tos =3D iph->tos; + + top_iph =3D (struct iphdr *) skb_push(skb, x->props.header_len); + top_iph->ihl =3D 5; + top_iph->version =3D 4; + top_iph->tos =3D INET_ECN_encapsulate(tos, iph->tos); + top_iph->tot_len =3D htons(skb->len); + top_iph->frag_off =3D iph->frag_off & ~htons(IP_MF|IP_OFFSET); + if (!(iph->frag_off & htons(IP_DF))) { +#ifdef NETIF_F_TSO + __ip_select_ident(top_iph, dst, 0); +#else + __ip_select_ident(top_iph, dst); +#endif + } + top_iph->ttl =3D iph->ttl; + top_iph->protocol =3D IPPROTO_IPIP; + top_iph->check =3D 0; + top_iph->saddr =3D x->props.saddr.a4; + top_iph->daddr =3D x->id.daddr.a4; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + ip_send_check(top_iph); + + skb->nh.raw =3D skb->data; + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + + spin_unlock_bh(&x->lock); + + if ((skb->dst =3D dst_pop(dst)) =3D=3D NULL) { + kfree_skb(skb); + err =3D -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error_nolock: + kfree_skb(skb); + return err; +} + +static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk= _buff *skb) +{ + struct iphdr *inner_iph =3D skb->nh.iph; + + if (INET_ECN_is_ce(outer_iph->tos) && + INET_ECN_is_not_ce(inner_iph->tos)) + IP_ECN_set_ce(inner_iph); +} + +static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *de= cap, struct sk_buff *skb) +{ + struct iphdr *outer_iph =3D skb->nh.iph; + + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + return -EINVAL; + skb->mac.raw =3D skb->nh.raw; + skb->nh.raw =3D skb->data; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + dst_release(skb->dst); + skb->dst =3D NULL; + skb->protocol =3D htons(ETH_P_IP); + skb->pkt_type =3D PACKET_HOST; + ipip_ecn_decapsulate(outer_iph, skb); + netif_rx(skb); + + return 0; +} + +static struct xfrm_tunnel *ipip_handler; +static DECLARE_MUTEX(xfrm4_tunnel_sem); + +int xfrm4_tunnel_register(struct xfrm_tunnel *handler) +{ + int ret; + + down(&xfrm4_tunnel_sem); + ret =3D 0; + if (ipip_handler !=3D NULL) + ret =3D -EINVAL; + if (!ret) + ipip_handler =3D handler; + up(&xfrm4_tunnel_sem); + + return ret; +} + +int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) +{ + int ret; + + down(&xfrm4_tunnel_sem); + ret =3D 0; + if (ipip_handler !=3D handler) + ret =3D -EINVAL; + if (!ret) + ipip_handler =3D NULL; + up(&xfrm4_tunnel_sem); + + synchronize_net(); + + return ret; +} + +static int ipip_rcv(struct sk_buff *skb) +{ + struct xfrm_tunnel *handler =3D ipip_handler; + struct xfrm_state *x =3D NULL; + int err; + + /* Tunnel devices take precedence. */ + if (handler) { + err =3D handler->handler(skb); + if (!err) + goto out; + } + + x =3D xfrm_state_lookup((xfrm_address_t *)&skb->nh.iph->daddr, + skb->nh.iph->saddr, + IPPROTO_IPIP, AF_INET); + + if (x) { + spin_lock(&x->lock); + + if (unlikely(x->km.state !=3D XFRM_STATE_VALID)) + goto drop_unlock; + } + + err =3D ipip_xfrm_rcv(x, NULL, skb); + if (err) + goto drop_unlock; + + if (x) { + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + + spin_unlock(&x->lock); + + xfrm_state_put(x); + } + + return 0; + +drop_unlock: + if (x) { + spin_unlock(&x->lock); + xfrm_state_put(x); + } + kfree_skb(skb); +out: + return 0; +} + +static void ipip_err(struct sk_buff *skb, u32 info) +{ + struct xfrm_tunnel *handler =3D ipip_handler; + u32 arg =3D info; + + if (handler) + handler->err_handler(skb, &arg); +} + +static int ipip_init_state(struct xfrm_state *x, void *args) +{ + if (!x->props.mode) + return -EINVAL; + x->props.header_len =3D sizeof(struct iphdr); + + return 0; +} + +static void ipip_destroy(struct xfrm_state *x) +{ +} + +static struct xfrm_type ipip_type =3D { + .description =3D "IPIP", + .proto =3D IPPROTO_IPIP, + .init_state =3D ipip_init_state, + .destructor =3D ipip_destroy, + .input =3D ipip_xfrm_rcv, + .output =3D ipip_output +}; + +static struct inet_protocol ipip_protocol =3D { + .handler =3D ipip_rcv, + .err_handler =3D ipip_err, +}; + +static int __init ipip_init(void) +{ + SET_MODULE_OWNER(&ipip_type); + if (xfrm_register_type(&ipip_type, AF_INET) < 0) { + printk(KERN_INFO "ipip init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) { + printk(KERN_INFO "ipip init: can't add protocol\n"); + xfrm_unregister_type(&ipip_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit ipip_fini(void) +{ + if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) + printk(KERN_INFO "ipip close: can't remove protocol\n"); + if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) + printk(KERN_INFO "ipip close: can't remove xfrm type\n"); +} + +module_init(ipip_init); +module_exit(ipip_fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/ipv6/Config.in b/net/ipv6/Config.in --- a/net/ipv6/Config.in Thu May 8 10:41:37 2003 +++ b/net/ipv6/Config.in Thu May 8 10:41:37 2003 @@ -2,9 +2,9 @@ # IPv6 configuration #=20 =20 -#bool ' IPv6: flow policy support' CONFIG_RT6_POLICY -#bool ' IPv6: firewall support' CONFIG_IPV6_FIREWALL - if [ "$CONFIG_NETFILTER" !=3D "n" ]; then source net/ipv6/netfilter/Config.in fi + +tristate 'IPv6: AH transformation' CONFIG_INET6_AH +tristate 'IPv6: ESP transformation' CONFIG_INET6_ESP diff -Nru a/net/ipv6/Makefile b/net/ipv6/Makefile --- a/net/ipv6/Makefile Thu May 8 10:41:37 2003 +++ b/net/ipv6/Makefile Thu May 8 10:41:37 2003 @@ -9,14 +9,18 @@ =20 O_TARGET :=3D ipv6.o =20 +export-objs :=3D ipv6_syms.o + obj-y :=3D af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o = \ route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \ protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ - ip6_flowlabel.o + ip6_flowlabel.o xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ + ipv6_syms.o =20 -obj-m :=3D $(O_TARGET) +obj-$(CONFIG_INET6_AH) +=3D ah6.o +obj-$(CONFIG_INET6_ESP) +=3D esp6.o =20 -#obj-$(CONFIG_IPV6_FIREWALL) +=3D ip6_fw.o +obj-m :=3D $(O_TARGET) =20 include $(TOPDIR)/Rules.make diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c --- a/net/ipv6/af_inet6.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/af_inet6.c Thu May 8 10:41:36 2003 @@ -672,6 +672,12 @@ addrconf_init(); sit_init(); =20 + /* Init v6 extention headers. */ + ipv6_rthdr_init(); + ipv6_frag_init(); + ipv6_nodata_init(); + ipv6_destopt_init(); + /* Init v6 transport protocols. */ udpv6_init(); tcpv6_init(); diff -Nru a/net/ipv6/ah6.c b/net/ipv6/ah6.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv6/ah6.c Thu May 8 10:41:38 2003 @@ -0,0 +1,364 @@ +/* + * Copyright (C)2002 USAGI/WIDE Project + *=20 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *=20 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *=20 + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U= SA + * + * Authors + * + * Mitsuru KANDA @USAGI : IPv6 Support=20 + * Kazunori MIYAZAWA @USAGI : + * Kunihiro Ishiguro : + * =09 + * This file is derived from net/ipv4/ah.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* XXX no ipv6 ah specific */ +#define NIP6(addr) \ + ntohs((addr).s6_addr16[0]),\ + ntohs((addr).s6_addr16[1]),\ + ntohs((addr).s6_addr16[2]),\ + ntohs((addr).s6_addr16[3]),\ + ntohs((addr).s6_addr16[4]),\ + ntohs((addr).s6_addr16[5]),\ + ntohs((addr).s6_addr16[6]),\ + ntohs((addr).s6_addr16[7]) + +int ah6_output(struct sk_buff *skb) +{ + int err; + int hdr_len =3D sizeof(struct ipv6hdr); + struct dst_entry *dst =3D skb->dst; + struct xfrm_state *x =3D dst->xfrm; + struct ipv6hdr *iph =3D NULL; + struct ip_auth_hdr *ah; + struct ah_data *ahp; + u16 nh_offset =3D 0; + u8 nexthdr; + + if (skb->ip_summed =3D=3D CHECKSUM_HW && skb_checksum_help(skb) =3D=3D NU= LL) { + err =3D -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err =3D xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + + if (x->props.mode) { + iph =3D skb->nh.ipv6h; + skb->nh.ipv6h =3D (struct ipv6hdr*)skb_push(skb, x->props.header_len); + skb->nh.ipv6h->version =3D 6; + skb->nh.ipv6h->payload_len =3D htons(skb->len - sizeof(struct ipv6hdr)); + skb->nh.ipv6h->nexthdr =3D IPPROTO_AH; + memcpy(&skb->nh.ipv6h->saddr, &x->props.saddr, sizeof(struct in6_addr)); + memcpy(&skb->nh.ipv6h->daddr, &x->id.daddr, sizeof(struct in6_addr)); + ah =3D (struct ip_auth_hdr*)(skb->nh.ipv6h+1); + ah->nexthdr =3D IPPROTO_IPV6; + } else { + hdr_len =3D skb->h.raw - skb->nh.raw; + iph =3D kmalloc(hdr_len, GFP_ATOMIC); + if (!iph) { + err =3D -ENOMEM; + goto error; + } + memcpy(iph, skb->data, hdr_len); + skb->nh.ipv6h =3D (struct ipv6hdr*)skb_push(skb, x->props.header_len); + memcpy(skb->nh.ipv6h, iph, hdr_len); + nexthdr =3D xfrm6_clear_mutable_options(skb, &nh_offset, XFRM_POLICY_OUT= ); + if (nexthdr =3D=3D 0) + goto error; + + skb->nh.raw[nh_offset] =3D IPPROTO_AH; + skb->nh.ipv6h->payload_len =3D htons(skb->len - sizeof(struct ipv6hdr)); + ah =3D (struct ip_auth_hdr*)(skb->nh.raw+hdr_len); + skb->h.raw =3D (unsigned char*) ah; + ah->nexthdr =3D nexthdr; + } + + skb->nh.ipv6h->priority =3D 0; + skb->nh.ipv6h->flow_lbl[0] =3D 0; + skb->nh.ipv6h->flow_lbl[1] =3D 0; + skb->nh.ipv6h->flow_lbl[2] =3D 0; + skb->nh.ipv6h->hop_limit =3D 0; + + ahp =3D x->data; + ah->hdrlen =3D (XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) +=20 + ahp->icv_trunc_len) >> 2) - 2; + + ah->reserved =3D 0; + ah->spi =3D x->id.spi; + ah->seq_no =3D htonl(++x->replay.oseq); + ahp->icv(ahp, skb, ah->auth_data); + + if (x->props.mode) { + skb->nh.ipv6h->hop_limit =3D iph->hop_limit; + skb->nh.ipv6h->priority =3D iph->priority; =09 + skb->nh.ipv6h->flow_lbl[0] =3D iph->flow_lbl[0]; + skb->nh.ipv6h->flow_lbl[1] =3D iph->flow_lbl[1]; + skb->nh.ipv6h->flow_lbl[2] =3D iph->flow_lbl[2]; + } else { + memcpy(skb->nh.ipv6h, iph, hdr_len); + skb->nh.raw[nh_offset] =3D IPPROTO_AH; + skb->nh.ipv6h->payload_len =3D htons(skb->len - sizeof(struct ipv6hdr)); + kfree (iph); + } + + skb->nh.raw =3D skb->data; + + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst =3D dst_pop(dst)) =3D=3D NULL) { + err =3D -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + return err; +} + +int ah6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct= sk_buff *skb) +{ + int ah_hlen; + struct ipv6hdr *iph; + struct ipv6_auth_hdr *ah; + struct ah_data *ahp; + unsigned char *tmp_hdr =3D NULL; + int hdr_len =3D skb->h.raw - skb->nh.raw; + u8 nexthdr =3D 0; + + if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) + goto out; + + ah =3D (struct ipv6_auth_hdr*)skb->data; + ahp =3D x->data; + ah_hlen =3D (ah->hdrlen + 2) << 2; + + if (ah_hlen !=3D XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->i= cv_full_len) && + ah_hlen !=3D XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->i= cv_trunc_len)) + goto out; + + if (!pskb_may_pull(skb, ah_hlen)) + goto out; + + /* We are going to _remove_ AH header to keep sockets happy, + * so... Later this can change. */ + if (skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto out; + + tmp_hdr =3D kmalloc(hdr_len, GFP_ATOMIC); + if (!tmp_hdr) + goto out; + memcpy(tmp_hdr, skb->nh.raw, hdr_len); + ah =3D (struct ipv6_auth_hdr*)skb->data; + iph =3D skb->nh.ipv6h; + + { + u8 auth_data[ahp->icv_trunc_len]; + + memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); + skb_push(skb, skb->data - skb->nh.raw); + ahp->icv(ahp, skb, ah->auth_data); + if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { + if (net_ratelimit()) + printk(KERN_WARNING "ipsec ah authentication error\n"); + x->stats.integrity_failed++; + goto free_out; + } + } + + nexthdr =3D ((struct ipv6hdr*)tmp_hdr)->nexthdr =3D ah->nexthdr; + skb->nh.raw =3D skb_pull(skb, (ah->hdrlen+2)<<2); + memcpy(skb->nh.raw, tmp_hdr, hdr_len); + skb->nh.ipv6h->payload_len =3D htons(skb->len - sizeof(struct ipv6hdr)); + skb_pull(skb, hdr_len); + skb->h.raw =3D skb->data; + + + kfree(tmp_hdr); + + return nexthdr; + +free_out: + kfree(tmp_hdr); +out: + return -EINVAL; +} + +void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,=20 + int type, int code, int offset, __u32 info) +{ + struct ipv6hdr *iph =3D (struct ipv6hdr*)skb->data; + struct ip_auth_hdr *ah =3D (struct ip_auth_hdr*)(skb->data+offset); + struct xfrm_state *x; + + if (type !=3D ICMPV6_DEST_UNREACH || + type !=3D ICMPV6_PKT_TOOBIG) + return; + + x =3D xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_A= H, AF_INET6); + if (!x) + return; + + printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/" + "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + ntohl(ah->spi), NIP6(iph->daddr)); + + xfrm_state_put(x); +} + +static int ah6_init_state(struct xfrm_state *x, void *args) +{ + struct ah_data *ahp =3D NULL; + struct xfrm_algo_desc *aalg_desc; + + /* null auth can use a zero length key */ + if (x->aalg->alg_key_len > 512) + goto error; + + ahp =3D kmalloc(sizeof(*ahp), GFP_KERNEL); + if (ahp =3D=3D NULL) + return -ENOMEM; + + memset(ahp, 0, sizeof(*ahp)); + + ahp->key =3D x->aalg->alg_key; + ahp->key_len =3D (x->aalg->alg_key_len+7)/8; + ahp->tfm =3D crypto_alloc_tfm(x->aalg->alg_name, 0); + if (!ahp->tfm) + goto error; + ahp->icv =3D ah_hmac_digest; +=09 + /* + * Lookup the algorithm description maintained by xfrm_algo, + * verify crypto transform properties, and store information + * we need for AH processing. This lookup cannot fail here + * after a successful crypto_alloc_tfm(). + */ + aalg_desc =3D xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 !=3D + crypto_tfm_alg_digestsize(ahp->tfm)) { + printk(KERN_INFO "AH: %s digestsize %u !=3D %hu\n", + x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } +=09 + ahp->icv_full_len =3D aalg_desc->uinfo.auth.icv_fullbits/8; + ahp->icv_trunc_len =3D aalg_desc->uinfo.auth.icv_truncbits/8; +=09 + ahp->work_icv =3D kmalloc(ahp->icv_full_len, GFP_KERNEL); + if (!ahp->work_icv) + goto error; +=09 + x->props.header_len =3D XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->i= cv_trunc_len); + if (x->props.mode) + x->props.header_len +=3D sizeof(struct ipv6hdr); + x->data =3D ahp; + + return 0; + +error: + if (ahp) { + if (ahp->work_icv) + kfree(ahp->work_icv); + if (ahp->tfm) + crypto_free_tfm(ahp->tfm); + kfree(ahp); + } + return -EINVAL; +} + +static void ah6_destroy(struct xfrm_state *x) +{ + struct ah_data *ahp =3D x->data; + + if (ahp->work_icv) { + kfree(ahp->work_icv); + ahp->work_icv =3D NULL; + } + if (ahp->tfm) { + crypto_free_tfm(ahp->tfm); + ahp->tfm =3D NULL; + } + kfree(ahp); +} + +static struct xfrm_type ah6_type =3D +{ + .description =3D "AH6", + .owner =3D THIS_MODULE, + .proto =3D IPPROTO_AH, + .init_state =3D ah6_init_state, + .destructor =3D ah6_destroy, + .input =3D ah6_input, + .output =3D ah6_output +}; + +static struct inet6_protocol ah6_protocol =3D { + .handler =3D xfrm6_rcv, + .err_handler =3D ah6_err, + .flags =3D INET6_PROTO_NOPOLICY, +}; + +int __init ah6_init(void) +{ + if (xfrm_register_type(&ah6_type, AF_INET6) < 0) { + printk(KERN_INFO "ipv6 ah init: can't add xfrm type\n"); + return -EAGAIN; + } + + if (inet6_add_protocol(&ah6_protocol, IPPROTO_AH) < 0) { + printk(KERN_INFO "ipv6 ah init: can't add protocol\n"); + xfrm_unregister_type(&ah6_type, AF_INET6); + return -EAGAIN; + } + + return 0; +} + +static void __exit ah6_fini(void) +{ + if (inet6_del_protocol(&ah6_protocol, IPPROTO_AH) < 0) + printk(KERN_INFO "ipv6 ah close: can't remove protocol\n"); + + if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0) + printk(KERN_INFO "ipv6 ah close: can't remove xfrm type\n"); + +} + +module_init(ah6_init); +module_exit(ah6_fini); + +MODULE_LICENSE("GPL"); diff -Nru a/net/ipv6/datagram.c b/net/ipv6/datagram.c --- a/net/ipv6/datagram.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/datagram.c Thu May 8 10:41:36 2003 @@ -89,7 +89,7 @@ serr->ee.ee_info =3D info; serr->ee.ee_data =3D 0; serr->addr_offset =3D (u8*)&iph->daddr - skb->nh.raw; - serr->port =3D fl->uli_u.ports.dport; + serr->port =3D fl->fl_ip_dport; =20 skb->h.raw =3D skb->tail; __skb_pull(skb, skb->tail - skb->data); diff -Nru a/net/ipv6/esp6.c b/net/ipv6/esp6.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv6/esp6.c Thu May 8 10:41:38 2003 @@ -0,0 +1,531 @@ +/* + * Copyright (C)2002 USAGI/WIDE Project + *=20 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *=20 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *=20 + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U= SA + * + * Authors + * + * Mitsuru KANDA @USAGI : IPv6 Support=20 + * Kazunori MIYAZAWA @USAGI : + * Kunihiro Ishiguro : + * =09 + * This file is derived from net/ipv4/esp.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SG_ONSTACK 4 + +/* BUGS: + * - we assume replay seqno is always present. + */ + +/* Move to common area: it is shared with AH. */ +/* Common with AH after some work on arguments. */ + +/* XXX no ipv6 esp specific */ +#define NIP6(addr) \ + ntohs((addr).s6_addr16[0]),\ + ntohs((addr).s6_addr16[1]),\ + ntohs((addr).s6_addr16[2]),\ + ntohs((addr).s6_addr16[3]),\ + ntohs((addr).s6_addr16[4]),\ + ntohs((addr).s6_addr16[5]),\ + ntohs((addr).s6_addr16[6]),\ + ntohs((addr).s6_addr16[7]) + +static int get_offset(u8 *packet, u32 packet_len, u8 *nexthdr, struct ipv6= _opt_hdr **prevhdr) +{ + u16 offset =3D sizeof(struct ipv6hdr); + struct ipv6_opt_hdr *exthdr =3D (struct ipv6_opt_hdr*)(packet + offset); + u8 nextnexthdr; + + *nexthdr =3D ((struct ipv6hdr*)packet)->nexthdr; + + while (offset + 1 < packet_len) { + + switch (*nexthdr) { + + case NEXTHDR_HOP: + case NEXTHDR_ROUTING: + offset +=3D ipv6_optlen(exthdr); + *nexthdr =3D exthdr->nexthdr; + *prevhdr =3D exthdr; + exthdr =3D (struct ipv6_opt_hdr*)(packet + offset); + break; + + case NEXTHDR_DEST: + nextnexthdr =3D + ((struct ipv6_opt_hdr*)(packet + offset + ipv6_optlen(exthdr)))->nexth= dr; + /* XXX We know the option is inner dest opt + with next next header check. */ + if (nextnexthdr !=3D NEXTHDR_HOP && + nextnexthdr !=3D NEXTHDR_ROUTING && + nextnexthdr !=3D NEXTHDR_DEST) { + return offset; + } + offset +=3D ipv6_optlen(exthdr); + *nexthdr =3D exthdr->nexthdr; + *prevhdr =3D exthdr; + exthdr =3D (struct ipv6_opt_hdr*)(packet + offset); + break; + + default : + return offset; + } + } + + return offset; +} + +int esp6_output(struct sk_buff *skb) +{ + int err; + int hdr_len =3D 0; + struct dst_entry *dst =3D skb->dst; + struct xfrm_state *x =3D dst->xfrm; + struct ipv6hdr *iph =3D NULL, *top_iph; + struct ipv6_esp_hdr *esph; + struct crypto_tfm *tfm; + struct esp_data *esp; + struct sk_buff *trailer; + struct ipv6_opt_hdr *prevhdr =3D NULL; + int blksize; + int clen; + int alen; + int nfrags; + u8 nexthdr; + + /* First, if the skb is not checksummed, complete checksum. */ + if (skb->ip_summed =3D=3D CHECKSUM_HW && skb_checksum_help(skb) =3D=3D NU= LL) { + err =3D -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err =3D xfrm_check_output(x, skb, AF_INET6); + if (err) + goto error; + err =3D -ENOMEM; + + /* Strip IP header in transport mode. Save it. */ + + if (!x->props.mode) { + hdr_len =3D get_offset(skb->nh.raw, skb->len, &nexthdr, &prevhdr); + iph =3D kmalloc(hdr_len, GFP_ATOMIC); + if (!iph) { + err =3D -ENOMEM; + goto error; + } + memcpy(iph, skb->nh.raw, hdr_len); + __skb_pull(skb, hdr_len); + } + + /* Now skb is pure payload to encrypt */ + + /* Round to block size */ + clen =3D skb->len; + + esp =3D x->data; + alen =3D esp->auth.icv_trunc_len; + tfm =3D esp->conf.tfm; + blksize =3D (crypto_tfm_alg_blocksize(tfm) + 3) & ~3; + clen =3D (clen + 2 + blksize-1)&~(blksize-1); + if (esp->conf.padlen) + clen =3D (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + if ((nfrags =3D skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) { + if (!x->props.mode && iph) kfree(iph); + goto error; + } + + /* Fill padding... */ + do { + int i; + for (i=3D0; ilen - 2; i++) + *(u8*)(trailer->tail + i) =3D i+1; + } while (0); + *(u8*)(trailer->tail + clen-skb->len - 2) =3D (clen - skb->len)-2; + pskb_put(skb, trailer, clen - skb->len); + + if (x->props.mode) { + iph =3D skb->nh.ipv6h; + top_iph =3D (struct ipv6hdr*)skb_push(skb, x->props.header_len); + esph =3D (struct ipv6_esp_hdr*)(top_iph+1); + *(u8*)(trailer->tail - 1) =3D IPPROTO_IPV6; + top_iph->version =3D 6; + top_iph->priority =3D iph->priority; + top_iph->flow_lbl[0] =3D iph->flow_lbl[0]; + top_iph->flow_lbl[1] =3D iph->flow_lbl[1]; + top_iph->flow_lbl[2] =3D iph->flow_lbl[2]; + top_iph->nexthdr =3D IPPROTO_ESP; + top_iph->payload_len =3D htons(skb->len + alen - sizeof(struct ipv6hdr))= ; + top_iph->hop_limit =3D iph->hop_limit; + memcpy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr, sizeof(struc= t in6_addr)); + memcpy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr, sizeof(struct i= n6_addr)); + } else {=20 + /* XXX exthdr */ + esph =3D (struct ipv6_esp_hdr*)skb_push(skb, x->props.header_len); + skb->h.raw =3D (unsigned char*)esph; + top_iph =3D (struct ipv6hdr*)skb_push(skb, hdr_len); + memcpy(top_iph, iph, hdr_len); + kfree(iph); + top_iph->payload_len =3D htons(skb->len + alen - sizeof(struct ipv6hdr))= ; + if (prevhdr) { + prevhdr->nexthdr =3D IPPROTO_ESP; + } else { + top_iph->nexthdr =3D IPPROTO_ESP; + } + *(u8*)(trailer->tail - 1) =3D nexthdr; + } + + esph->spi =3D x->id.spi; + esph->seq_no =3D htonl(++x->replay.oseq); + + if (esp->conf.ivlen) + crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + + do { + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg =3D sgbuf; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg =3D kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto error; + } + skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); + crypto_cipher_encrypt(tfm, sg, sg, clen); + if (unlikely(sg !=3D sgbuf)) + kfree(sg); + } while (0); + + if (esp->conf.ivlen) { + memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + } + + if (esp->auth.icv_full_len) { + esp->auth.icv(esp, skb, (u8*)esph-skb->data, + sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); + pskb_put(skb, trailer, alen); + } + + skb->nh.raw =3D skb->data; + + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst =3D dst_pop(dst)) =3D=3D NULL) { + err =3D -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + return err; +} + +int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc= t sk_buff *skb) +{ + struct ipv6hdr *iph; + struct ipv6_esp_hdr *esph; + struct esp_data *esp =3D x->data; + struct sk_buff *trailer; + int blksize =3D crypto_tfm_alg_blocksize(esp->conf.tfm); + int alen =3D esp->auth.icv_trunc_len; + int elen =3D skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - a= len; + + int hdr_len =3D skb->h.raw - skb->nh.raw; + int nfrags; + u8 ret_nexthdr =3D 0; + unsigned char *tmp_hdr =3D NULL; + + if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) + goto out; + + if (elen <=3D 0 || (elen & (blksize-1))) + goto out; + + tmp_hdr =3D kmalloc(hdr_len, GFP_ATOMIC); + if (!tmp_hdr) + goto out; + memcpy(tmp_hdr, skb->nh.raw, hdr_len); + + /* If integrity check is required, do this. */ + if (esp->auth.icv_full_len) { + u8 sum[esp->auth.icv_full_len]; + u8 sum1[alen]; + + esp->auth.icv(esp, skb, 0, skb->len-alen, sum); + + if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) + BUG(); + + if (unlikely(memcmp(sum, sum1, alen))) { + x->stats.integrity_failed++; + goto out; + } + } + + if ((nfrags =3D skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + + skb->ip_summed =3D CHECKSUM_NONE; + + esph =3D (struct ipv6_esp_hdr*)skb->data; + iph =3D skb->nh.ipv6h; + + /* Get ivec. This can be wrong, check against another impls. */ + if (esp->conf.ivlen) + crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsiz= e(esp->conf.tfm)); + + { + u8 nexthdr[2]; + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg =3D sgbuf; + u8 padlen; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg =3D kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto out; + } + skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, ele= n); + crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); + if (unlikely(sg !=3D sgbuf)) + kfree(sg); + + if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) + BUG(); + + padlen =3D nexthdr[0]; + if (padlen+2 >=3D elen) { + if (net_ratelimit()) { + printk(KERN_WARNING "ipsec esp packet is garbage padlen=3D%d, elen=3D%= d\n", padlen+2, elen); + } + goto out; + } + /* ... check padding bits here. Silly. :-) */=20 + + ret_nexthdr =3D ((struct ipv6hdr*)tmp_hdr)->nexthdr =3D nexthdr[1]; + pskb_trim(skb, skb->len - alen - padlen - 2); + skb->h.raw =3D skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivl= en); + skb->nh.raw +=3D sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; + memcpy(skb->nh.raw, tmp_hdr, hdr_len); + } + kfree(tmp_hdr); + return ret_nexthdr; + +out: + return -EINVAL; +} + +static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) +{ + struct esp_data *esp =3D x->data; + u32 blksize =3D crypto_tfm_alg_blocksize(esp->conf.tfm); + + if (x->props.mode) { + mtu =3D (mtu + 2 + blksize-1)&~(blksize-1); + } else { + /* The worst case. */ + mtu +=3D 2 + blksize; + } + if (esp->conf.padlen) + mtu =3D (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + return mtu + x->props.header_len + esp->auth.icv_full_len; +} + +void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) +{ + struct ipv6hdr *iph =3D (struct ipv6hdr*)skb->data; + struct ipv6_esp_hdr *esph =3D (struct ipv6_esp_hdr*)(skb->data+offset); + struct xfrm_state *x; + + if (type !=3D ICMPV6_DEST_UNREACH || + type !=3D ICMPV6_PKT_TOOBIG) + return; + + x =3D xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO= _ESP, AF_INET6); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA ESP/%08x/" + "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",=20 + ntohl(esph->spi), NIP6(iph->daddr)); + xfrm_state_put(x); +} + +void esp6_destroy(struct xfrm_state *x) +{ + struct esp_data *esp =3D x->data; + + if (esp->conf.tfm) { + crypto_free_tfm(esp->conf.tfm); + esp->conf.tfm =3D NULL; + } + if (esp->conf.ivec) { + kfree(esp->conf.ivec); + esp->conf.ivec =3D NULL; + } + if (esp->auth.tfm) { + crypto_free_tfm(esp->auth.tfm); + esp->auth.tfm =3D NULL; + } + if (esp->auth.work_icv) { + kfree(esp->auth.work_icv); + esp->auth.work_icv =3D NULL; + } + kfree(esp); +} + +int esp6_init_state(struct xfrm_state *x, void *args) +{ + struct esp_data *esp =3D NULL; + + if (x->aalg) { + if (x->aalg->alg_key_len =3D=3D 0 || x->aalg->alg_key_len > 512) + goto error; + } + if (x->ealg =3D=3D NULL) + goto error; + + esp =3D kmalloc(sizeof(*esp), GFP_KERNEL); + if (esp =3D=3D NULL) + return -ENOMEM; + + memset(esp, 0, sizeof(*esp)); + + if (x->aalg) { + struct xfrm_algo_desc *aalg_desc; + + esp->auth.key =3D x->aalg->alg_key; + esp->auth.key_len =3D (x->aalg->alg_key_len+7)/8; + esp->auth.tfm =3D crypto_alloc_tfm(x->aalg->alg_name, 0); + if (esp->auth.tfm =3D=3D NULL) + goto error; + esp->auth.icv =3D esp_hmac_digest; +=20 + aalg_desc =3D xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); +=20 + if (aalg_desc->uinfo.auth.icv_fullbits/8 !=3D + crypto_tfm_alg_digestsize(esp->auth.tfm)) { + printk(KERN_INFO "ESP: %s digestsize %u !=3D %hu\n", + x->aalg->alg_name, + crypto_tfm_alg_digestsize(esp->auth.tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } +=20 + esp->auth.icv_full_len =3D aalg_desc->uinfo.auth.icv_fullbits/8; + esp->auth.icv_trunc_len =3D aalg_desc->uinfo.auth.icv_truncbits/8; +=20 + esp->auth.work_icv =3D kmalloc(esp->auth.icv_full_len, GFP_KERNEL); + if (!esp->auth.work_icv) + goto error; + } + esp->conf.key =3D x->ealg->alg_key; + esp->conf.key_len =3D (x->ealg->alg_key_len+7)/8; + esp->conf.tfm =3D crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC= ); + if (esp->conf.tfm =3D=3D NULL) + goto error; + esp->conf.ivlen =3D crypto_tfm_alg_ivsize(esp->conf.tfm); + esp->conf.padlen =3D 0; + if (esp->conf.ivlen) { + esp->conf.ivec =3D kmalloc(esp->conf.ivlen, GFP_KERNEL); + get_random_bytes(esp->conf.ivec, esp->conf.ivlen); + } + crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len); + x->props.header_len =3D sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; + if (x->props.mode) + x->props.header_len +=3D sizeof(struct ipv6hdr); + x->data =3D esp; + return 0; + +error: + if (esp) { + if (esp->auth.tfm) + crypto_free_tfm(esp->auth.tfm); + if (esp->auth.work_icv) + kfree(esp->auth.work_icv); + if (esp->conf.tfm) + crypto_free_tfm(esp->conf.tfm); + kfree(esp); + } + return -EINVAL; +} + +static struct xfrm_type esp6_type =3D +{ + .description =3D "ESP6", + .owner =3D THIS_MODULE, + .proto =3D IPPROTO_ESP, + .init_state =3D esp6_init_state, + .destructor =3D esp6_destroy, + .get_max_size =3D esp6_get_max_size, + .input =3D esp6_input, + .output =3D esp6_output +}; + +static struct inet6_protocol esp6_protocol =3D { + .handler =3D xfrm6_rcv, + .err_handler =3D esp6_err, + .flags =3D INET6_PROTO_NOPOLICY, +}; + +int __init esp6_init(void) +{ + if (xfrm_register_type(&esp6_type, AF_INET6) < 0) { + printk(KERN_INFO "ipv6 esp init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet6_add_protocol(&esp6_protocol, IPPROTO_ESP) < 0) { + printk(KERN_INFO "ipv6 esp init: can't add protocol\n"); + xfrm_unregister_type(&esp6_type, AF_INET6); + return -EAGAIN; + } + + return 0; +} + +static void __exit esp6_fini(void) +{ + if (inet6_del_protocol(&esp6_protocol, IPPROTO_ESP) < 0) + printk(KERN_INFO "ipv6 esp close: can't remove protocol\n"); + if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0) + printk(KERN_INFO "ipv6 esp close: can't remove xfrm type\n"); +} + +module_init(esp6_init); +module_exit(esp6_fini); + +MODULE_LICENSE("GPL"); diff -Nru a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c --- a/net/ipv6/exthdrs.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/exthdrs.c Thu May 8 10:41:36 2003 @@ -18,6 +18,9 @@ /* Changes: * yoshfuji : ensure not to overrun while parsing=20 * tlv options. + * Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs(). + * YOSHIFUJI Hideaki @USAGI Register inbound extention header + * handlers as inet6_protocol{}. */ =20 #include @@ -44,20 +47,6 @@ #include =20 /* - * Parsing inbound headers. - * - * Parsing function "func" returns offset wrt skb->nh of the place, - * where next nexthdr value is stored or NULL, if parsing - * failed. It should also update skb->h tp point at the next header. - */ - -struct hdrtype_proc -{ - int type; - int (*func) (struct sk_buff **, int offset); -}; - -/* * Parsing tlv encoded headers. * * Parsing function "func" returns 1, if parsing succeed @@ -164,9 +153,9 @@ {-1, NULL} }; =20 -static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff) +static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) { - struct sk_buff *skb=3D*skb_ptr; + struct sk_buff *skb =3D *skbp; struct inet6_skb_parm *opt =3D (struct inet6_skb_parm *)skb->cb; =20 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || @@ -179,29 +168,56 @@ =20 if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { skb->h.raw +=3D ((skb->h.raw[1]+1)<<3); - return opt->dst1; + *nhoffp =3D opt->dst1; + return 1; } =20 return -1; } =20 +static struct inet6_protocol destopt_protocol =3D +{ + .handler =3D ipv6_destopt_rcv, + .flags =3D INET6_PROTO_NOPOLICY, +}; + +void __init ipv6_destopt_init(void) +{ + if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0) + printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n"); +} + /******************************** NONE header. No data in packet. ********************************/ =20 -static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff) +static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp) { - kfree_skb(*skb_ptr); - return -1; + struct sk_buff *skb =3D *skbp; + + kfree_skb(skb); + return 0; +} + +static struct inet6_protocol nodata_protocol =3D +{ + .handler =3D ipv6_nodata_rcv, + .flags =3D INET6_PROTO_NOPOLICY, +}; + +void __init ipv6_nodata_init(void) +{ + if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0) + printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n"); } =20 /******************************** Routing header. ********************************/ =20 -static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff) +static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) { - struct sk_buff *skb =3D *skb_ptr; + struct sk_buff *skb =3D *skbp; struct inet6_skb_parm *opt =3D (struct inet6_skb_parm *)skb->cb; struct in6_addr *addr; struct in6_addr daddr; @@ -232,7 +248,8 @@ skb->h.raw +=3D (hdr->hdrlen + 1) << 3; opt->dst0 =3D opt->dst1; opt->dst1 =3D 0; - return (&hdr->nexthdr) - skb->nh.raw; + *nhoffp =3D (&hdr->nexthdr) - skb->nh.raw; + return 1; } =20 if (hdr->type !=3D IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) { @@ -242,7 +259,7 @@ =20 /* * This is the routing header forwarding algorithm from - * RFC 1883, page 17. + * RFC 2460, page 16. */ =20 n =3D hdr->hdrlen >> 1; @@ -260,7 +277,7 @@ kfree_skb(skb); if (skb2 =3D=3D NULL) return -1; - *skb_ptr =3D skb =3D skb2; + *skbp =3D skb =3D skb2; opt =3D (struct inet6_skb_parm *)skb2->cb; hdr =3D (struct ipv6_rt_hdr *) skb2->h.raw; } @@ -288,7 +305,7 @@ dst_release(xchg(&skb->dst, NULL)); ip6_route_input(skb); if (skb->dst->error) { - skb->dst->input(skb); + dst_input(skb); return -1; } if (skb->dst->dev->flags&IFF_LOOPBACK) { @@ -302,10 +319,22 @@ goto looped_back; } =20 - skb->dst->input(skb); + dst_input(skb); return -1; } =20 +static struct inet6_protocol rthdr_protocol =3D +{ + .handler =3D ipv6_rthdr_rcv, + .flags =3D INET6_PROTO_NOPOLICY, +}; + +void __init ipv6_rthdr_init(void) +{ + if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0) + printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n"); +}; + /* This function inverts received rthdr. NOTE: specs allow to make it automatically only if @@ -370,97 +399,6 @@ memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16); return opt; } - -/******************************** - AUTH header. - ********************************/ - -/* - rfc1826 said, that if a host does not implement AUTH header - it MAY ignore it. We use this hole 8) - - Actually, now we can implement OSPFv6 without kernel IPsec. - Authentication for poors may be done in user space with the same succes= s. - - Yes, it means, that we allow application to send/receive - raw authentication header. Apparently, we suppose, that it knows - what it does and calculates authentication data correctly. - Certainly, it is possible only for udp and raw sockets, but not for tcp= . - - AUTH header has 4byte granular length, which kills all the idea - behind AUTOMATIC 64bit alignment of IPv6. Now we will lose - cpu ticks, checking that sender did not something stupid - and opt->hdrlen is even. Shit! --ANK (980730) - */ - -static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff) -{ - struct sk_buff *skb=3D*skb_ptr; - struct inet6_skb_parm *opt =3D (struct inet6_skb_parm *)skb->cb; - int len; - - if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8)) - goto fail; - - /* - * RFC2402 2.2 Payload Length - * The 8-bit field specifies the length of AH in 32-bit words=20 - * (4-byte units), minus "2". - * -- Noriaki Takamiya @USAGI Project - */ - len =3D (skb->h.raw[1]+2)<<2; - - if (len&7) - goto fail; - - if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len)) - goto fail; - - opt->auth =3D skb->h.raw - skb->nh.raw; - skb->h.raw +=3D len; - return opt->auth; - -fail: - kfree_skb(skb); - return -1; -} - -/* This list MUST NOT contain entry for NEXTHDR_HOP. - It is parsed immediately after packet received - and if it occurs somewhere in another place we must - generate error. - */ - -struct hdrtype_proc hdrproc_lst[] =3D { - {NEXTHDR_FRAGMENT, ipv6_reassembly}, - {NEXTHDR_ROUTING, ipv6_routing_header}, - {NEXTHDR_DEST, ipv6_dest_opt}, - {NEXTHDR_NONE, ipv6_nodata}, - {NEXTHDR_AUTH, ipv6_auth_hdr}, - /* - {NEXTHDR_ESP, ipv6_esp_hdr}, - */ - {-1, NULL} -}; - -int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff) -{ - struct hdrtype_proc *hdrt; - u8 nexthdr =3D (*skb_in)->nh.raw[nhoff]; - -restart: - for (hdrt=3Dhdrproc_lst; hdrt->type >=3D 0; hdrt++) { - if (hdrt->type =3D=3D nexthdr) { - if ((nhoff =3D hdrt->func(skb_in, nhoff)) >=3D 0) { - nexthdr =3D (*skb_in)->nh.raw[nhoff]; - goto restart; - } - return -1; - } - } - return nhoff; -} - =20 /********************************** Hop-by-hop options. diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c --- a/net/ipv6/icmp.c Thu May 8 10:41:37 2003 +++ b/net/ipv6/icmp.c Thu May 8 10:41:37 2003 @@ -74,17 +74,11 @@ #define icmpv6_socket __icmpv6_socket[smp_processor_id()] #define icmpv6_socket_cpu(X) __icmpv6_socket[(X)] =20 -int icmpv6_rcv(struct sk_buff *skb); +static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); =20 -static struct inet6_protocol icmpv6_protocol =3D=20 -{ - icmpv6_rcv, /* handler */ - NULL, /* error control */ - NULL, /* next */ - IPPROTO_ICMPV6, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "ICMPv6" /* name */ +static struct inet6_protocol icmpv6_protocol =3D { + .handler =3D icmpv6_rcv, + .flags =3D INET6_PROTO_FINAL, }; =20 struct icmpv6_msg { @@ -318,12 +312,12 @@ } =20 fl.proto =3D IPPROTO_ICMPV6; - fl.nl_u.ip6_u.daddr =3D &hdr->saddr; - fl.nl_u.ip6_u.saddr =3D saddr; + fl.fl6_dst =3D &hdr->saddr; + fl.fl6_src =3D saddr; fl.oif =3D iif; fl.fl6_flowlabel =3D 0; - fl.uli_u.icmpt.type =3D type; - fl.uli_u.icmpt.code =3D code; + fl.fl_icmp_type =3D type; + fl.fl_icmp_code =3D code; =20 icmpv6_xmit_lock(); =20 @@ -392,12 +386,12 @@ msg.daddr =3D &skb->nh.ipv6h->saddr; =20 fl.proto =3D IPPROTO_ICMPV6; - fl.nl_u.ip6_u.daddr =3D msg.daddr; - fl.nl_u.ip6_u.saddr =3D saddr; + fl.fl6_dst =3D msg.daddr; + fl.fl6_src =3D saddr; fl.oif =3D skb->dev->ifindex; fl.fl6_flowlabel =3D 0; - fl.uli_u.icmpt.type =3D ICMPV6_ECHO_REPLY; - fl.uli_u.icmpt.code =3D 0; + fl.fl_icmp_type =3D ICMPV6_ECHO_REPLY; + fl.fl_icmp_code =3D 0; =20 icmpv6_xmit_lock(); =20 @@ -447,15 +441,9 @@ =20 hash =3D nexthdr & (MAX_INET_PROTOS - 1); =20 - for (ipprot =3D (struct inet6_protocol *) inet6_protos[hash];=20 - ipprot !=3D NULL;=20 - ipprot=3D(struct inet6_protocol *)ipprot->next) { - if (ipprot->protocol !=3D nexthdr) - continue; - - if (ipprot->err_handler) - ipprot->err_handler(skb, NULL, type, code, inner_offset, info); - } + ipprot =3D inet6_protos[hash]; + if (ipprot && ipprot->err_handler) + ipprot->err_handler(skb, NULL, type, code, inner_offset, info); =20 read_lock(&raw_v6_lock); if ((sk =3D raw_v6_htable[hash]) !=3D NULL) { @@ -471,8 +459,9 @@ * Handle icmp messages */ =20 -int icmpv6_rcv(struct sk_buff *skb) +static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) { + struct sk_buff *skb =3D *pskb; struct net_device *dev =3D skb->dev; struct in6_addr *saddr, *daddr; struct ipv6hdr *orig_hdr; @@ -643,7 +632,12 @@ sk->prot->unhash(sk); } =20 - inet6_add_protocol(&icmpv6_protocol); + if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) { + printk(KERN_ERR "Failed to register ICMP6 protocol\n"); + sock_release(icmpv6_socket); + icmpv6_socket =3D NULL; + return -EAGAIN; + } =20 return 0; fail: @@ -662,7 +656,7 @@ sock_release(icmpv6_socket_cpu(i)); icmpv6_socket_cpu(i) =3D NULL; } - inet6_del_protocol(&icmpv6_protocol); + inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); } =20 static struct icmp6_err { diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c --- a/net/ipv6/ip6_fib.c Thu May 8 10:41:37 2003 +++ b/net/ipv6/ip6_fib.c Thu May 8 10:41:37 2003 @@ -453,7 +453,6 @@ */ =20 if ((iter->rt6i_dev =3D=3D rt->rt6i_dev) && - (iter->rt6i_flowr =3D=3D rt->rt6i_flowr) && (ipv6_addr_cmp(&iter->rt6i_gateway, &rt->rt6i_gateway) =3D=3D 0)) { if (!(iter->rt6i_flags&RTF_EXPIRES)) diff -Nru a/net/ipv6/ip6_fw.c b/net/ipv6/ip6_fw.c --- a/net/ipv6/ip6_fw.c Thu May 8 10:41:37 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,390 +0,0 @@ -/* - * IPv6 Firewall - * Linux INET6 implementation - * - * Authors: - * Pedro Roque =09 - * - * $Id: ip6_fw.c,v 1.16 2001/10/31 08:17:58 davem Exp $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static unsigned long ip6_fw_rule_cnt; -static struct ip6_fw_rule ip6_fw_rule_list =3D { - {0}, - NULL, NULL, - {0}, - IP6_FW_REJECT -}; - -static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args); - -struct flow_rule_ops ip6_fw_ops =3D { - ip6_fw_accept -}; - - -static struct rt6_info ip6_fw_null_entry =3D { - {{NULL, 0, 0, NULL, - 0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL, - ip6_pkt_discard, ip6_pkt_discard, NULL}}, - NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL, - 0, &ip6_fw_rule_list, {{{{0}}}, 128}, {{{{0}}}, 128} -}; - -static struct fib6_node ip6_fw_fib =3D { - NULL, NULL, NULL, NULL, - &ip6_fw_null_entry, - 0, RTN_ROOT|RTN_TL_ROOT, 0 -}; - -rwlock_t ip6_fw_lock =3D RW_LOCK_UNLOCKED; - - -static void ip6_rule_add(struct ip6_fw_rule *rl) -{ - struct ip6_fw_rule *next; - - write_lock_bh(&ip6_fw_lock); - ip6_fw_rule_cnt++; - next =3D &ip6_fw_rule_list; - rl->next =3D next; - rl->prev =3D next->prev; - rl->prev->next =3D rl; - next->prev =3D rl; - write_unlock_bh(&ip6_fw_lock); -} - -static void ip6_rule_del(struct ip6_fw_rule *rl) -{ - struct ip6_fw_rule *next, *prev; - - write_lock_bh(&ip6_fw_lock); - ip6_fw_rule_cnt--; - next =3D rl->next; - prev =3D rl->prev; - next->prev =3D prev; - prev->next =3D next; - write_unlock_bh(&ip6_fw_lock); -} - -static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void) -{ - struct ip6_fw_rule *rl; - - rl =3D kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC); - if (rl) - { - memset(rl, 0, sizeof(struct ip6_fw_rule)); - rl->flowr.ops =3D &ip6_fw_ops; - } - return rl; -} - -static __inline__ void ip6_fwrule_free(struct ip6_fw_rule * rl) -{ - kfree(rl); -} - -static __inline__ int port_match(int rl_port, int fl_port) -{ - int res =3D 0; - if (rl_port =3D=3D 0 || (rl_port =3D=3D fl_port)) - res =3D 1; - return res; -} - -static int ip6_fw_accept_trans(struct ip6_fw_rule *rl, - struct fl_acc_args *args) -{ - int res =3D FLOWR_NODECISION; - int proto =3D 0; - int sport =3D 0; - int dport =3D 0; - - switch (args->type) { - case FL_ARG_FORWARD: - { - struct sk_buff *skb =3D args->fl_u.skb; - struct ipv6hdr *hdr =3D skb->nh.ipv6h; - int len; - - len =3D skb->len - sizeof(struct ipv6hdr); - - proto =3D hdr->nexthdr; - - switch (proto) { - case IPPROTO_TCP: - { - struct tcphdr *th; - - if (len < sizeof(struct tcphdr)) { - res =3D FLOWR_ERROR; - goto out; - } - th =3D (struct tcphdr *)(hdr + 1); - sport =3D th->source; - dport =3D th->dest; - break; - } - case IPPROTO_UDP: - { - struct udphdr *uh; - - if (len < sizeof(struct udphdr)) { - res =3D FLOWR_ERROR; - goto out; - } - uh =3D (struct udphdr *)(hdr + 1); - sport =3D uh->source; - dport =3D uh->dest; - break; - } - default: - goto out; - }; - break; - } - - case FL_ARG_ORIGIN: - { - proto =3D args->fl_u.fl_o.flow->proto; - - if (proto =3D=3D IPPROTO_ICMPV6) { - goto out; - } else { - sport =3D args->fl_u.fl_o.flow->uli_u.ports.sport; - dport =3D args->fl_u.fl_o.flow->uli_u.ports.dport; - } - break; - } - - if (proto =3D=3D rl->info.proto && - port_match(args->fl_u.fl_o.flow->uli_u.ports.sport, sport) && - port_match(args->fl_u.fl_o.flow->uli_u.ports.dport, dport)) { - if (rl->policy & IP6_FW_REJECT) - res =3D FLOWR_SELECT; - else - res =3D FLOWR_CLEAR; - } - - default: -#if IP6_FW_DEBUG >=3D 1 - printk(KERN_DEBUG "ip6_fw_accept: unknown arg type\n"); -#endif - goto out; - }; - -out: - return res; -} - -static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args) -{ - struct rt6_info *rt; - struct ip6_fw_rule *rl; - int proto; - int res =3D FLOWR_NODECISION; - - rt =3D (struct rt6_info *) dst; - rl =3D (struct ip6_fw_rule *) rt->rt6i_flowr; - - proto =3D rl->info.proto; - - switch (proto) { - case 0: - if (rl->policy & IP6_FW_REJECT) - res =3D FLOWR_SELECT; - else - res =3D FLOWR_CLEAR; - break; - case IPPROTO_TCP: - case IPPROTO_UDP: - res =3D ip6_fw_accept_trans(rl, args); - break; - case IPPROTO_ICMPV6: - }; - - return res; -} - -static struct dst_entry * ip6_fw_dup(struct dst_entry *frule, - struct dst_entry *rt, - struct fl_acc_args *args) -{ - struct ip6_fw_rule *rl; - struct rt6_info *nrt; - struct rt6_info *frt; - - frt =3D (struct rt6_info *) frule; - - rl =3D (struct ip6_fw_rule *) frt->rt6i_flowr; - - nrt =3D ip6_rt_copy((struct rt6_info *) rt); - - if (nrt) { - nrt->u.dst.input =3D frule->input; - nrt->u.dst.output =3D frule->output; - - nrt->rt6i_flowr =3D flow_clone(frt->rt6i_flowr); - - nrt->rt6i_flags |=3D RTF_CACHE; - nrt->rt6i_tstamp =3D jiffies; - } - - return (struct dst_entry *) nrt; -} - -int ip6_fw_reject(struct sk_buff *skb) -{ -#if IP6_FW_DEBUG >=3D 1 - printk(KERN_DEBUG "packet rejected: \n"); -#endif - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, - skb->dev); - /* - * send it via netlink, as (rule, skb) - */ - - kfree_skb(skb); - return 0; -} - -int ip6_fw_discard(struct sk_buff *skb) -{ - printk(KERN_DEBUG "ip6_fw: BUG fw_reject called\n"); - kfree_skb(skb); - return 0; -} - -int ip6_fw_msg_add(struct ip6_fw_msg *msg) -{ - struct in6_rtmsg rtmsg; - struct ip6_fw_rule *rl; - struct rt6_info *rt; - int err; - - ipv6_addr_copy(&rtmsg.rtmsg_dst, &msg->dst); - ipv6_addr_copy(&rtmsg.rtmsg_src, &msg->src); - rtmsg.rtmsg_dst_len =3D msg->dst_len; - rtmsg.rtmsg_src_len =3D msg->src_len; - rtmsg.rtmsg_metric =3D IP6_RT_PRIO_FW; - - rl =3D ip6_fwrule_alloc(); - - if (rl =3D=3D NULL) - return -ENOMEM; - - rl->policy =3D msg->policy; - rl->info.proto =3D msg->proto; - rl->info.uli_u.data =3D msg->u.data; - - rtmsg.rtmsg_flags =3D RTF_NONEXTHOP|RTF_POLICY; - err =3D ip6_route_add(&rtmsg); - - if (err) { - ip6_fwrule_free(rl); - return err; - } - - /* The rest will not work for now. --ABK (989725) */ - -#ifndef notdef - ip6_fwrule_free(rl); - return -EPERM; -#else - rt->u.dst.error =3D -EPERM; - - if (msg->policy =3D=3D IP6_FW_ACCEPT) { - /* - * Accept rules are never selected - * (i.e. packets use normal forwarding) - */ - rt->u.dst.input =3D ip6_fw_discard; - rt->u.dst.output =3D ip6_fw_discard; - } else { - rt->u.dst.input =3D ip6_fw_reject; - rt->u.dst.output =3D ip6_fw_reject; - } - - ip6_rule_add(rl); - - rt->rt6i_flowr =3D flow_clone((struct flow_rule *)rl); - - return 0; -#endif -} - -static int ip6_fw_msgrcv(int unit, struct sk_buff *skb) -{ - int count =3D 0; - - while (skb->len) { - struct ip6_fw_msg *msg; - - if (skb->len < sizeof(struct ip6_fw_msg)) { - count =3D -EINVAL; - break; - } - - msg =3D (struct ip6_fw_msg *) skb->data; - skb_pull(skb, sizeof(struct ip6_fw_msg)); - count +=3D sizeof(struct ip6_fw_msg); - - switch (msg->action) { - case IP6_FW_MSG_ADD: - ip6_fw_msg_add(msg); - break; - case IP6_FW_MSG_DEL: - break; - default: - return -EINVAL; - }; - } - - return count; -} - -static void ip6_fw_destroy(struct flow_rule *rl) -{ - ip6_fwrule_free((struct ip6_fw_rule *)rl); -} - -#ifdef MODULE -#define ip6_fw_init module_init -#endif - -void __init ip6_fw_init(void) -{ - netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv); -} - -#ifdef MODULE -void cleanup_module(void) -{ - netlink_detach(NETLINK_IP6_FW); -} -#endif diff -Nru a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c --- a/net/ipv6/ip6_input.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/ip6_input.c Thu May 8 10:41:36 2003 @@ -15,6 +15,11 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +/* Changes + * + * Mitsuru KANDA @USAGI and + * YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs(). + */ =20 #include #include @@ -39,6 +44,7 @@ #include #include #include +#include =20 =20 =20 @@ -47,7 +53,7 @@ if (skb->dst =3D=3D NULL) ip6_route_input(skb); =20 - return skb->dst->input(skb); + return dst_input(skb); } =20 int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty= pe *pt) @@ -121,13 +127,12 @@ =20 static inline int ip6_input_finish(struct sk_buff *skb) { - struct ipv6hdr *hdr =3D skb->nh.ipv6h; struct inet6_protocol *ipprot; struct sock *raw_sk; - int nhoff; + unsigned int nhoff; int nexthdr; - int found =3D 0; u8 hash; + int cksum_sub =3D 0; =20 skb->h.raw =3D skb->nh.raw + sizeof(struct ipv6hdr); =20 @@ -135,7 +140,7 @@ * Parse extension headers */ =20 - nexthdr =3D hdr->nexthdr; + nexthdr =3D skb->nh.ipv6h->nexthdr; nhoff =3D offsetof(struct ipv6hdr, nexthdr); =20 /* Skip hop-by-hop options, they are already parsed. */ @@ -145,58 +150,46 @@ skb->h.raw +=3D (skb->h.raw[1]+1)<<3; } =20 - /* This check is sort of optimization. - It would be stupid to detect for optional headers, - which are missing with probability of 200% - */ - if (nexthdr !=3D IPPROTO_TCP && nexthdr !=3D IPPROTO_UDP) { - nhoff =3D ipv6_parse_exthdrs(&skb, nhoff); - if (nhoff < 0) - return 0; - nexthdr =3D skb->nh.raw[nhoff]; - hdr =3D skb->nh.ipv6h; - } - +resubmit: if (!pskb_pull(skb, skb->h.raw - skb->data)) goto discard; + nexthdr =3D skb->nh.raw[nhoff]; =20 - if (skb->ip_summed =3D=3D CHECKSUM_HW) - skb->csum =3D csum_sub(skb->csum, - csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0)); - - raw_sk =3D raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)]; + raw_sk =3D raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]; if (raw_sk) - raw_sk =3D ipv6_raw_deliver(skb, nexthdr); + ipv6_raw_deliver(skb, nexthdr); =20 hash =3D nexthdr & (MAX_INET_PROTOS - 1); - for (ipprot =3D (struct inet6_protocol *) inet6_protos[hash];=20 - ipprot !=3D NULL;=20 - ipprot =3D (struct inet6_protocol *) ipprot->next) { - struct sk_buff *buff =3D skb; - - if (ipprot->protocol !=3D nexthdr) - continue; - - if (ipprot->copy || raw_sk) - buff =3D skb_clone(skb, GFP_ATOMIC); - - if (buff) - ipprot->handler(buff); - found =3D 1; - } - - if (raw_sk) { - rawv6_rcv(raw_sk, skb); - sock_put(raw_sk); - found =3D 1; - } - - /* - * not found: send ICMP parameter problem back - */ - if (!found) { - IP6_INC_STATS_BH(Ip6InUnknownProtos); - icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff); + if ((ipprot =3D inet6_protos[hash]) !=3D NULL) { + int ret; + =09 + if (ipprot->flags & INET6_PROTO_FINAL) { + if (!cksum_sub && skb->ip_summed =3D=3D CHECKSUM_HW) { + skb->csum =3D csum_sub(skb->csum, + csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0)); + cksum_sub++; + } + } + if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && + !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + return 0; + } + =09 + ret =3D ipprot->handler(&skb, &nhoff); + if (ret > 0) + goto resubmit; + else if (ret =3D=3D 0) + IP6_INC_STATS_BH(Ip6InDelivers); + } else { + if (!raw_sk) { + if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { + IP6_INC_STATS_BH(Ip6InUnknownProtos); + icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff); + } + } else { + kfree_skb(skb); + } } =20 return 0; @@ -246,7 +239,7 @@ skb2 =3D skb; } =20 - dst->output(skb2); + dst_output(skb2); } } #endif diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c --- a/net/ipv6/ip6_output.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/ip6_output.c Thu May 8 10:41:36 2003 @@ -49,6 +49,7 @@ #include #include #include +#include =20 static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_= hdr *fhdr) { @@ -143,8 +144,8 @@ fl.fl6_src =3D &iph->saddr; fl.oif =3D skb->sk ? skb->sk->bound_dev_if : 0; fl.fl6_flowlabel =3D 0; - fl.uli_u.ports.dport =3D 0; - fl.uli_u.ports.sport =3D 0; + fl.fl_ip_dport =3D 0; + fl.fl_ip_sport =3D 0; =20 dst =3D ip6_route_output(skb->sk, &fl); =20 @@ -173,7 +174,7 @@ } } #endif /* CONFIG_NETFILTER */ - return skb->dst->output(skb); + return dst_output(skb); } =20 /* @@ -184,12 +185,18 @@ struct ipv6_txoptions *opt) { struct ipv6_pinfo * np =3D sk ? &sk->net_pinfo.af_inet6 : NULL; - struct in6_addr *first_hop =3D fl->nl_u.ip6_u.daddr; + struct in6_addr *first_hop =3D fl->fl6_dst; struct dst_entry *dst =3D skb->dst; struct ipv6hdr *hdr; u8 proto =3D fl->proto; int seg_len =3D skb->len; int hlimit; + u32 mtu; + int err =3D 0; + + if ((err =3D xfrm_lookup(&skb->dst, fl, sk, 0)) < 0) { + return err; + } =20 if (opt) { int head_room; @@ -233,17 +240,18 @@ hdr->nexthdr =3D proto; hdr->hop_limit =3D hlimit; =20 - ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr); + ipv6_addr_copy(&hdr->saddr, fl->fl6_src); ipv6_addr_copy(&hdr->daddr, first_hop); =20 - if (skb->len <=3D dst->pmtu) { + mtu =3D dst_pmtu(dst); + if (skb->len <=3D mtu) { IP6_INC_STATS(Ip6OutRequests); return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_mayb= e_reroute); } =20 if (net_ratelimit()) printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev); + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); kfree_skb(skb); return -EMSGSIZE; } @@ -297,8 +305,8 @@ hdr->hop_limit =3D hlimit; hdr->nexthdr =3D fl->proto; =20 - ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr); - ipv6_addr_copy(&hdr->daddr, fl->nl_u.ip6_u.daddr); + ipv6_addr_copy(&hdr->saddr, fl->fl6_src); + ipv6_addr_copy(&hdr->daddr, fl->fl6_dst); return hdr; } =20 @@ -514,7 +522,7 @@ fl->fl6_dst =3D rt0->addr; } =20 - if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr)) + if (!fl->oif && ipv6_addr_is_multicast(fl->fl6_dst)) fl->oif =3D np->mcast_oif; =20 dst =3D __sk_dst_check(sk, np->dst_cookie); @@ -572,6 +580,13 @@ } pktlength =3D length; =20 + if (dst) { + if ((err =3D xfrm_lookup(&dst, fl, sk, 0)) < 0) { + dst_release(dst);=09 + return -ENETUNREACH; + } + } + if (hlimit < 0) { if (ipv6_addr_is_multicast(fl->fl6_dst)) hlimit =3D np->mcast_hops; @@ -598,7 +613,7 @@ } } =20 - mtu =3D dst->pmtu; + mtu =3D dst_pmtu(dst); if (np->frag_size < mtu) { if (np->frag_size) mtu =3D np->frag_size; @@ -626,9 +641,8 @@ err =3D 0; if (flags&MSG_PROBE) goto out; - - skb =3D sock_alloc_send_skb(sk, pktlength + 15 + - dev->hard_header_len, + /* alloc skb with mtu as we do in the IPv4 stack for IPsec */ + skb =3D sock_alloc_send_skb(sk, mtu + LL_RESERVED_SPACE(dev), flags & MSG_DONTWAIT, &err); =20 if (skb =3D=3D NULL) { @@ -659,6 +673,8 @@ err =3D getfrag(data, &hdr->saddr, ((char *) hdr) + (pktlength - length), 0, length); + if (!opt || !opt->dst1opt) + skb->h.raw =3D ((char *) hdr) + (pktlength - length); =20 if (!err) { IP6_INC_STATS(Ip6OutRequests); @@ -683,7 +699,7 @@ * cleanup */ out: - ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr =3D=3D &np->daddr ? &np->dadd= r : NULL); + ip6_dst_store(sk, dst, fl->fl6_dst =3D=3D &np->daddr ? &np->daddr : NULL)= ; if (err > 0) err =3D np->recverr ? net_xmit_errno(err) : 0; return err; @@ -718,7 +734,7 @@ =20 static inline int ip6_forward_finish(struct sk_buff *skb) { - return skb->dst->output(skb); + return dst_output(skb); } =20 int ip6_forward(struct sk_buff *skb) @@ -730,6 +746,9 @@ if (ipv6_devconf.forwarding =3D=3D 0) goto error; =20 + if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) + goto drop; + skb->ip_summed =3D CHECKSUM_NONE; =20 /* @@ -764,6 +783,9 @@ return -ETIMEDOUT; } =20 + if (!xfrm6_route_forward(skb)) + goto drop; + /* IPv6 specs say nothing about it, but it is clear that we cannot send redirects to source routed frames. */ @@ -794,10 +816,10 @@ goto error; } =20 - if (skb->len > dst->pmtu) { + if (skb->len > dst_pmtu(dst)) { /* Again, force OUTPUT device used as source address */ skb->dev =3D dst->dev; - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev); + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_pmtu(dst), skb->dev); IP6_INC_STATS_BH(Ip6InTooBigErrors); kfree_skb(skb); return -EMSGSIZE; diff -Nru a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c --- a/net/ipv6/ipv6_sockglue.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/ipv6_sockglue.c Thu May 8 10:41:36 2003 @@ -47,6 +47,7 @@ #include #include #include +#include =20 #include =20 @@ -404,6 +405,10 @@ case IPV6_FLOWLABEL_MGR: retv =3D ipv6_flowlabel_opt(sk, optval, optlen); break; + case IPV6_IPSEC_POLICY: + case IPV6_XFRM_POLICY: + retv =3D xfrm_user_policy(sk, optname, optval, optlen); + break; =20 #ifdef CONFIG_NETFILTER default: @@ -482,7 +487,7 @@ lock_sock(sk); dst =3D sk_dst_get(sk); if (dst) { - val =3D dst->pmtu; + val =3D dst_pmtu(dst) - dst->header_len; dst_release(dst); } release_sock(sk); diff -Nru a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv6/ipv6_syms.c Thu May 8 10:41:38 2003 @@ -0,0 +1,5 @@ +#include +#include + +EXPORT_SYMBOL(xfrm6_rcv); +EXPORT_SYMBOL(xfrm6_clear_mutable_options); diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c --- a/net/ipv6/ndisc.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/ndisc.c Thu May 8 10:41:36 2003 @@ -71,6 +71,7 @@ #include #include =20 +#include #include #include =20 @@ -330,8 +331,6 @@ unsigned char ha[MAX_ADDR_LEN]; unsigned char *h_dest =3D NULL; =20 - skb_reserve(skb, (dev->hard_header_len + 15) & ~15); - if (dev->hard_header) { if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) { ndisc_mc_map(daddr, ha, dev, 1); @@ -368,10 +367,50 @@ * Send a Neighbour Advertisement */ =20 +int ndisc_output(struct sk_buff *skb) +{ + if (skb) { + struct neighbour *neigh =3D (skb->dst ? skb->dst->neighbour : NULL); + if (ndisc_build_ll_hdr(skb, skb->dev, &skb->nh.ipv6h->daddr, neigh, skb-= >len) =3D=3D 0) { + kfree_skb(skb); + return -EINVAL; + } + dev_queue_xmit(skb); + return 0; + } + return -EINVAL; +} + +static inline void ndisc_rt_init(struct rt6_info *rt, struct net_device *d= ev, + struct neighbour *neigh) +{ + rt->rt6i_dev =3D dev; + rt->rt6i_nexthop =3D neigh; + rt->rt6i_expires =3D 0; + rt->rt6i_flags =3D RTF_LOCAL; + rt->rt6i_metric =3D 0; + rt->rt6i_hoplimit =3D 255; + rt->u.dst.output =3D ndisc_output; +} + +static inline void ndisc_flow_init(struct flowi *fl, u8 type, + struct in6_addr *saddr, struct in6_addr *daddr) +{ + memset(fl, 0, sizeof(*fl)); + fl->fl6_src =3D saddr; + fl->fl6_dst =3D daddr; + fl->proto =3D IPPROTO_ICMPV6; + fl->fl_icmp_type =3D type; + fl->fl_icmp_code =3D 0; +} + void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, struct in6_addr *daddr, struct in6_addr *solicited_addr, - int router, int solicited, int override, int inc_opt)=20 + int router, int solicited, int override, int inc_opt)=20 { + struct flowi fl; + struct rt6_info *rt =3D NULL; + struct dst_entry* dst; static struct in6_addr tmpaddr; struct inet6_ifaddr *ifp; struct sock *sk =3D ndisc_socket->sk; @@ -383,6 +422,22 @@ =20 len =3D sizeof(struct icmp6hdr) + sizeof(struct in6_addr); =20 + rt =3D ip6_dst_alloc(); + if (!rt)=20 + return; + + ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, solicited_addr, daddr= ); + ndisc_rt_init(rt, dev, neigh);=09 + + dst =3D (struct dst_entry*)rt; + dst_clone(dst); + + err =3D xfrm_lookup(&dst, &fl, NULL, 0); + if (err < 0) { + dst_release(dst); + return; + } + if (inc_opt) { if (dev->addr_len) len +=3D NDISC_OPT_SPACE(dev->addr_len); @@ -408,14 +463,10 @@ src_addr =3D &tmpaddr; } =20 - if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) =3D=3D 0) { - kfree_skb(skb); - return; - } - + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); ip6_nd_hdr(sk, skb, dev, src_addr, daddr, IPPROTO_ICMPV6, len); =20 - msg =3D (struct nd_msg *) skb_put(skb, len); + skb->h.raw =3D (unsigned char*) msg =3D (struct nd_msg *) skb_put(skb, le= n); =20 msg->icmph.icmp6_type =3D NDISC_NEIGHBOUR_ADVERTISEMENT; msg->icmph.icmp6_code =3D 0; @@ -438,7 +489,9 @@ csum_partial((__u8 *) msg,=20 len, 0)); =20 - dev_queue_xmit(skb); + dst_clone(dst); + skb->dst =3D dst; + dst_output(skb); =20 ICMP6_INC_STATS(Icmp6OutNeighborAdvertisements); ICMP6_INC_STATS(Icmp6OutMsgs); @@ -448,6 +501,9 @@ struct in6_addr *solicit, struct in6_addr *daddr, struct in6_addr *saddr)=20 { + struct flowi fl; + struct rt6_info *rt =3D NULL; + struct dst_entry* dst; struct sock *sk =3D ndisc_socket->sk; struct sk_buff *skb; struct nd_msg *msg; @@ -462,6 +518,22 @@ saddr =3D &addr_buf; } =20 + rt =3D ip6_dst_alloc(); + if (!rt)=20 + return; + + ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); + ndisc_rt_init(rt, dev, neigh);=09 + + dst =3D (struct dst_entry*)rt; + dst_clone(dst); + + err =3D xfrm_lookup(&dst, &fl, NULL, 0); + if (err < 0) { + dst_release(dst); + return; + } + len =3D sizeof(struct icmp6hdr) + sizeof(struct in6_addr); send_llinfo =3D dev->addr_len && ipv6_addr_type(saddr) !=3D IPV6_ADDR_ANY= ; if (send_llinfo) @@ -474,14 +546,10 @@ return; } =20 - if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) =3D=3D 0) { - kfree_skb(skb); - return; - } - + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); =20 - msg =3D (struct nd_msg *)skb_put(skb, len); + skb->h.raw =3D (unsigned char*) msg =3D (struct nd_msg *)skb_put(skb, len= ); msg->icmph.icmp6_type =3D NDISC_NEIGHBOUR_SOLICITATION; msg->icmph.icmp6_code =3D 0; msg->icmph.icmp6_cksum =3D 0; @@ -500,7 +568,9 @@ csum_partial((__u8 *) msg,=20 len, 0)); /* send it! */ - dev_queue_xmit(skb); + dst_clone(dst); + skb->dst =3D dst; + dst_output(skb); =20 ICMP6_INC_STATS(Icmp6OutNeighborSolicits); ICMP6_INC_STATS(Icmp6OutMsgs); @@ -509,6 +579,9 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr) { + struct flowi fl; + struct rt6_info *rt =3D NULL; + struct dst_entry* dst; struct sock *sk =3D ndisc_socket->sk; struct sk_buff *skb; struct icmp6hdr *hdr; @@ -516,6 +589,22 @@ int len; int err; =20 + rt =3D ip6_dst_alloc(); + if (!rt)=20 + return; + + ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); + ndisc_rt_init(rt, dev, NULL); + + dst =3D (struct dst_entry*)rt; + dst_clone(dst); + + err =3D xfrm_lookup(&dst, &fl, NULL, 0); + if (err < 0) { + dst_release(dst); + return; + } + len =3D sizeof(struct icmp6hdr); if (dev->addr_len) len +=3D NDISC_OPT_SPACE(dev->addr_len); @@ -527,14 +616,10 @@ return; } =20 - if (ndisc_build_ll_hdr(skb, dev, daddr, NULL, len) =3D=3D 0) { - kfree_skb(skb); - return; - } - + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); =20 - hdr =3D (struct icmp6hdr *) skb_put(skb, len); + skb->h.raw =3D (unsigned char*) hdr =3D (struct icmp6hdr *) skb_pu= t(skb, len); hdr->icmp6_type =3D NDISC_ROUTER_SOLICITATION; hdr->icmp6_code =3D 0; hdr->icmp6_cksum =3D 0; @@ -551,7 +636,9 @@ csum_partial((__u8 *) hdr, len, 0)); =20 /* send it! */ - dev_queue_xmit(skb); + dst_clone(dst); + skb->dst =3D dst; + dst_output(skb); =20 ICMP6_INC_STATS(Icmp6OutRouterSolicits); ICMP6_INC_STATS(Icmp6OutMsgs); @@ -1058,7 +1145,7 @@ in6_dev->cnf.mtu6 =3D mtu; =20 if (rt) - rt->u.dst.pmtu =3D mtu; + rt->u.dst.metrics[RTAX_MTU-1] =3D mtu; =20 rt6_mtu_change(skb->dev, mtu); } @@ -1181,6 +1268,8 @@ struct in6_addr *addrp; struct net_device *dev; struct rt6_info *rt; + struct dst_entry *dst; + struct flowi fl; u8 *opt; int rd_len; int err; @@ -1192,6 +1281,22 @@ if (rt =3D=3D NULL) return; =20 + dst =3D (struct dst_entry*)rt; + + if (ipv6_get_lladdr(dev, &saddr_buf)) { + ND_PRINTK1("redirect: no link_local addr for dev\n"); + return; + } + + ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr); + + dst_clone(dst); + err =3D xfrm_lookup(&dst, &fl, NULL, 0); + if (err) { + dst_release(dst); + return; + } + if (rt->rt6i_flags & RTF_GATEWAY) { ND_PRINTK1("ndisc_send_redirect: not a neighbour\n"); dst_release(&rt->u.dst); @@ -1220,11 +1325,6 @@ rd_len &=3D ~0x7; len +=3D rd_len; =20 - if (ipv6_get_lladdr(dev, &saddr_buf)) { - ND_PRINTK1("redirect: no link_local addr for dev\n"); - return; - } - buff =3D sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len = + 15, 1, &err); if (buff =3D=3D NULL) { @@ -1234,15 +1334,11 @@ =20 hlen =3D 0; =20 - if (ndisc_build_ll_hdr(buff, dev, &skb->nh.ipv6h->saddr, NULL, len) =3D= =3D 0) { - kfree_skb(buff); - return; - } - + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr, IPPROTO_ICMPV6, len); =20 - icmph =3D (struct icmp6hdr *) skb_put(buff, len); + skb->h.raw =3D (unsigned char*) icmph =3D (struct icmp6hdr *) skb_put(buf= f, len); =20 memset(icmph, 0, sizeof(struct icmp6hdr)); icmph->icmp6_type =3D NDISC_REDIRECT; @@ -1280,7 +1376,8 @@ len, IPPROTO_ICMPV6, csum_partial((u8 *) icmph, len, 0)); =20 - dev_queue_xmit(buff); + skb->dst =3D dst; + dst_output(skb); =20 ICMP6_INC_STATS(Icmp6OutRedirects); ICMP6_INC_STATS(Icmp6OutMsgs); diff -Nru a/net/ipv6/protocol.c b/net/ipv6/protocol.c --- a/net/ipv6/protocol.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/protocol.c Thu May 8 10:41:36 2003 @@ -42,77 +42,42 @@ =20 struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; =20 -void inet6_add_protocol(struct inet6_protocol *prot) +int inet6_add_protocol(struct inet6_protocol *prot, unsigned char protocol= ) { - unsigned char hash; - struct inet6_protocol *p2; + int ret, hash =3D protocol & (MAX_INET_PROTOS - 1); =20 - hash =3D prot->protocol & (MAX_INET_PROTOS - 1); br_write_lock_bh(BR_NETPROTO_LOCK); - prot->next =3D inet6_protos[hash]; - inet6_protos[hash] =3D prot; - prot->copy =3D 0; - - /* - * Set the copy bit if we need to.=20 - */ - =20 - p2 =3D (struct inet6_protocol *) prot->next; - while(p2 !=3D NULL) { - if (p2->protocol =3D=3D prot->protocol) { - prot->copy =3D 1; - break; - } - p2 =3D (struct inet6_protocol *) p2->next; + + if (inet6_protos[hash]) { + ret =3D -1; + } else { + inet6_protos[hash] =3D prot; + ret =3D 0; } + br_write_unlock_bh(BR_NETPROTO_LOCK); + + return ret; } =20 /* * Remove a protocol from the hash tables. */ =20 -int inet6_del_protocol(struct inet6_protocol *prot) +int inet6_del_protocol(struct inet6_protocol *prot, unsigned char protocol= ) { - struct inet6_protocol *p; - struct inet6_protocol *lp =3D NULL; - unsigned char hash; + int ret, hash =3D protocol & (MAX_INET_PROTOS - 1); =20 - hash =3D prot->protocol & (MAX_INET_PROTOS - 1); br_write_lock_bh(BR_NETPROTO_LOCK); - if (prot =3D=3D inet6_protos[hash]) { - inet6_protos[hash] =3D (struct inet6_protocol *) inet6_protos[hash]->nex= t; - br_write_unlock_bh(BR_NETPROTO_LOCK); - return(0); - } - - p =3D (struct inet6_protocol *) inet6_protos[hash]; =20 - if (p !=3D NULL && p->protocol =3D=3D prot->protocol) - lp =3D p; - - while(p !=3D NULL) { - /* - * We have to worry if the protocol being deleted is - * the last one on the list, then we may need to reset - * someone's copied bit. - */ - if (p->next !=3D NULL && p->next =3D=3D prot) { - /* - * if we are the last one with this protocol and - * there is a previous one, reset its copy bit. - */ - if (prot->copy =3D=3D 0 && lp !=3D NULL) - lp->copy =3D 0; - p->next =3D prot->next; - br_write_unlock_bh(BR_NETPROTO_LOCK); - return(0); - } - if (p->next !=3D NULL && p->next->protocol =3D=3D prot->protocol)=20 - lp =3D p->next; - - p =3D (struct inet6_protocol *) p->next; + if (inet6_protos[hash] !=3D prot) { + ret =3D -1; + } else { + inet6_protos[hash] =3D NULL; + ret =3D 0; } + br_write_unlock_bh(BR_NETPROTO_LOCK); - return(-1); + + return ret; } diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c --- a/net/ipv6/raw.c Thu May 8 10:41:37 2003 +++ b/net/ipv6/raw.c Thu May 8 10:41:37 2003 @@ -45,6 +45,7 @@ #include =20 #include +#include =20 struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE]; rwlock_t raw_v6_lock =3D RW_LOCK_UNLOCKED; @@ -133,12 +134,14 @@ * demultiplex raw sockets. * (should consider queueing the skb in the sock receive_queue * without calling rawv6.c) + * + * Caller owns SKB so we must make clones. */ -struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) +void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { struct in6_addr *saddr; struct in6_addr *daddr; - struct sock *sk, *sk2; + struct sock *sk; __u8 hash; =20 saddr =3D &skb->nh.ipv6h->saddr; @@ -159,30 +162,18 @@ =20 sk =3D __raw_v6_lookup(sk, nexthdr, daddr, saddr); =20 - if (sk) { - sk2 =3D sk; - - while ((sk2 =3D __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) { - struct sk_buff *buff; - - if (nexthdr =3D=3D IPPROTO_ICMPV6 && - icmpv6_filter(sk2, skb)) - continue; - - buff =3D skb_clone(skb, GFP_ATOMIC); - if (buff) - rawv6_rcv(sk2, buff); + while (sk) { + if (nexthdr !=3D IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) { + struct sk_buff *clone =3D skb_clone(skb, GFP_ATOMIC); + + /* Not releasing hash table! */ + if (clone) + rawv6_rcv(sk, clone); } + sk =3D __raw_v6_lookup(sk->next, nexthdr, daddr, saddr); } - - if (sk && nexthdr =3D=3D IPPROTO_ICMPV6 && icmpv6_filter(sk, skb)) - sk =3D NULL; - out: - if (sk) - sock_hold(sk); read_unlock(&raw_v6_lock); - return sk; } =20 /* This cleans up af_inet6 a bit. -DaveM */ @@ -309,6 +300,11 @@ */ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) { + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } + if (!sk->tp_pinfo.tp_raw.checksum) skb->ip_summed =3D CHECKSUM_UNNECESSARY; =20 @@ -620,8 +616,8 @@ fl.fl6_dst =3D daddr; if (fl.fl6_src =3D=3D NULL && !ipv6_addr_any(&np->saddr)) fl.fl6_src =3D &np->saddr; - fl.uli_u.icmpt.type =3D 0; - fl.uli_u.icmpt.code =3D 0; + fl.fl_icmp_type =3D 0; + fl.fl_icmp_code =3D 0; =09 if (raw_opt->checksum) { struct rawv6_fakehdr hdr; diff -Nru a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c --- a/net/ipv6/reassembly.c Thu May 8 10:41:37 2003 +++ b/net/ipv6/reassembly.c Thu May 8 10:41:37 2003 @@ -23,6 +23,7 @@ * Horst von Brand Add missing #include * Alexey Kuznetsov SMP races, threading, cleanup. * Patrick McHardy LRU queue of frag heads for evictor. + * Mitsuru KANDA @USAGI Register inet6_protocol{}. */ #include #include @@ -519,12 +520,13 @@ * the last and the first frames arrived and all the bits are here. */ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, + unsigned int *nhoffp, struct net_device *dev) { struct sk_buff *fp, *head =3D fq->fragments; int remove_fraghdr =3D 0; int payload_len; - int nhoff; + unsigned int nhoff; =20 fq_kill(fq); =20 @@ -611,7 +613,8 @@ =20 IP6_INC_STATS_BH(Ip6ReasmOKs); fq->fragments =3D NULL; - return nhoff; + *nhoffp =3D nhoff; + return 1; =20 out_oversize: if (net_ratelimit()) @@ -625,7 +628,7 @@ return -1; } =20 -int ipv6_reassembly(struct sk_buff **skbp, int nhoff) +static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) { struct sk_buff *skb =3D *skbp;=20 struct net_device *dev =3D skb->dev; @@ -655,7 +658,8 @@ skb->h.raw +=3D sizeof(struct frag_hdr); IP6_INC_STATS_BH(Ip6ReasmOKs); =20 - return (u8*)fhdr - skb->nh.raw; + *nhoffp =3D (u8*)fhdr - skb->nh.raw; + return 1; } =20 if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh) @@ -666,11 +670,11 @@ =20 spin_lock(&fq->lock); =20 - ip6_frag_queue(fq, skb, fhdr, nhoff); + ip6_frag_queue(fq, skb, fhdr, *nhoffp); =20 if (fq->last_in =3D=3D (FIRST_IN|LAST_IN) && fq->meat =3D=3D fq->len) - ret =3D ip6_frag_reasm(fq, skbp, dev); + ret =3D ip6_frag_reasm(fq, skbp, nhoffp, dev); =20 spin_unlock(&fq->lock); fq_put(fq); @@ -680,4 +684,16 @@ IP6_INC_STATS_BH(Ip6ReasmFails); kfree_skb(skb); return -1; +} + +static struct inet6_protocol frag_protocol =3D +{ + .handler =3D ipv6_frag_rcv, + .flags =3D INET6_PROTO_NOPOLICY, +}; + +void __init ipv6_frag_init(void) +{ + if (inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT) < 0) + printk(KERN_ERR "ipv6_frag_init: Could not register protocol\n"); } diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c --- a/net/ipv6/route.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/route.c Thu May 8 10:41:36 2003 @@ -38,6 +38,8 @@ #include #include #include +#include +#include =20 #include =20 @@ -45,8 +47,6 @@ #include #endif =20 -#undef CONFIG_RT6_POLICY - /* Set to 3 to get tracing. */ #define RT6_DEBUG 2 =20 @@ -69,39 +69,43 @@ =20 static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); -static struct dst_entry *ip6_dst_reroute(struct dst_entry *dst, - struct sk_buff *skb); static struct dst_entry *ip6_negative_advice(struct dst_entry *); static int ip6_dst_gc(void); =20 static int ip6_pkt_discard(struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb); +static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); =20 struct dst_ops ip6_dst_ops =3D { - AF_INET6, - __constant_htons(ETH_P_IPV6), - 1024, - - ip6_dst_gc, - ip6_dst_check, - ip6_dst_reroute, - NULL, - ip6_negative_advice, - ip6_link_failure, - sizeof(struct rt6_info), + .family =3D AF_INET6, + .protocol =3D __constant_htons(ETH_P_IPV6), + .gc =3D ip6_dst_gc, + .gc_thresh =3D 1024, + .check =3D ip6_dst_check, + .negative_advice =3D ip6_negative_advice, + .link_failure =3D ip6_link_failure, + .update_pmtu =3D ip6_rt_update_pmtu, + .entry_size =3D sizeof(struct rt6_info), }; =20 struct rt6_info ip6_null_entry =3D { - {{NULL, ATOMIC_INIT(1), 1, &loopback_dev, - -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -ENETUNREACH, NULL, NULL, - ip6_pkt_discard, ip6_pkt_discard, -#ifdef CONFIG_NET_CLS_ROUTE - 0, -#endif - &ip6_dst_ops}}, - NULL, {{{0}}}, RTF_REJECT|RTF_NONEXTHOP, ~0U, - 255, ATOMIC_INIT(1), {NULL}, {{{{0}}}, 0}, {{{{0}}}, 0} + .u =3D { + .dst =3D { + .__refcnt =3D ATOMIC_INIT(1), + .__use =3D 1, + .dev =3D &loopback_dev, + .obsolete =3D -1, + .error =3D -ENETUNREACH, + .input =3D ip6_pkt_discard, + .output =3D ip6_pkt_discard, + .ops =3D &ip6_dst_ops, + .path =3D (struct dst_entry*)&ip6_null_entry, + } + }, + .rt6i_flags =3D (RTF_REJECT | RTF_NONEXTHOP), + .rt6i_metric =3D ~(u32) 0, + .rt6i_hoplimit =3D 255, + .rt6i_ref =3D ATOMIC_INIT(1), }; =20 struct fib6_node ip6_routing_table =3D { @@ -110,29 +114,22 @@ 0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0 }; =20 -#ifdef CONFIG_RT6_POLICY -int ip6_rt_policy =3D 0; - -struct pol_chain *rt6_pol_list =3D NULL; - - -static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb); -static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk); - -static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt, - struct in6_addr *daddr, - struct in6_addr *saddr, - struct fl_acc_args *args); - -#else -#define ip6_rt_policy (0) -#endif - /* Protects all the ip6 fib */ =20 rwlock_t rt6_lock =3D RW_LOCK_UNLOCKED; =20 =20 +/* allocate dst with ip6_dst_ops */ +static __inline__ struct rt6_info *__ip6_dst_alloc(void) +{ + return dst_alloc(&ip6_dst_ops); +} + +struct rt6_info *ip6_dst_alloc(void) +{ + return __ip6_dst_alloc(); +} + /* * Route lookup. Any rt6_lock is implied. */ @@ -321,38 +318,6 @@ return &ip6_null_entry; } =20 -#ifdef CONFIG_RT6_POLICY -static __inline__ struct rt6_info *rt6_flow_lookup_in(struct rt6_info *rt, - struct sk_buff *skb) -{ - struct in6_addr *daddr, *saddr; - struct fl_acc_args arg; - - arg.type =3D FL_ARG_FORWARD; - arg.fl_u.skb =3D skb; - - saddr =3D &skb->nh.ipv6h->saddr; - daddr =3D &skb->nh.ipv6h->daddr; - - return rt6_flow_lookup(rt, daddr, saddr, &arg); -} - -static __inline__ struct rt6_info *rt6_flow_lookup_out(struct rt6_info *rt= , - struct sock *sk, - struct flowi *fl) -{ - struct fl_acc_args arg; - - arg.type =3D FL_ARG_ORIGIN; - arg.fl_u.fl_o.sk =3D sk; - arg.fl_u.fl_o.flow =3D fl; - - return rt6_flow_lookup(rt, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr, - &arg); -} - -#endif - #define BACKTRACK() \ if (rt =3D=3D &ip6_null_entry && strict) { \ while ((fn =3D fn->parent) !=3D NULL) { \ @@ -385,53 +350,29 @@ rt =3D fn->leaf; =20 if ((rt->rt6i_flags & RTF_CACHE)) { - if (ip6_rt_policy =3D=3D 0) { - rt =3D rt6_device_match(rt, skb->dev->ifindex, strict); - BACKTRACK(); - dst_hold(&rt->u.dst); - goto out; - } - -#ifdef CONFIG_RT6_POLICY - if ((rt->rt6i_flags & RTF_FLOW)) { - struct rt6_info *sprt; - - for (sprt =3D rt; sprt; sprt =3D sprt->u.next) { - if (rt6_flow_match_in(sprt, skb)) { - rt =3D sprt; - dst_hold(&rt->u.dst); - goto out; - } - } - } -#endif + rt =3D rt6_device_match(rt, skb->dev->ifindex, strict); + BACKTRACK(); + dst_hold(&rt->u.dst); + goto out; } =20 rt =3D rt6_device_match(rt, skb->dev->ifindex, 0); BACKTRACK(); =20 - if (ip6_rt_policy =3D=3D 0) { - if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { - read_unlock_bh(&rt6_lock); + if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { + read_unlock_bh(&rt6_lock); =20 - rt =3D rt6_cow(rt, &skb->nh.ipv6h->daddr, - &skb->nh.ipv6h->saddr); + rt =3D rt6_cow(rt, &skb->nh.ipv6h->daddr, + &skb->nh.ipv6h->saddr); =09 - if (rt->u.dst.error !=3D -EEXIST || --attempts <=3D 0) - goto out2; - /* Race condition! In the gap, when rt6_lock was - released someone could insert this route. Relookup. - */ - goto relookup; - } - dst_hold(&rt->u.dst); - } else { -#ifdef CONFIG_RT6_POLICY - rt =3D rt6_flow_lookup_in(rt, skb); -#else - /* NEVER REACHED */ -#endif + if (rt->u.dst.error !=3D -EEXIST || --attempts <=3D 0) + goto out2; + /* Race condition! In the gap, when rt6_lock was + released someone could insert this route. Relookup. + */ + goto relookup; } + dst_hold(&rt->u.dst); =20 out: read_unlock_bh(&rt6_lock); @@ -448,38 +389,21 @@ int strict; int attempts =3D 3; =20 - strict =3D ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IP= V6_ADDR_LINKLOCAL); + strict =3D ipv6_addr_type(fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_L= INKLOCAL); =20 relookup: read_lock_bh(&rt6_lock); =20 - fn =3D fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr, - fl->nl_u.ip6_u.saddr); + fn =3D fib6_lookup(&ip6_routing_table, fl->fl6_dst, fl->fl6_src); =20 restart: rt =3D fn->leaf; =20 if ((rt->rt6i_flags & RTF_CACHE)) { - if (ip6_rt_policy =3D=3D 0) { - rt =3D rt6_device_match(rt, fl->oif, strict); - BACKTRACK(); - dst_hold(&rt->u.dst); - goto out; - } - -#ifdef CONFIG_RT6_POLICY - if ((rt->rt6i_flags & RTF_FLOW)) { - struct rt6_info *sprt; - - for (sprt =3D rt; sprt; sprt =3D sprt->u.next) { - if (rt6_flow_match_out(sprt, sk)) { - rt =3D sprt; - dst_hold(&rt->u.dst); - goto out; - } - } - } -#endif + rt =3D rt6_device_match(rt, fl->oif, strict); + BACKTRACK(); + dst_hold(&rt->u.dst); + goto out; } if (rt->rt6i_flags & RTF_DEFAULT) { if (rt->rt6i_metric >=3D IP6_RT_PRIO_ADDRCONF) @@ -489,29 +413,20 @@ BACKTRACK(); } =20 - if (ip6_rt_policy =3D=3D 0) { - if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { - read_unlock_bh(&rt6_lock); + if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { + read_unlock_bh(&rt6_lock); =20 - rt =3D rt6_cow(rt, fl->nl_u.ip6_u.daddr, - fl->nl_u.ip6_u.saddr); - =09 - if (rt->u.dst.error !=3D -EEXIST || --attempts <=3D 0) - goto out2; + rt =3D rt6_cow(rt, fl->fl6_dst, fl->fl6_src); =20 - /* Race condition! In the gap, when rt6_lock was - released someone could insert this route. Relookup. - */ - goto relookup; - } - dst_hold(&rt->u.dst); - } else { -#ifdef CONFIG_RT6_POLICY - rt =3D rt6_flow_lookup_out(rt, sk, fl); -#else - /* NEVER REACHED */ -#endif + if (rt->u.dst.error !=3D -EEXIST || --attempts <=3D 0) + goto out2; + + /* Race condition! In the gap, when rt6_lock was + released someone could insert this route. Relookup. + */ + goto relookup; } + dst_hold(&rt->u.dst); =20 out: read_unlock_bh(&rt6_lock); @@ -539,16 +454,6 @@ return NULL; } =20 -static struct dst_entry *ip6_dst_reroute(struct dst_entry *dst, struct sk_= buff *skb) -{ - /* - * FIXME - */ - RDBG(("ip6_dst_reroute(%p,%p)[%p] (AIEEE)\n", dst, skb, - __builtin_return_address(0))); - return NULL; -} - static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) { struct rt6_info *rt =3D (struct rt6_info *) dst; @@ -578,6 +483,16 @@ } } =20 +static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) +{ + struct rt6_info *rt6 =3D (struct rt6_info*)dst; + + if (mtu < dst_pmtu(dst) && rt6->rt6i_dst.plen =3D=3D 128) { + rt6->rt6i_flags |=3D RTF_MODIFIED; + dst->metrics[RTAX_MTU-1] =3D mtu; + } +} + static int ip6_dst_gc() { static unsigned expire =3D 30*HZ; @@ -665,7 +580,7 @@ if (rtmsg->rtmsg_metric =3D=3D 0) rtmsg->rtmsg_metric =3D IP6_RT_PRIO_USER; =20 - rt =3D dst_alloc(&ip6_dst_ops); + rt =3D __ip6_dst_alloc(); =20 if (rt =3D=3D NULL) return -ENOMEM; @@ -792,14 +707,14 @@ rt->rt6i_flags =3D rtmsg->rtmsg_flags; =20 install_route: - rt->u.dst.pmtu =3D ipv6_get_mtu(dev); - rt->u.dst.advmss =3D max_t(unsigned int, rt->u.dst.pmtu - 60, ip6_rt_min_= advmss); + rt->u.dst.metrics[RTAX_MTU-1] =3D ipv6_get_mtu(dev); + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D max_t(unsigned int, dst_pmtu(&rt->u.= dst) - 60, ip6_rt_min_advmss); /* Maximal non-jumbo IPv6 payload is 65535 and corresponding MSS is 65535 - tcp_header_size. 65535 is also valid and means: "any MSS, rely only on pmtu discovery" */ - if (rt->u.dst.advmss > 65535-20) - rt->u.dst.advmss =3D 65535; + if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535-20) + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D 65535; rt->u.dst.dev =3D dev; return rt6_ins(rt, nlh); =20 @@ -951,10 +866,10 @@ ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); nrt->rt6i_nexthop =3D neigh_clone(neigh); /* Reset pmtu, it may be better */ - nrt->u.dst.pmtu =3D ipv6_get_mtu(neigh->dev); - nrt->u.dst.advmss =3D max_t(unsigned int, nrt->u.dst.pmtu - 60, ip6_rt_mi= n_advmss); - if (rt->u.dst.advmss > 65535-20) - rt->u.dst.advmss =3D 65535; + nrt->u.dst.metrics[RTAX_MTU-1] =3D ipv6_get_mtu(neigh->dev); + nrt->u.dst.metrics[RTAX_ADVMSS-1] =3D max_t(unsigned int, dst_pmtu(&nrt->= u.dst) - 60, ip6_rt_min_advmss); + if (nrt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20) + nrt->u.dst.metrics[RTAX_ADVMSS-1] =3D 65535; nrt->rt6i_hoplimit =3D ipv6_get_hoplimit(neigh->dev); =20 if (rt6_ins(nrt, NULL)) @@ -996,7 +911,7 @@ if (rt =3D=3D NULL) return; =20 - if (pmtu >=3D rt->u.dst.pmtu) + if (pmtu >=3D dst_pmtu(&rt->u.dst)) goto out; =20 /* New mtu received -> path was valid. @@ -1011,7 +926,7 @@ would return automatically. */ if (rt->rt6i_flags & RTF_CACHE) { - rt->u.dst.pmtu =3D pmtu; + rt->u.dst.metrics[RTAX_MTU-1] =3D pmtu; dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires); rt->rt6i_flags |=3D RTF_MODIFIED|RTF_EXPIRES; goto out; @@ -1025,7 +940,7 @@ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { nrt =3D rt6_cow(rt, daddr, saddr); if (!nrt->u.dst.error) { - nrt->u.dst.pmtu =3D pmtu; + nrt->u.dst.metrics[RTAX_MTU-1] =3D pmtu; /* According to RFC 1981, detecting PMTU increase shouldn't be happened within 5 mins, the recommended timer is 10 mins. Here this route expiration time is set to ip6_rt_mtu_expires=20 @@ -1046,7 +961,7 @@ nrt->rt6i_nexthop =3D neigh_clone(rt->rt6i_nexthop); dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); nrt->rt6i_flags |=3D RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES; - nrt->u.dst.pmtu =3D pmtu; + nrt->u.dst.metrics[RTAX_MTU-1] =3D pmtu; rt6_ins(nrt, NULL); } =20 @@ -1060,15 +975,13 @@ =20 static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { - struct rt6_info *rt; - - rt =3D dst_alloc(&ip6_dst_ops); + struct rt6_info *rt =3D __ip6_dst_alloc(); =20 if (rt) { rt->u.dst.input =3D ort->u.dst.input; rt->u.dst.output =3D ort->u.dst.output; =20 - memcpy(&rt->u.dst.mxlock, &ort->u.dst.mxlock, RTAX_MAX*sizeof(unsigned))= ; + memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); rt->u.dst.dev =3D ort->u.dst.dev; if (rt->u.dst.dev) dev_hold(rt->u.dst.dev); @@ -1206,9 +1119,8 @@ =20 int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) { - struct rt6_info *rt; + struct rt6_info *rt =3D __ip6_dst_alloc(); =20 - rt =3D dst_alloc(&ip6_dst_ops); if (rt =3D=3D NULL) return -ENOMEM; =20 @@ -1216,10 +1128,10 @@ rt->u.dst.input =3D ip6_input; rt->u.dst.output =3D ip6_output; rt->rt6i_dev =3D dev_get_by_name("lo"); - rt->u.dst.pmtu =3D ipv6_get_mtu(rt->rt6i_dev); - rt->u.dst.advmss =3D max_t(unsigned int, rt->u.dst.pmtu - 60, ip6_rt_min_= advmss); - if (rt->u.dst.advmss > 65535-20) - rt->u.dst.advmss =3D 65535; + rt->u.dst.metrics[RTAX_MTU-1] =3D ipv6_get_mtu(rt->rt6i_dev); + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D max_t(unsigned int, dst_pmtu(&rt->u.= dst) - 60, ip6_rt_min_advmss); + if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20) + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D 65535; rt->rt6i_hoplimit =3D ipv6_get_hoplimit(rt->rt6i_dev); rt->u.dst.obsolete =3D -1; =20 @@ -1256,122 +1168,6 @@ =20 return err; } - -#ifdef CONFIG_RT6_POLICY - -static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb) -{ - struct flow_filter *frule; - struct pkt_filter *filter; - int res =3D 1; - - if ((frule =3D rt->rt6i_filter) =3D=3D NULL) - goto out; - - if (frule->type !=3D FLR_INPUT) { - res =3D 0; - goto out; - } - - for (filter =3D frule->u.filter; filter; filter =3D filter->next) { - __u32 *word; - - word =3D (__u32 *) skb->h.raw; - word +=3D filter->offset; - - if ((*word ^ filter->value) & filter->mask) { - res =3D 0; - break; - } - } - -out: - return res; -} - -static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk) -{ - struct flow_filter *frule; - int res =3D 1; - - if ((frule =3D rt->rt6i_filter) =3D=3D NULL) - goto out; - - if (frule->type !=3D FLR_INPUT) { - res =3D 0; - goto out; - } - - if (frule->u.sk !=3D sk) - res =3D 0; -out: - return res; -} - -static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt, - struct in6_addr *daddr, - struct in6_addr *saddr, - struct fl_acc_args *args) -{ - struct flow_rule *frule; - struct rt6_info *nrt =3D NULL; - struct pol_chain *pol; - - for (pol =3D rt6_pol_list; pol; pol =3D pol->next) { - struct fib6_node *fn; - struct rt6_info *sprt; - - fn =3D fib6_lookup(pol->rules, daddr, saddr); - - do { - for (sprt =3D fn->leaf; sprt; sprt=3Dsprt->u.next) { - int res; - - frule =3D sprt->rt6i_flowr; -#if RT6_DEBUG >=3D 2 - if (frule =3D=3D NULL) { - printk(KERN_DEBUG "NULL flowr\n"); - goto error; - } -#endif - res =3D frule->ops->accept(rt, sprt, args, &nrt); - - switch (res) { - case FLOWR_SELECT: - goto found; - case FLOWR_CLEAR: - goto next_policy; - case FLOWR_NODECISION: - break; - default: - goto error; - }; - } - - fn =3D fn->parent; - - } while ((fn->fn_flags & RTN_TL_ROOT) =3D=3D 0); - - next_policy: - } - -error: - dst_hold(&ip6_null_entry.u.dst); - return &ip6_null_entry; - -found: - if (nrt =3D=3D NULL) - goto error; - - nrt->rt6i_flags |=3D RTF_CACHE; - dst_hold(&nrt->u.dst); - err =3D rt6_ins(nrt, NULL); - if (err) - nrt->u.dst.error =3D err; - return nrt; -} -#endif - static int fib6_ifdown(struct rt6_info *rt, void *arg) { if (((void*)rt->rt6i_dev =3D=3D arg || arg =3D=3D NULL) && @@ -1423,14 +1219,14 @@ PMTU discouvery.=20 */ if (rt->rt6i_dev =3D=3D arg->dev && - !(rt->u.dst.mxlock&(1<u.dst.pmtu > arg->mtu || - (rt->u.dst.pmtu < arg->mtu && - rt->u.dst.pmtu =3D=3D idev->cnf.mtu6))) - rt->u.dst.pmtu =3D arg->mtu; - rt->u.dst.advmss =3D max_t(unsigned int, arg->mtu - 60, ip6_rt_min_advmss= ); - if (rt->u.dst.advmss > 65535-20) - rt->u.dst.advmss =3D 65535; + !dst_metric_locked(&rt->u.dst, RTAX_MTU) && + (rt->u.dst.metrics[RTAX_MTU-1] > arg->mtu || + (rt->u.dst.metrics[RTAX_MTU-1] < arg->mtu && + rt->u.dst.metrics[RTAX_MTU-1] =3D=3D idev->cnf.mtu6))) + rt->u.dst.metrics[RTAX_MTU-1] =3D arg->mtu; + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D max_t(unsigned int, arg->mtu - 60, i= p6_rt_min_advmss); + if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20) + rt->u.dst.metrics[RTAX_ADVMSS-1] =3D 65535; return 0; } =20 @@ -1572,7 +1368,7 @@ if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) =3D=3D 0) RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } - if (rtnetlink_put_metrics(skb, &rt->u.dst.mxlock) < 0) + if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto rtattr_failure; if (rt->u.dst.neighbour) RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); @@ -1721,15 +1517,11 @@ skb->mac.raw =3D skb->data; skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); =20 - fl.proto =3D 0; - fl.nl_u.ip6_u.daddr =3D NULL; - fl.nl_u.ip6_u.saddr =3D NULL; - fl.uli_u.icmpt.type =3D 0; - fl.uli_u.icmpt.code =3D 0; + memset(&fl, 0, sizeof(fl)); if (rta[RTA_SRC-1]) - fl.nl_u.ip6_u.saddr =3D (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]); + fl.fl6_src =3D (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]); if (rta[RTA_DST-1]) - fl.nl_u.ip6_u.daddr =3D (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]); + fl.fl6_dst =3D (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]); =20 if (rta[RTA_IIF-1]) memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); @@ -1753,8 +1545,7 @@ =20 NETLINK_CB(skb).dst_pid =3D NETLINK_CB(in_skb).pid; err =3D rt6_fill_node(skb, rt,=20 - fl.nl_u.ip6_u.daddr, - fl.nl_u.ip6_u.saddr, + fl.fl6_dst, fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, nlh); @@ -1966,7 +1757,6 @@ =20 #endif =20 - void __init ip6_route_init(void) { ip6_dst_ops.kmem_cachep =3D kmem_cache_create("ip6_dst_cache", @@ -1978,6 +1768,7 @@ proc_net_create("ipv6_route", 0, rt6_proc_info); proc_net_create("rt6_stats", 0, rt6_proc_stats); #endif + xfrm6_init(); } =20 #ifdef MODULE @@ -1987,7 +1778,7 @@ proc_net_remove("ipv6_route"); proc_net_remove("rt6_stats"); #endif - + xfrm6_fini(); rt6_ifdown(NULL); fib6_gc_cleanup(); } diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c --- a/net/ipv6/sit.c Thu May 8 10:41:38 2003 +++ b/net/ipv6/sit.c Thu May 8 10:41:38 2003 @@ -422,13 +422,6 @@ return 0; } =20 -/* Need this wrapper because NF_HOOK takes the function address */ -static inline int do_ip_send(struct sk_buff *skb) -{ - return ip_send(skb); -} - - /* Returns the embedded IPv4 address if the IPv6 address comes from 6to4 (draft-ietf-ngtrans-6to4-04) addr space */ =20 @@ -501,9 +494,16 @@ dst =3D addr6->s6_addr32[3]; } =20 - if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.lin= k)) { - tunnel->stat.tx_carrier_errors++; - goto tx_error_icmp; + { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D dst, + .saddr =3D tiph->saddr, + .tos =3D RT_TOS(tos) } }, + .oif =3D tunnel->parms.link }; + if (ip_route_output_key(&rt, &fl)) { + tunnel->stat.tx_carrier_errors++; + goto tx_error_icmp; + } } if (rt->rt_type !=3D RTN_UNICAST) { tunnel->stat.tx_carrier_errors++; @@ -518,9 +518,9 @@ } =20 if (tiph->frag_off) - mtu =3D rt->u.dst.pmtu - sizeof(struct iphdr); + mtu =3D dst_pmtu(&rt->u.dst) - sizeof(struct iphdr); else - mtu =3D skb->dst ? skb->dst->pmtu : dev->mtu; + mtu =3D skb->dst ? dst_pmtu(skb->dst) : dev->mtu; =20 if (mtu < 68) { tunnel->stat.collisions++; @@ -529,15 +529,9 @@ } if (mtu < IPV6_MIN_MTU) mtu =3D IPV6_MIN_MTU; - if (skb->dst && mtu < skb->dst->pmtu) { - struct rt6_info *rt6 =3D (struct rt6_info*)skb->dst; - if (mtu < rt6->u.dst.pmtu) { - if (tunnel->parms.iph.daddr || rt6->rt6i_dst.plen =3D=3D 128) { - rt6->rt6i_flags |=3D RTF_MODIFIED; - rt6->u.dst.pmtu =3D mtu; - } - } - } + if (tunnel->parms.iph.daddr && skb->dst) + skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb->len > mtu) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); ip_rt_put(rt); @@ -557,7 +551,7 @@ /* * Okay, now see if we can stuff it in the buffer as-is. */ - max_headroom =3D (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr)); + max_headroom =3D LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr); =20 if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb= )) { struct sk_buff *new_skb =3D skb_realloc_headroom(skb, max_headroom); @@ -776,8 +770,13 @@ ipip6_tunnel_init_gen(dev); =20 if (iph->daddr) { + struct flowi fl =3D { .nl_u =3D { .ip4_u =3D + { .daddr =3D iph->daddr, + .saddr =3D iph->saddr, + .tos =3D RT_TOS(iph->tos) } }, + .oif =3D tunnel->parms.link }; struct rtable *rt; - if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunn= el->parms.link)) { + if (!ip_route_output_key(&rt, &fl)) { tdev =3D rt->u.dst.dev; ip_rt_put(rt); } @@ -834,19 +833,14 @@ } =20 static struct inet_protocol sit_protocol =3D { - ipip6_rcv, - ipip6_err, - 0, - IPPROTO_IPV6, - 0, - NULL, - "IPv6" + .handler =3D ipip6_rcv, + .err_handler =3D ipip6_err, }; =20 #ifdef MODULE void sit_cleanup(void) { - inet_del_protocol(&sit_protocol); + inet_del_protocol(&sit_protocol, IPPROTO_IPV6); unregister_netdev(&ipip6_fb_tunnel_dev); } #endif @@ -855,9 +849,13 @@ { printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); =20 + if (inet_add_protocol(&sit_protocol, IPPROTO_IPV6) < 0) { + printk(KERN_INFO "sit init: Can't add protocol\n"); + return -EAGAIN; + } + ipip6_fb_tunnel_dev.priv =3D (void*)&ipip6_fb_tunnel; strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name); register_netdev(&ipip6_fb_tunnel_dev); - inet_add_protocol(&sit_protocol); return 0; } diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c --- a/net/ipv6/tcp_ipv6.c Thu May 8 10:41:36 2003 +++ b/net/ipv6/tcp_ipv6.c Thu May 8 10:41:36 2003 @@ -38,6 +38,7 @@ #include #include #include +#include =20 #include #include @@ -647,14 +648,17 @@ fl.fl6_dst =3D &np->daddr; fl.fl6_src =3D saddr; fl.oif =3D sk->bound_dev_if; - fl.uli_u.ports.dport =3D usin->sin6_port; - fl.uli_u.ports.sport =3D sk->sport; + fl.fl_ip_dport =3D usin->sin6_port; + fl.fl_ip_sport =3D sk->sport; =20 if (np->opt && np->opt->srcrt) { struct rt0_hdr *rt0 =3D (struct rt0_hdr *) np->opt->srcrt; - fl.nl_u.ip6_u.daddr =3D rt0->addr; + fl.fl6_dst =3D rt0->addr; } =20 + if (!fl.fl6_src) + fl.fl6_src =3D &np->saddr; + dst =3D ip6_route_output(sk, &fl); =20 if ((err =3D dst->error) !=3D 0) { @@ -767,11 +771,11 @@ for now. */ fl.proto =3D IPPROTO_TCP; - fl.nl_u.ip6_u.daddr =3D &np->daddr; - fl.nl_u.ip6_u.saddr =3D &np->saddr; + fl.fl6_dst =3D &np->daddr; + fl.fl6_src =3D &np->saddr; fl.oif =3D sk->bound_dev_if; - fl.uli_u.ports.dport =3D sk->dport; - fl.uli_u.ports.sport =3D sk->sport; + fl.fl_ip_dport =3D sk->dport; + fl.fl_ip_sport =3D sk->sport; =20 dst =3D ip6_route_output(sk, &fl); } else @@ -779,8 +783,8 @@ =20 if (dst->error) { sk->err_soft =3D -dst->error; - } else if (tp->pmtu_cookie > dst->pmtu) { - tcp_sync_mss(sk, dst->pmtu); + } else if (tp->pmtu_cookie > dst_pmtu(dst)) { + tcp_sync_mss(sk, dst_pmtu(dst)); tcp_simple_retransmit(sk); } /* else let the usual retransmit timer handle it */ dst_release(dst); @@ -851,12 +855,12 @@ int err =3D -1; =20 fl.proto =3D IPPROTO_TCP; - fl.nl_u.ip6_u.daddr =3D &req->af.v6_req.rmt_addr; - fl.nl_u.ip6_u.saddr =3D &req->af.v6_req.loc_addr; + fl.fl6_dst =3D &req->af.v6_req.rmt_addr; + fl.fl6_src =3D &req->af.v6_req.loc_addr; fl.fl6_flowlabel =3D 0; fl.oif =3D req->af.v6_req.iif; - fl.uli_u.ports.dport =3D req->rmt_port; - fl.uli_u.ports.sport =3D sk->sport; + fl.fl_ip_dport =3D req->rmt_port; + fl.fl_ip_sport =3D sk->sport; =20 if (dst =3D=3D NULL) { opt =3D sk->net_pinfo.af_inet6.opt; @@ -871,7 +875,7 @@ =20 if (opt && opt->srcrt) { struct rt0_hdr *rt0 =3D (struct rt0_hdr *) opt->srcrt; - fl.nl_u.ip6_u.daddr =3D rt0->addr; + fl.fl6_dst =3D rt0->addr; } =20 dst =3D ip6_route_output(sk, &fl); @@ -887,7 +891,7 @@ &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr, csum_partial((char *)th, skb->len, skb->csum)); =20 - fl.nl_u.ip6_u.daddr =3D &req->af.v6_req.rmt_addr; + fl.fl6_dst =3D &req->af.v6_req.rmt_addr; err =3D ip6_xmit(sk, skb, &fl, opt); if (err =3D=3D NET_XMIT_CN) err =3D 0; @@ -988,19 +992,18 @@ =20 buff->csum =3D csum_partial((char *)t1, sizeof(*t1), 0); =20 - fl.nl_u.ip6_u.daddr =3D &skb->nh.ipv6h->saddr; - fl.nl_u.ip6_u.saddr =3D &skb->nh.ipv6h->daddr; + fl.fl6_dst =3D &skb->nh.ipv6h->saddr; + fl.fl6_src =3D &skb->nh.ipv6h->daddr; fl.fl6_flowlabel =3D 0; =20 - t1->check =3D csum_ipv6_magic(fl.nl_u.ip6_u.saddr, - fl.nl_u.ip6_u.daddr,=20 + t1->check =3D csum_ipv6_magic(fl.fl6_src, fl.fl6_dst,=20 sizeof(*t1), IPPROTO_TCP, buff->csum); =20 fl.proto =3D IPPROTO_TCP; fl.oif =3D tcp_v6_iif(skb); - fl.uli_u.ports.dport =3D t1->dest; - fl.uli_u.ports.sport =3D t1->source; + fl.fl_ip_dport =3D t1->dest; + fl.fl_ip_sport =3D t1->source; =20 /* sk =3D NULL, but it is safe for now. RST socket required. */ buff->dst =3D ip6_route_output(NULL, &fl); @@ -1055,19 +1058,18 @@ =20 buff->csum =3D csum_partial((char *)t1, tot_len, 0); =20 - fl.nl_u.ip6_u.daddr =3D &skb->nh.ipv6h->saddr; - fl.nl_u.ip6_u.saddr =3D &skb->nh.ipv6h->daddr; + fl.fl6_dst =3D &skb->nh.ipv6h->saddr; + fl.fl6_src =3D &skb->nh.ipv6h->daddr; fl.fl6_flowlabel =3D 0; =20 - t1->check =3D csum_ipv6_magic(fl.nl_u.ip6_u.saddr, - fl.nl_u.ip6_u.daddr,=20 + t1->check =3D csum_ipv6_magic(fl.fl6_src, fl.fl6_dst,=20 tot_len, IPPROTO_TCP, buff->csum); =20 fl.proto =3D IPPROTO_TCP; fl.oif =3D tcp_v6_iif(skb); - fl.uli_u.ports.dport =3D t1->dest; - fl.uli_u.ports.sport =3D t1->source; + fl.fl_ip_dport =3D t1->dest; + fl.fl_ip_sport =3D t1->source; =20 buff->dst =3D ip6_route_output(NULL, &fl); =20 @@ -1296,16 +1298,16 @@ =20 if (dst =3D=3D NULL) { fl.proto =3D IPPROTO_TCP; - fl.nl_u.ip6_u.daddr =3D &req->af.v6_req.rmt_addr; + fl.fl6_dst =3D &req->af.v6_req.rmt_addr; if (opt && opt->srcrt) { struct rt0_hdr *rt0 =3D (struct rt0_hdr *) opt->srcrt; - fl.nl_u.ip6_u.daddr =3D rt0->addr; + fl.fl6_dst =3D rt0->addr; } - fl.nl_u.ip6_u.saddr =3D &req->af.v6_req.loc_addr; + fl.fl6_src =3D &req->af.v6_req.loc_addr; fl.fl6_flowlabel =3D 0; fl.oif =3D sk->bound_dev_if; - fl.uli_u.ports.dport =3D req->rmt_port; - fl.uli_u.ports.sport =3D sk->sport; + fl.fl_ip_dport =3D req->rmt_port; + fl.fl_ip_sport =3D sk->sport; =20 dst =3D ip6_route_output(sk, &fl); } @@ -1372,8 +1374,8 @@ if (np->opt) newtp->ext_header_len =3D np->opt->opt_nflen + np->opt->opt_flen; =20 - tcp_sync_mss(newsk, dst->pmtu); - newtp->advmss =3D dst->advmss; + tcp_sync_mss(newsk, dst_pmtu(dst)); + newtp->advmss =3D dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(newsk); =20 newsk->daddr =3D LOOPBACK4_IPV6; @@ -1542,8 +1544,9 @@ return 0; } =20 -int tcp_v6_rcv(struct sk_buff *skb) +static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) { + struct sk_buff *skb =3D *pskb; struct tcphdr *th;=09 struct sock *sk; int ret; @@ -1586,11 +1589,12 @@ goto no_tcp_socket; =20 process: - if(!ipsec_sk_policy(sk,skb)) - goto discard_and_relse; if(sk->state =3D=3D TCP_TIME_WAIT) goto do_time_wait; =20 + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) + goto discard_and_relse; + if (sk_filter(sk, skb, 0)) goto discard_and_relse; =09 @@ -1606,9 +1610,12 @@ bh_unlock_sock(sk); =20 sock_put(sk); - return ret; + return ret ? -1 : 0; =20 no_tcp_socket: + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard_and_relse; + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); @@ -1630,6 +1637,10 @@ goto discard_it; =20 do_time_wait: + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { + sock_put(sk); + goto discard_it; + }=20 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); sock_put(sk); @@ -1674,16 +1685,16 @@ struct flowi fl; =20 fl.proto =3D IPPROTO_TCP; - fl.nl_u.ip6_u.daddr =3D &np->daddr; - fl.nl_u.ip6_u.saddr =3D &np->saddr; + fl.fl6_dst =3D &np->daddr; + fl.fl6_src =3D &np->saddr; fl.fl6_flowlabel =3D np->flow_label; fl.oif =3D sk->bound_dev_if; - fl.uli_u.ports.dport =3D sk->dport; - fl.uli_u.ports.sport =3D sk->sport; + fl.fl_ip_dport =3D sk->dport; + fl.fl_ip_sport =3D sk->sport; =20 if (np->opt && np->opt->srcrt) { struct rt0_hdr *rt0 =3D (struct rt0_hdr *) np->opt->srcrt; - fl.nl_u.ip6_u.daddr =3D rt0->addr; + fl.fl6_dst =3D rt0->addr; } =20 dst =3D ip6_route_output(sk, &fl); @@ -1715,12 +1726,12 @@ fl.fl6_flowlabel =3D np->flow_label; IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); fl.oif =3D sk->bound_dev_if; - fl.uli_u.ports.sport =3D sk->sport; - fl.uli_u.ports.dport =3D sk->dport; + fl.fl_ip_sport =3D sk->sport; + fl.fl_ip_dport =3D sk->dport; =20 if (np->opt && np->opt->srcrt) { struct rt0_hdr *rt0 =3D (struct rt0_hdr *) np->opt->srcrt; - fl.nl_u.ip6_u.daddr =3D rt0->addr; + fl.fl6_dst =3D rt0->addr; } =20 dst =3D __sk_dst_check(sk, np->dst_cookie); @@ -1740,7 +1751,7 @@ skb->dst =3D dst_clone(dst); =20 /* Restore final destination back after routing done */ - fl.nl_u.ip6_u.daddr =3D &np->daddr; + fl.fl6_dst =3D &np->daddr; =20 return ip6_xmit(sk, skb, &fl, np->opt); } @@ -1850,6 +1861,7 @@ static int tcp_v6_destroy_sock(struct sock *sk) { struct tcp_opt *tp =3D &(sk->tp_pinfo.af_tcp); + struct inet_opt *inet =3D inet_sk(sk); =20 tcp_clear_xmit_timers(sk); =20 @@ -1867,8 +1879,8 @@ tcp_put_port(sk); =20 /* If sendmsg cached page exists, toss it. */ - if (tp->sndmsg_page !=3D NULL) - __free_page(tp->sndmsg_page); + if (inet->sndmsg_page !=3D NULL) + __free_page(inet->sndmsg_page); =20 atomic_dec(&tcp_sockets_allocated); =20 @@ -2128,15 +2140,10 @@ get_port: tcp_v6_get_port, }; =20 -static struct inet6_protocol tcpv6_protocol =3D -{ - tcp_v6_rcv, /* TCP handler */ - tcp_v6_err, /* TCP error control */ - NULL, /* next */ - IPPROTO_TCP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "TCPv6" /* name */ +static struct inet6_protocol tcpv6_protocol =3D { + .handler =3D tcp_v6_rcv, + .err_handler =3D tcp_v6_err, + .flags =3D INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; =20 extern struct proto_ops inet6_stream_ops; @@ -2154,6 +2161,7 @@ void __init tcpv6_init(void) { /* register inet6 protocol */ - inet6_add_protocol(&tcpv6_protocol); + if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0) + printk(KERN_ERR "tcpv6_init: Could not register protocol\n"); inet6_register_protosw(&tcpv6_protosw); } diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c --- a/net/ipv6/udp.c Thu May 8 10:41:37 2003 +++ b/net/ipv6/udp.c Thu May 8 10:41:37 2003 @@ -50,6 +50,7 @@ #include =20 #include +#include =20 struct udp_mib udp_stats_in6[NR_CPUS*2]; =20 @@ -331,8 +332,8 @@ fl.fl6_dst =3D &np->daddr; fl.fl6_src =3D &saddr; fl.oif =3D sk->bound_dev_if; - fl.uli_u.ports.dport =3D sk->dport; - fl.uli_u.ports.sport =3D sk->sport; + fl.fl_ip_dport =3D sk->dport; + fl.fl_ip_sport =3D sk->sport; =20 if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) fl.oif =3D np->mcast_oif; @@ -517,6 +518,11 @@ =20 static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *sk= b) { + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + return -1; + } + #if defined(CONFIG_FILTER) if (sk->filter && skb->ip_summed !=3D CHECKSUM_UNNECESSARY) { if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))= ) { @@ -612,8 +618,9 @@ read_unlock(&udp_hash_lock); } =20 -int udpv6_rcv(struct sk_buff *skb) +static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) { + struct sk_buff *skb =3D *pskb; struct sock *sk; struct udphdr *uh; struct net_device *dev =3D skb->dev; @@ -680,6 +687,9 @@ sk =3D udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex); =20 if (sk =3D=3D NULL) { + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard; + if (skb->ip_summed !=3D CHECKSUM_UNNECESSARY && (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))= ) goto discard; @@ -903,8 +913,8 @@ fl.fl6_dst =3D daddr; if (fl.fl6_src =3D=3D NULL && !ipv6_addr_any(&np->saddr)) fl.fl6_src =3D &np->saddr; - fl.uli_u.ports.dport =3D udh.uh.dest; - fl.uli_u.ports.sport =3D udh.uh.source; + fl.fl_ip_dport =3D udh.uh.dest; + fl.fl_ip_sport =3D udh.uh.source; =20 err =3D ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit, msg->msg_flags); @@ -918,15 +928,10 @@ return ulen; } =20 -static struct inet6_protocol udpv6_protocol =3D=20 -{ - udpv6_rcv, /* UDP handler */ - udpv6_err, /* UDP error control */ - NULL, /* next */ - IPPROTO_UDP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "UDPv6" /* name */ +static struct inet6_protocol udpv6_protocol =3D { + .handler =3D udpv6_rcv, + .err_handler =3D udpv6_err, + .flags =3D INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; =20 #define LINE_LEN 190 @@ -1034,6 +1039,7 @@ =20 void __init udpv6_init(void) { - inet6_add_protocol(&udpv6_protocol); + if (inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP) < 0) + printk(KERN_ERR "udpv6_init: Could not register protocol\n"); inet6_register_protosw(&udpv6_protosw); } diff -Nru a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv6/xfrm6_input.c Thu May 8 10:41:38 2003 @@ -0,0 +1,271 @@ +/* + * xfrm6_input.c: based on net/ipv4/xfrm4_input.c + * + * Authors: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro + * YOSHIFUJI Hideaki @USAGI + * IPv6 support + */ + +#include +#include +#include + +static kmem_cache_t *secpath_cachep; + +static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr) +{ + u8 *opt =3D (u8 *)opthdr; + int len =3D ipv6_optlen(opthdr); + int off =3D 0; + int optlen =3D 0; + + off +=3D 2; + len -=3D 2; + + while (len > 0) { + + switch (opt[off]) { + + case IPV6_TLV_PAD0: + optlen =3D 1; + break; + default: + if (len < 2)=20 + goto bad; + optlen =3D opt[off+1]+2; + if (len < optlen) + goto bad; + if (opt[off] & 0x20) + memset(&opt[off+2], 0, opt[off+1]); + break; + } + + off +=3D optlen; + len -=3D optlen; + } + if (len =3D=3D 0) + return 1; + +bad: + return 0; +} + +int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int d= ir) +{ + u16 offset =3D sizeof(struct ipv6hdr); + struct ipv6_opt_hdr *exthdr =3D (struct ipv6_opt_hdr*)(skb->nh.raw + offs= et); + unsigned int packet_len =3D skb->tail - skb->nh.raw; + u8 nexthdr =3D skb->nh.ipv6h->nexthdr; + u8 nextnexthdr =3D 0; + + *nh_offset =3D ((unsigned char *)&skb->nh.ipv6h->nexthdr) - skb->nh.raw; + + while (offset + 1 <=3D packet_len) { + + switch (nexthdr) { + + case NEXTHDR_HOP: + *nh_offset =3D offset; + offset +=3D ipv6_optlen(exthdr); + if (!zero_out_mutable_opts(exthdr)) { + if (net_ratelimit()) + printk(KERN_WARNING "overrun hopopts\n");=20 + return 0; + } + nexthdr =3D exthdr->nexthdr; + exthdr =3D (struct ipv6_opt_hdr*)(skb->nh.raw + offset); + break; + + case NEXTHDR_ROUTING: + *nh_offset =3D offset; + offset +=3D ipv6_optlen(exthdr); + ((struct ipv6_rt_hdr*)exthdr)->segments_left =3D 0;=20 + nexthdr =3D exthdr->nexthdr; + exthdr =3D (struct ipv6_opt_hdr*)(skb->nh.raw + offset); + break; + + case NEXTHDR_DEST: + *nh_offset =3D offset; + offset +=3D ipv6_optlen(exthdr); + if (!zero_out_mutable_opts(exthdr)) { + if (net_ratelimit()) + printk(KERN_WARNING "overrun destopt\n");=20 + return 0; + } + nexthdr =3D exthdr->nexthdr; + exthdr =3D (struct ipv6_opt_hdr*)(skb->nh.raw + offset); + break; + + case NEXTHDR_AUTH: + if (dir =3D=3D XFRM_POLICY_OUT) { + memset(((struct ipv6_auth_hdr*)exthdr)->auth_data, 0,=20 + (((struct ipv6_auth_hdr*)exthdr)->hdrlen - 1) << 2); + } + if (exthdr->nexthdr =3D=3D NEXTHDR_DEST) { + offset +=3D (((struct ipv6_auth_hdr*)exthdr)->hdrlen + 2) << 2; + exthdr =3D (struct ipv6_opt_hdr*)(skb->nh.raw + offset); + nextnexthdr =3D exthdr->nexthdr; + if (!zero_out_mutable_opts(exthdr)) { + if (net_ratelimit()) + printk(KERN_WARNING "overrun destopt\n"); + return 0; + } + } + return nexthdr; + default : + return nexthdr; + } + } + + return nexthdr; +} + +int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +{ + struct sk_buff *skb =3D *pskb; + int err; + u32 spi, seq; + struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH]; + struct xfrm_state *x; + int xfrm_nr =3D 0; + int decaps =3D 0; + struct ipv6hdr *hdr =3D skb->nh.ipv6h; + unsigned char *tmp_hdr =3D NULL; + int hdr_len =3D 0; + u16 nh_offset =3D 0; + int nexthdr =3D 0; + + nh_offset =3D ((unsigned char*)&skb->nh.ipv6h->nexthdr) - skb->nh.raw; + hdr_len =3D sizeof(struct ipv6hdr); + + tmp_hdr =3D kmalloc(hdr_len, GFP_ATOMIC); + if (!tmp_hdr) + goto drop; + memcpy(tmp_hdr, skb->nh.raw, hdr_len); + + nexthdr =3D xfrm6_clear_mutable_options(skb, &nh_offset, XFRM_POLICY_IN); + hdr->priority =3D 0; + hdr->flow_lbl[0] =3D 0; + hdr->flow_lbl[1] =3D 0; + hdr->flow_lbl[2] =3D 0; + hdr->hop_limit =3D 0; + + if ((err =3D xfrm_parse_spi(skb, nexthdr, &spi, &seq)) !=3D 0) + goto drop; +=09 + do { + struct ipv6hdr *iph =3D skb->nh.ipv6h; + + if (xfrm_nr =3D=3D XFRM_MAX_DEPTH) + goto drop; + + x =3D xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_= INET6); + if (x =3D=3D NULL) + goto drop; + spin_lock(&x->lock); + if (unlikely(x->km.state !=3D XFRM_STATE_VALID)) + goto drop_unlock; + + if (x->props.replay_window && xfrm_replay_check(x, seq)) + goto drop_unlock; + + if (xfrm_state_check_expire(x)) + goto drop_unlock; + + nexthdr =3D x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb); + if (nexthdr <=3D 0) + goto drop_unlock; + + if (x->props.replay_window) + xfrm_replay_advance(x, seq); + + x->curlft.bytes +=3D skb->len; + x->curlft.packets++; + + spin_unlock(&x->lock); + + xfrm_vec[xfrm_nr++].xvec =3D x; + + iph =3D skb->nh.ipv6h; + + if (x->props.mode) { /* XXX */ + if (iph->nexthdr !=3D IPPROTO_IPV6) + goto drop; + skb->nh.raw =3D skb->data; + iph =3D skb->nh.ipv6h; + decaps =3D 1; + break; + } + + if ((err =3D xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) + goto drop; + } while (!err); + + if (!decaps) { + memcpy(skb->nh.raw, tmp_hdr, hdr_len); + skb->nh.raw[nh_offset] =3D nexthdr; + skb->nh.ipv6h->payload_len =3D htons(hdr_len + skb->len - sizeof(struct = ipv6hdr)); + } + + /* Allocate new secpath or COW existing one. */ + if (!skb->sp || atomic_read(&skb->sp->refcnt) !=3D 1) { + kmem_cache_t *pool =3D skb->sp ? skb->sp->pool : secpath_cachep; + struct sec_path *sp; + sp =3D kmem_cache_alloc(pool, SLAB_ATOMIC); + if (!sp) + goto drop; + if (skb->sp) { + memcpy(sp, skb->sp, sizeof(struct sec_path)); + secpath_put(skb->sp); + } else { + sp->pool =3D pool; + sp->len =3D 0; + } + atomic_set(&sp->refcnt, 1); + skb->sp =3D sp; + } + + if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) + goto drop; + + memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap= _state)); + skb->sp->len +=3D xfrm_nr; + skb->ip_summed =3D CHECKSUM_NONE; + + if (decaps) { + if (!(skb->dev->flags&IFF_LOOPBACK)) { + dst_release(skb->dst); + skb->dst =3D NULL; + } + netif_rx(skb); + return -1; + } else { + *nhoffp =3D nh_offset; + return 1; + } + +drop_unlock: + spin_unlock(&x->lock); + xfrm_state_put(x); +drop: + if (tmp_hdr) kfree(tmp_hdr); + while (--xfrm_nr >=3D 0) + xfrm_state_put(xfrm_vec[xfrm_nr].xvec); + kfree_skb(skb); + return -1; +} + +void __init xfrm6_input_init(void) +{ + secpath_cachep =3D kmem_cache_create("secpath6_cache", + sizeof(struct sec_path), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + + if (!secpath_cachep) + panic("IPv6: failed to allocate secpath6_cache\n"); +} + diff -Nru a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv6/xfrm6_policy.c Thu May 8 10:41:38 2003 @@ -0,0 +1,274 @@ +/* + * xfrm6_policy.c: based on xfrm4_policy.c + * + * Authors: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro + * IPv6 support + * YOSHIFUJI Hideaki + * Split up af-specific portion + *=20 + */ + +#include +#include +#include +#include +#include + +extern struct dst_ops xfrm6_dst_ops; +extern struct xfrm_policy_afinfo xfrm6_policy_afinfo; + +static struct xfrm_type_map xfrm6_type_map =3D { .lock =3D RW_LOCK_UNLOCKE= D }; + +int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) +{ + int err =3D 0; + *dst =3D (struct xfrm_dst*)ip6_route_output(NULL, fl); + if (!*dst) + err =3D -ENETUNREACH; + return err; +} + +/* Check that the bundle accepts the flow and its components are + * still valid. + */ + +static int __xfrm6_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl) +{ + do { + if (xdst->u.dst.ops !=3D &xfrm6_dst_ops) + return 1; + + if (!xfrm_selector_match(&xdst->u.dst.xfrm->sel, fl, AF_INET6)) + return 0; + if (xdst->u.dst.xfrm->km.state !=3D XFRM_STATE_VALID || + xdst->u.dst.path->obsolete > 0) + return 0; + xdst =3D (struct xfrm_dst*)xdst->u.dst.child; + } while (xdst); + return 0; +} + +static struct dst_entry * +__xfrm6_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_polic= y *policy) +{ + struct dst_entry *dst; + + /* Still not clear if we should set fl->fl6_{src,dst}... */ + read_lock_bh(&policy->lock); + for (dst =3D policy->bundles; dst; dst =3D dst->next) { + struct xfrm_dst *xdst =3D (struct xfrm_dst*)dst; + if (!ipv6_addr_cmp(&xdst->u.rt6.rt6i_dst.addr, fl->fl6_dst) && + !ipv6_addr_cmp(&xdst->u.rt6.rt6i_src.addr, fl->fl6_src) && + __xfrm6_bundle_ok(xdst, fl)) { + dst_clone(dst); + break; + } + } + read_unlock_bh(&policy->lock); + return dst; +} + +/* Allocate chain of dst_entry's, attach known xfrm's, calculate + * all the metrics... Shortly, bundle a bundle. + */ + +static int +__xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm= , int nx, + struct flowi *fl, struct dst_entry **dst_p) +{ + struct dst_entry *dst, *dst_prev; + struct rt6_info *rt0 =3D (struct rt6_info*)(*dst_p); + struct rt6_info *rt =3D rt0; + struct in6_addr *remote =3D fl->fl6_dst; + struct in6_addr *local =3D fl->fl6_src; + int i; + int err =3D 0; + int header_len =3D 0; + int trailer_len =3D 0; + + dst =3D dst_prev =3D NULL; + + for (i =3D 0; i < nx; i++) { + struct dst_entry *dst1 =3D dst_alloc(&xfrm6_dst_ops); + + if (unlikely(dst1 =3D=3D NULL)) { + err =3D -ENOBUFS; + goto error; + } + + dst1->xfrm =3D xfrm[i]; + if (!dst) + dst =3D dst1; + else { + dst_prev->child =3D dst1; + dst1->flags |=3D DST_NOHASH; + dst_clone(dst1); + } + dst_prev =3D dst1; + if (xfrm[i]->props.mode) { + remote =3D (struct in6_addr*)&xfrm[i]->id.daddr; + local =3D (struct in6_addr*)&xfrm[i]->props.saddr; + } + header_len +=3D xfrm[i]->props.header_len; + trailer_len +=3D xfrm[i]->props.trailer_len; + } + + if (ipv6_addr_cmp(remote, fl->fl6_dst)) { + struct flowi fl_tunnel =3D { .nl_u =3D { .ip6_u =3D + { .daddr =3D remote, + .saddr =3D local } + } + }; + err =3D xfrm_dst_lookup((struct xfrm_dst**)&rt, &fl_tunnel, AF_INET6); + if (err) + goto error; + } else { + dst_hold(&rt->u.dst); + } + dst_prev->child =3D &rt->u.dst; + for (dst_prev =3D dst; dst_prev !=3D &rt->u.dst; dst_prev =3D dst_prev->c= hild) { + struct xfrm_dst *x =3D (struct xfrm_dst*)dst_prev; + x->u.rt.fl =3D *fl; + + dst_prev->dev =3D rt->u.dst.dev; + if (rt->u.dst.dev) + dev_hold(rt->u.dst.dev); + dst_prev->obsolete =3D -1; + dst_prev->flags |=3D DST_HOST; + dst_prev->lastuse =3D jiffies; + dst_prev->header_len =3D header_len; + dst_prev->trailer_len =3D trailer_len; + memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics)= ); + dst_prev->path =3D &rt->u.dst; + + /* Copy neighbout for reachability confirmation */ + dst_prev->neighbour =3D neigh_clone(rt->u.dst.neighbour); + dst_prev->input =3D rt->u.dst.input; + dst_prev->output =3D dst_prev->xfrm->type->output; + /* Sheit... I remember I did this right. Apparently, + * it was magically lost, so this code needs audit */ + x->u.rt6.rt6i_flags =3D rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAS= T|RTCF_LOCAL); + x->u.rt6.rt6i_metric =3D rt0->rt6i_metric; + x->u.rt6.rt6i_node =3D rt0->rt6i_node; + x->u.rt6.rt6i_hoplimit =3D rt0->rt6i_hoplimit; + x->u.rt6.rt6i_gateway =3D rt0->rt6i_gateway; + memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_= gateway));=20 + header_len -=3D x->u.dst.xfrm->props.header_len; + trailer_len -=3D x->u.dst.xfrm->props.trailer_len; + } + *dst_p =3D dst; + return 0; + +error: + if (dst) + dst_free(dst); + return err; +} + +static inline void +_decode_session6(struct sk_buff *skb, struct flowi *fl) +{ + u16 offset =3D sizeof(struct ipv6hdr); + struct ipv6hdr *hdr =3D skb->nh.ipv6h; + struct ipv6_opt_hdr *exthdr =3D (struct ipv6_opt_hdr*)(skb->nh.raw + offs= et); + u8 nexthdr =3D skb->nh.ipv6h->nexthdr; + + fl->fl6_dst =3D &hdr->daddr; + fl->fl6_src =3D &hdr->saddr; + + while (pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) { + switch (nexthdr) { + case NEXTHDR_ROUTING: + case NEXTHDR_HOP: + case NEXTHDR_DEST: + offset +=3D ipv6_optlen(exthdr); + nexthdr =3D exthdr->nexthdr; + exthdr =3D (struct ipv6_opt_hdr*)(skb->nh.raw + offset); + break; + + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + if (pskb_may_pull(skb, skb->nh.raw + offset + 4 - skb->data)) { + u16 *ports =3D (u16 *)exthdr; + + fl->fl_ip_sport =3D ports[0]; + fl->fl_ip_dport =3D ports[1]; + } + return; + + /* XXX Why are there these headers? */ + case IPPROTO_AH: + case IPPROTO_ESP: + case IPPROTO_COMP: + default: + fl->fl_ipsec_spi =3D 0; + return; + }; + } +} + +static inline int xfrm6_garbage_collect(void) +{ + read_lock(&xfrm6_policy_afinfo.lock); + xfrm6_policy_afinfo.garbage_collect(); + read_unlock(&xfrm6_policy_afinfo.lock); + return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2); +} + +static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) +{ + struct dst_entry *path =3D dst->path; + + if (mtu >=3D 1280 && mtu < dst_pmtu(dst)) + return; + + path->ops->update_pmtu(path, mtu); +} + +struct dst_ops xfrm6_dst_ops =3D { + .family =3D AF_INET6, + .protocol =3D __constant_htons(ETH_P_IPV6), + .gc =3D xfrm6_garbage_collect, + .update_pmtu =3D xfrm6_update_pmtu, + .gc_thresh =3D 1024, + .entry_size =3D sizeof(struct xfrm_dst), +}; + +struct xfrm_policy_afinfo xfrm6_policy_afinfo =3D { + .family =3D AF_INET6, + .lock =3D RW_LOCK_UNLOCKED, + .type_map =3D &xfrm6_type_map, + .dst_ops =3D &xfrm6_dst_ops, + .dst_lookup =3D xfrm6_dst_lookup, + .find_bundle =3D __xfrm6_find_bundle, + .bundle_create =3D __xfrm6_bundle_create, + .decode_session =3D _decode_session6, +}; + +void __init xfrm6_policy_init(void) +{ + xfrm_policy_register_afinfo(&xfrm6_policy_afinfo); +} + +void __exit xfrm6_policy_fini(void) +{ + xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); +} + +void __init xfrm6_init(void) +{ + xfrm6_policy_init(); + xfrm6_state_init(); + xfrm6_input_init(); +} + +void __exit xfrm6_fini(void) +{ + //xfrm6_input_fini(); + xfrm6_policy_fini(); + xfrm6_state_fini(); +} diff -Nru a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv6/xfrm6_state.c Thu May 8 10:41:38 2003 @@ -0,0 +1,134 @@ +/* + * xfrm6_state.c: based on xfrm4_state.c + * + * Authors: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro + * IPv6 support + * YOSHIFUJI Hideaki @USAGI + * Split up af-specific portion + * =09 + */ + +#include +#include +#include +#include + +extern struct xfrm_state_afinfo xfrm6_state_afinfo; + +static void +__xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, + struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + /* Initialize temporary selector matching only + * to current session. */ + memcpy(&x->sel.daddr, fl->fl6_dst, sizeof(struct in6_addr)); + memcpy(&x->sel.saddr, fl->fl6_src, sizeof(struct in6_addr)); + x->sel.dport =3D fl->fl_ip_dport; + x->sel.dport_mask =3D ~0; + x->sel.sport =3D fl->fl_ip_sport; + x->sel.sport_mask =3D ~0; + x->sel.prefixlen_d =3D 128; + x->sel.prefixlen_s =3D 128; + x->sel.proto =3D fl->proto; + x->sel.ifindex =3D fl->oif; + x->id =3D tmpl->id; + if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) + memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); + memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); + if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) + memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); + x->props.mode =3D tmpl->mode; + x->props.reqid =3D tmpl->reqid; + x->props.family =3D AF_INET6; +} + +static struct xfrm_state * +__xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) +{ + unsigned h =3D __xfrm6_spi_hash(daddr, spi, proto); + struct xfrm_state *x; + + list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) { + if (x->props.family =3D=3D AF_INET6 && + spi =3D=3D x->id.spi && + !ipv6_addr_cmp((struct in6_addr *)daddr, (struct in6_addr *)x->id.da= ddr.a6) && + proto =3D=3D x->id.proto) { + atomic_inc(&x->refcnt); + return x; + } + } + return NULL; +} + +static struct xfrm_state * +__xfrm6_find_acq(u8 mode, u16 reqid, u8 proto,=20 + xfrm_address_t *daddr, xfrm_address_t *saddr,=20 + int create) +{ + struct xfrm_state *x, *x0; + unsigned h =3D __xfrm6_dst_hash(daddr); + + x0 =3D NULL; + + list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) { + if (x->props.family =3D=3D AF_INET6 && + !ipv6_addr_cmp((struct in6_addr *)daddr, (struct in6_addr *)x->id.da= ddr.a6) && + mode =3D=3D x->props.mode && + proto =3D=3D x->id.proto && + !ipv6_addr_cmp((struct in6_addr *)saddr, (struct in6_addr *)x->props= .saddr.a6) && + reqid =3D=3D x->props.reqid && + x->km.state =3D=3D XFRM_STATE_ACQ) { + if (!x0) + x0 =3D x; + if (x->id.spi) + continue; + x0 =3D x; + break; + } + } + if (x0) { + atomic_inc(&x0->refcnt); + } else if (create && (x0 =3D xfrm_state_alloc()) !=3D NULL) { + memcpy(x0->sel.daddr.a6, daddr, sizeof(struct in6_addr)); + memcpy(x0->sel.saddr.a6, saddr, sizeof(struct in6_addr)); + x0->sel.prefixlen_d =3D 128; + x0->sel.prefixlen_s =3D 128; + memcpy(x0->props.saddr.a6, saddr, sizeof(struct in6_addr)); + x0->km.state =3D XFRM_STATE_ACQ; + memcpy(x0->id.daddr.a6, daddr, sizeof(struct in6_addr)); + x0->id.proto =3D proto; + x0->props.family =3D AF_INET6; + x0->props.mode =3D mode; + x0->props.reqid =3D reqid; + x0->lft.hard_add_expires_seconds =3D XFRM_ACQ_EXPIRES; + atomic_inc(&x0->refcnt); + mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ); + atomic_inc(&x0->refcnt); + list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h); + wake_up(&km_waitq); + } + return x0; +} + +static struct xfrm_state_afinfo xfrm6_state_afinfo =3D { + .family =3D AF_INET6, + .lock =3D RW_LOCK_UNLOCKED, + .init_tempsel =3D __xfrm6_init_tempsel, + .state_lookup =3D __xfrm6_state_lookup, + .find_acq =3D __xfrm6_find_acq, +}; + +void __init xfrm6_state_init(void) +{ + xfrm_state_register_afinfo(&xfrm6_state_afinfo); +} + +void __exit xfrm6_state_fini(void) +{ + xfrm_state_unregister_afinfo(&xfrm6_state_afinfo); +} + diff -Nru a/net/key/Makefile b/net/key/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/key/Makefile Thu May 8 10:41:38 2003 @@ -0,0 +1,9 @@ +# +# Makefile for the key AF. +# + +O_TARGET :=3D key.o + +obj-$(CONFIG_NET_KEY) +=3D af_key.o + +include $(TOPDIR)/Rules.make diff -Nru a/net/key/af_key.c b/net/key/af_key.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/key/af_key.c Thu May 8 10:41:38 2003 @@ -0,0 +1,2868 @@ +/* + * net/key/af_key.c An implementation of PF_KEYv2 sockets. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Maxim Giryaev + * David S. Miller + * Alexey Kuznetsov + * Kunihiro Ishiguro + * Kazunori MIYAZAWA / USAGI Project + * Derek Atkins + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define _X2KEY(x) ((x) =3D=3D XFRM_INF ? 0 : (x)) +#define _KEY2X(x) ((x) =3D=3D 0 ? XFRM_INF : (x)) + + +/* List of all pfkey sockets. */ +static struct sock * pfkey_table; +static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait); +static rwlock_t pfkey_table_lock =3D RW_LOCK_UNLOCKED; +static atomic_t pfkey_table_users =3D ATOMIC_INIT(0); + +static atomic_t pfkey_socks_nr =3D ATOMIC_INIT(0); + +static void pfkey_sock_destruct(struct sock *sk) +{ + skb_queue_purge(&sk->receive_queue); + + if (!sk->dead) { + printk("Attempt to release alive pfkey socket: %p\n", sk); + return; + } + + BUG_TRAP(atomic_read(&sk->rmem_alloc)=3D=3D0); + BUG_TRAP(atomic_read(&sk->wmem_alloc)=3D=3D0); + + kfree(pfkey_sk(sk)); + + atomic_dec(&pfkey_socks_nr); + + MOD_DEC_USE_COUNT; +} + +static void pfkey_table_grab(void) +{ + write_lock_bh(&pfkey_table_lock); + + if (atomic_read(&pfkey_table_users)) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue_exclusive(&pfkey_table_wait, &wait); + for(;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (atomic_read(&pfkey_table_users) =3D=3D 0) + break; + write_unlock_bh(&pfkey_table_lock); + schedule(); + write_lock_bh(&pfkey_table_lock); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&pfkey_table_wait, &wait); + } +} + +static __inline__ void pfkey_table_ungrab(void) +{ + write_unlock_bh(&pfkey_table_lock); + wake_up(&pfkey_table_wait); +} + +static __inline__ void pfkey_lock_table(void) +{ + /* read_lock() synchronizes us to pfkey_table_grab */ + + read_lock(&pfkey_table_lock); + atomic_inc(&pfkey_table_users); + read_unlock(&pfkey_table_lock); +} + +static __inline__ void pfkey_unlock_table(void) +{ + if (atomic_dec_and_test(&pfkey_table_users)) + wake_up(&pfkey_table_wait); +} + + +static struct proto_ops pfkey_ops; + +static void pfkey_insert(struct sock *sk) +{ + pfkey_table_grab(); + sk->next =3D pfkey_table; + pfkey_table =3D sk; + sock_hold(sk); + pfkey_table_ungrab(); +} + +static void pfkey_remove(struct sock *sk) +{ + struct sock **skp; + + pfkey_table_grab(); + for (skp =3D &pfkey_table; *skp; skp =3D &((*skp)->next)) { + if (*skp =3D=3D sk) { + *skp =3D sk->next; + __sock_put(sk); + break; + } + } + pfkey_table_ungrab(); +} + +static int pfkey_create(struct socket *sock, int protocol) +{ + struct sock *sk; + struct pfkey_opt *pfk; + int err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (sock->type !=3D SOCK_RAW) + return -ESOCKTNOSUPPORT; + if (protocol !=3D PF_KEY_V2) + return -EPROTONOSUPPORT; + + MOD_INC_USE_COUNT; + + err =3D -ENOMEM; + sk =3D sk_alloc(PF_KEY, GFP_KERNEL, 1); + if (sk =3D=3D NULL) + goto out; + + sock->ops =3D &pfkey_ops; + sock_init_data(sock, sk); + + err =3D -ENOMEM; + pfk =3D pfkey_sk(sk) =3D kmalloc(sizeof(*pfk), GFP_KERNEL); + if (!pfk) { + sk_free(sk); + goto out; + } + memset(pfk, 0, sizeof(*pfk)); + + sk->family =3D PF_KEY; + sk->destruct =3D pfkey_sock_destruct; + + atomic_inc(&pfkey_socks_nr); + + pfkey_insert(sk); + + return 0; + +out: + MOD_DEC_USE_COUNT; + return err; +} + +static int pfkey_release(struct socket *sock) +{ + struct sock *sk =3D sock->sk; + + if (!sk) + return 0; + + pfkey_remove(sk); + + sock_orphan(sk); + sock->sk =3D NULL; + skb_queue_purge(&sk->write_queue); + sock_put(sk); + + return 0; +} + +static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, + int allocation, struct sock *sk) +{ + int err =3D -ENOBUFS; + + sock_hold(sk); + if (*skb2 =3D=3D NULL) { + if (atomic_read(&skb->users) !=3D 1) { + *skb2 =3D skb_clone(skb, allocation); + } else { + *skb2 =3D skb; + atomic_inc(&skb->users); + } + } + if (*skb2 !=3D NULL) { + if (atomic_read(&sk->rmem_alloc) <=3D sk->rcvbuf) { + skb_orphan(*skb2); + skb_set_owner_r(*skb2, sk); + skb_queue_tail(&sk->receive_queue, *skb2); + sk->data_ready(sk, (*skb2)->len); + *skb2 =3D NULL; + err =3D 0; + } + } + sock_put(sk); + return err; +} + +/* Send SKB to all pfkey sockets matching selected criteria. */ +#define BROADCAST_ALL 0 +#define BROADCAST_ONE 1 +#define BROADCAST_REGISTERED 2 +#define BROADCAST_PROMISC_ONLY 4 +static int pfkey_broadcast(struct sk_buff *skb, int allocation, + int broadcast_flags, struct sock *one_sk) +{ + struct sock *sk; + struct sk_buff *skb2 =3D NULL; + int err =3D -ESRCH; + + /* XXX Do we need something like netlink_overrun? I think + * XXX PF_KEY socket apps will not mind current behavior. + */ + if (!skb) + return -ENOMEM; + + pfkey_lock_table(); + for (sk =3D pfkey_table; sk; sk =3D sk->next) { + struct pfkey_opt *pfk =3D pfkey_sk(sk); + int err2; + + /* Yes, it means that if you are meant to receive this + * pfkey message you receive it twice as promiscuous + * socket. + */ + if (pfk->promisc) + pfkey_broadcast_one(skb, &skb2, allocation, sk); + + /* the exact target will be processed later */ + if (sk =3D=3D one_sk) + continue; + if (broadcast_flags !=3D BROADCAST_ALL) { + if (broadcast_flags & BROADCAST_PROMISC_ONLY) + continue; + if ((broadcast_flags & BROADCAST_REGISTERED) && + !pfk->registered) + continue; + if (broadcast_flags & BROADCAST_ONE) + continue; + } + + err2 =3D pfkey_broadcast_one(skb, &skb2, allocation, sk); + + /* Error is cleare after succecful sending to at least one + * registered KM */ + if ((broadcast_flags & BROADCAST_REGISTERED) && err) + err =3D err2; + } + pfkey_unlock_table(); + + if (one_sk !=3D NULL) + err =3D pfkey_broadcast_one(skb, &skb2, allocation, one_sk); + + if (skb2) + kfree_skb(skb2); + kfree_skb(skb); + return err; +} + +static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *or= ig) +{ + *new =3D *orig; +} + +static int pfkey_error(struct sadb_msg *orig, int err, struct sock *sk) +{ + struct sk_buff *skb =3D alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNE= L); + struct sadb_msg *hdr; + + if (!skb) + return -ENOBUFS; + + /* Woe be to the platform trying to support PFKEY yet + * having normal errnos outside the 1-255 range, inclusive. + */ + err =3D -err; + if (err =3D=3D ERESTARTSYS || + err =3D=3D ERESTARTNOHAND || + err =3D=3D ERESTARTNOINTR) + err =3D EINTR; + if (err >=3D 512) + err =3D EINVAL; + if (err <=3D 0 || err >=3D 256) + BUG(); + + hdr =3D (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); + pfkey_hdr_dup(hdr, orig); + hdr->sadb_msg_errno =3D (uint8_t) err; + hdr->sadb_msg_len =3D (sizeof(struct sadb_msg) / + sizeof(uint64_t)); + + pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk); + + return 0; +} + +static u8 sadb_ext_min_len[] =3D { + [SADB_EXT_RESERVED] =3D (u8) 0, + [SADB_EXT_SA] =3D (u8) sizeof(struct sadb_sa), + [SADB_EXT_LIFETIME_CURRENT] =3D (u8) sizeof(struct sadb_lifetime), + [SADB_EXT_LIFETIME_HARD] =3D (u8) sizeof(struct sadb_lifetime), + [SADB_EXT_LIFETIME_SOFT] =3D (u8) sizeof(struct sadb_lifetime), + [SADB_EXT_ADDRESS_SRC] =3D (u8) sizeof(struct sadb_address), + [SADB_EXT_ADDRESS_DST] =3D (u8) sizeof(struct sadb_address), + [SADB_EXT_ADDRESS_PROXY] =3D (u8) sizeof(struct sadb_address), + [SADB_EXT_KEY_AUTH] =3D (u8) sizeof(struct sadb_key), + [SADB_EXT_KEY_ENCRYPT] =3D (u8) sizeof(struct sadb_key), + [SADB_EXT_IDENTITY_SRC] =3D (u8) sizeof(struct sadb_ident), + [SADB_EXT_IDENTITY_DST] =3D (u8) sizeof(struct sadb_ident), + [SADB_EXT_SENSITIVITY] =3D (u8) sizeof(struct sadb_sens), + [SADB_EXT_PROPOSAL] =3D (u8) sizeof(struct sadb_prop), + [SADB_EXT_SUPPORTED_AUTH] =3D (u8) sizeof(struct sadb_supported), + [SADB_EXT_SUPPORTED_ENCRYPT] =3D (u8) sizeof(struct sadb_supported), + [SADB_EXT_SPIRANGE] =3D (u8) sizeof(struct sadb_spirange), + [SADB_X_EXT_KMPRIVATE] =3D (u8) sizeof(struct sadb_x_kmprivate), + [SADB_X_EXT_POLICY] =3D (u8) sizeof(struct sadb_x_policy), + [SADB_X_EXT_SA2] =3D (u8) sizeof(struct sadb_x_sa2), + [SADB_X_EXT_NAT_T_TYPE] =3D (u8) sizeof(struct sadb_x_nat_t_type), + [SADB_X_EXT_NAT_T_SPORT] =3D (u8) sizeof(struct sadb_x_nat_t_port), + [SADB_X_EXT_NAT_T_DPORT] =3D (u8) sizeof(struct sadb_x_nat_t_port), + [SADB_X_EXT_NAT_T_OA] =3D (u8) sizeof(struct sadb_address), +}; + +/* Verify sadb_address_{len,prefixlen} against sa_family. */ +static int verify_address_len(void *p) +{ + struct sadb_address *sp =3D p; + struct sockaddr *addr =3D (struct sockaddr *)(sp + 1); + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + int len; + + switch (addr->sa_family) { + case AF_INET: + len =3D sizeof(*sp) + sizeof(*sin) + (sizeof(uint64_t) - 1); + len /=3D sizeof(uint64_t); + if (sp->sadb_address_len !=3D len || + sp->sadb_address_prefixlen > 32) + return -EINVAL; + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + len =3D sizeof(*sp) + sizeof(*sin6) + (sizeof(uint64_t) - 1); + len /=3D sizeof(uint64_t); + if (sp->sadb_address_len !=3D len || + sp->sadb_address_prefixlen > 128) + return -EINVAL; + break; +#endif + default: + /* It is user using kernel to keep track of security + * associations for another protocol, such as + * OSPF/RSVP/RIPV2/MIP. It is user's job to verify + * lengths. + * + * XXX Actually, association/policy database is not yet + * XXX able to cope with arbitrary sockaddr families. + * XXX When it can, remove this -EINVAL. -DaveM + */ + return -EINVAL; + break; + }; + + return 0; +} + +static int present_and_same_family(struct sadb_address *src, + struct sadb_address *dst) +{ + struct sockaddr *s_addr, *d_addr; + + if (!src || !dst) + return 0; + + s_addr =3D (struct sockaddr *)(src + 1); + d_addr =3D (struct sockaddr *)(dst + 1); + if (s_addr->sa_family !=3D d_addr->sa_family) + return 0; + if (s_addr->sa_family !=3D AF_INET +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + && s_addr->sa_family !=3D AF_INET6 +#endif + ) + return 0; + + return 1; +} + +static int parse_exthdrs(struct sk_buff *skb, struct sadb_msg *hdr, void *= *ext_hdrs) +{ + char *p =3D (char *) hdr; + int len =3D skb->len; + + len -=3D sizeof(*hdr); + p +=3D sizeof(*hdr); + while (len > 0) { + struct sadb_ext *ehdr =3D (struct sadb_ext *) p; + uint16_t ext_type; + int ext_len; + + ext_len =3D ehdr->sadb_ext_len; + ext_len *=3D sizeof(uint64_t); + ext_type =3D ehdr->sadb_ext_type; + if (ext_len < sizeof(uint64_t) || + ext_len > len || + ext_type =3D=3D SADB_EXT_RESERVED) + return -EINVAL; + + if (ext_type <=3D SADB_EXT_MAX) { + int min =3D (int) sadb_ext_min_len[ext_type]; + if (ext_len < min) + return -EINVAL; + if (ext_hdrs[ext_type-1] !=3D NULL) + return -EINVAL; + if (ext_type =3D=3D SADB_EXT_ADDRESS_SRC || + ext_type =3D=3D SADB_EXT_ADDRESS_DST || + ext_type =3D=3D SADB_EXT_ADDRESS_PROXY || + ext_type =3D=3D SADB_X_EXT_NAT_T_OA) { + if (verify_address_len(p)) + return -EINVAL; + } =09 + ext_hdrs[ext_type-1] =3D p; + } + p +=3D ext_len; + len -=3D ext_len; + } + + return 0; +} + +static uint16_t +pfkey_satype2proto(uint8_t satype) +{ + switch (satype) { + case SADB_SATYPE_UNSPEC: + return IPSEC_PROTO_ANY; + case SADB_SATYPE_AH: + return IPPROTO_AH; + case SADB_SATYPE_ESP: + return IPPROTO_ESP; + case SADB_X_SATYPE_IPCOMP: + return IPPROTO_COMP; + break; + default: + return 0; + } + /* NOTREACHED */ +} + +static uint8_t +pfkey_proto2satype(uint16_t proto) +{ + switch (proto) { + case IPPROTO_AH: + return SADB_SATYPE_AH; + case IPPROTO_ESP: + return SADB_SATYPE_ESP; + case IPPROTO_COMP: + return SADB_X_SATYPE_IPCOMP; + break; + default: + return 0; + } + /* NOTREACHED */ +} + +/* BTW, this scheme means that there is no way with PFKEY2 sockets to + * say specifically 'just raw sockets' as we encode them as 255. + */ + +static uint8_t pfkey_proto_to_xfrm(uint8_t proto) +{ + return (proto =3D=3D IPSEC_PROTO_ANY ? 0 : proto); +} + +static uint8_t pfkey_proto_from_xfrm(uint8_t proto) +{ + return (proto ? proto : IPSEC_PROTO_ANY); +} + +static int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, + xfrm_address_t *xaddr) +{ + switch (((struct sockaddr*)(addr + 1))->sa_family) { + case AF_INET: + xaddr->a4 =3D=20 + ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr; + return AF_INET; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + memcpy(xaddr->a6,=20 + &((struct sockaddr_in6 *)(addr + 1))->sin6_addr, + sizeof(struct in6_addr)); + return AF_INET6; +#endif + default: + return 0; + } + /* NOTREACHED */ +} + +static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, v= oid **ext_hdrs) +{ + struct sadb_sa *sa; + struct sadb_address *addr; + uint16_t proto; + unsigned short family; + xfrm_address_t *xaddr; + + sa =3D (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; + if (sa =3D=3D NULL) + return NULL; + + proto =3D pfkey_satype2proto(hdr->sadb_msg_satype); + if (proto =3D=3D 0) + return NULL; + + /* sadb_address_len should be checked by caller */ + addr =3D (struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1]; + if (addr =3D=3D NULL) + return NULL; + + family =3D ((struct sockaddr *)(addr + 1))->sa_family; + switch (family) { + case AF_INET: + xaddr =3D (xfrm_address_t *)&((struct sockaddr_in *)(addr + 1))->sin_add= r; + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + xaddr =3D (xfrm_address_t *)&((struct sockaddr_in6 *)(addr + 1))->sin6_a= ddr; + break; +#endif + default: + xaddr =3D NULL; + } + + if (!xaddr) + return NULL; + + return xfrm_state_lookup(xaddr, sa->sadb_sa_spi, proto, family); +} + +#define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) +static int +pfkey_sockaddr_size(sa_family_t family) +{ + switch (family) { + case AF_INET: + return PFKEY_ALIGN8(sizeof(struct sockaddr_in)); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + return PFKEY_ALIGN8(sizeof(struct sockaddr_in6)); +#endif + default: + return 0; + } + /* NOTREACHED */ +} + +static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add= _keys, int hsc) +{ + struct sk_buff *skb; + struct sadb_msg *hdr; + struct sadb_sa *sa; + struct sadb_lifetime *lifetime; + struct sadb_address *addr; + struct sadb_key *key; + struct sadb_x_sa2 *sa2; + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + int size; + int auth_key_size =3D 0; + int encrypt_key_size =3D 0; + int sockaddr_size; + struct xfrm_encap_tmpl *natt =3D NULL; + + /* address family check */ + sockaddr_size =3D pfkey_sockaddr_size(x->props.family); + if (!sockaddr_size) + ERR_PTR(-EINVAL); + + /* base, SA, (lifetime (HSC),) address(SD), (address(P),) + key(AE), (identity(SD),) (sensitivity)> */ + size =3D sizeof(struct sadb_msg) +sizeof(struct sadb_sa) +=20 + sizeof(struct sadb_lifetime) + + ((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) + + ((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) + + sizeof(struct sadb_address)*2 +=20 + sockaddr_size*2 + + sizeof(struct sadb_x_sa2); + /* identity & sensitivity */ + + if ((x->props.family =3D=3D AF_INET && + x->sel.saddr.a4 !=3D x->props.saddr.a4) +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + || (x->props.family =3D=3D AF_INET6 && + memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr))) +#endif + ) + size +=3D sizeof(struct sadb_address) + sockaddr_size; + + if (add_keys) { + if (x->aalg && x->aalg->alg_key_len) { + auth_key_size =3D=20 + PFKEY_ALIGN8((x->aalg->alg_key_len + 7) / 8);=20 + size +=3D sizeof(struct sadb_key) + auth_key_size; + } + if (x->ealg && x->ealg->alg_key_len) { + encrypt_key_size =3D=20 + PFKEY_ALIGN8((x->ealg->alg_key_len+7) / 8);=20 + size +=3D sizeof(struct sadb_key) + encrypt_key_size; + } + } + if (x->encap) + natt =3D x->encap; + + if (natt && natt->encap_type) { + size +=3D sizeof(struct sadb_x_nat_t_type); + size +=3D sizeof(struct sadb_x_nat_t_port); + size +=3D sizeof(struct sadb_x_nat_t_port); + } + + skb =3D alloc_skb(size + 16, GFP_ATOMIC); + if (skb =3D=3D NULL) + return ERR_PTR(-ENOBUFS); + + /* call should fill header later */ + hdr =3D (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); + memset(hdr, 0, size); /* XXX do we need this ? */ + hdr->sadb_msg_len =3D size / sizeof(uint64_t); + + /* sa */ + sa =3D (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); + sa->sadb_sa_len =3D sizeof(struct sadb_sa)/sizeof(uint64_t); + sa->sadb_sa_exttype =3D SADB_EXT_SA; + sa->sadb_sa_spi =3D x->id.spi; + sa->sadb_sa_replay =3D x->props.replay_window; + sa->sadb_sa_state =3D SADB_SASTATE_DYING; + if (x->km.state =3D=3D XFRM_STATE_VALID && !x->km.dying) + sa->sadb_sa_state =3D SADB_SASTATE_MATURE; + else if (x->km.state =3D=3D XFRM_STATE_ACQ) + sa->sadb_sa_state =3D SADB_SASTATE_LARVAL; + else if (x->km.state =3D=3D XFRM_STATE_EXPIRED) + sa->sadb_sa_state =3D SADB_SASTATE_DEAD; + sa->sadb_sa_auth =3D 0; + if (x->aalg) { + struct xfrm_algo_desc *a =3D xfrm_aalg_get_byname(x->aalg->alg_name); + sa->sadb_sa_auth =3D a ? a->desc.sadb_alg_id : 0; + } + sa->sadb_sa_encrypt =3D 0; + BUG_ON(x->ealg && x->calg); + if (x->ealg) { + struct xfrm_algo_desc *a =3D xfrm_ealg_get_byname(x->ealg->alg_name); + sa->sadb_sa_encrypt =3D a ? a->desc.sadb_alg_id : 0; + } + /* KAME compatible: sadb_sa_encrypt is overloaded with calg id */ + if (x->calg) { + struct xfrm_algo_desc *a =3D xfrm_calg_get_byname(x->calg->alg_name); + sa->sadb_sa_encrypt =3D a ? a->desc.sadb_alg_id : 0; + } + + sa->sadb_sa_flags =3D 0; + + /* hard time */ + if (hsc & 2) { + lifetime =3D (struct sadb_lifetime *) skb_put(skb,=20 + sizeof(struct sadb_lifetime)); + lifetime->sadb_lifetime_len =3D + sizeof(struct sadb_lifetime)/sizeof(uint64_t); + lifetime->sadb_lifetime_exttype =3D SADB_EXT_LIFETIME_HARD; + lifetime->sadb_lifetime_allocations =3D _X2KEY(x->lft.hard_packet_limit= ); + lifetime->sadb_lifetime_bytes =3D _X2KEY(x->lft.hard_byte_limit); + lifetime->sadb_lifetime_addtime =3D x->lft.hard_add_expires_seconds; + lifetime->sadb_lifetime_usetime =3D x->lft.hard_use_expires_seconds; + } + /* soft time */ + if (hsc & 1) { + lifetime =3D (struct sadb_lifetime *) skb_put(skb,=20 + sizeof(struct sadb_lifetime)); + lifetime->sadb_lifetime_len =3D + sizeof(struct sadb_lifetime)/sizeof(uint64_t); + lifetime->sadb_lifetime_exttype =3D SADB_EXT_LIFETIME_SOFT; + lifetime->sadb_lifetime_allocations =3D _X2KEY(x->lft.soft_packet_limit= ); + lifetime->sadb_lifetime_bytes =3D _X2KEY(x->lft.soft_byte_limit); + lifetime->sadb_lifetime_addtime =3D x->lft.soft_add_expires_seconds; + lifetime->sadb_lifetime_usetime =3D x->lft.soft_use_expires_seconds; + } + /* current time */ + lifetime =3D (struct sadb_lifetime *) skb_put(skb, + sizeof(struct sadb_lifetime)); + lifetime->sadb_lifetime_len =3D + sizeof(struct sadb_lifetime)/sizeof(uint64_t); + lifetime->sadb_lifetime_exttype =3D SADB_EXT_LIFETIME_CURRENT; + lifetime->sadb_lifetime_allocations =3D x->curlft.packets; + lifetime->sadb_lifetime_bytes =3D x->curlft.bytes; + lifetime->sadb_lifetime_addtime =3D x->curlft.add_time; + lifetime->sadb_lifetime_usetime =3D x->curlft.use_time; + /* src address */ + addr =3D (struct sadb_address*) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_SRC; + /* "if the ports are non-zero, then the sadb_address_proto field,=20 + normally zero, MUST be filled in with the transport=20 + protocol's number." - RFC2367 */ + addr->sadb_address_proto =3D 0;=20 + addr->sadb_address_reserved =3D 0; + if (x->props.family =3D=3D AF_INET) { + addr->sadb_address_prefixlen =3D 32; + + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D x->props.saddr.a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (x->props.family =3D=3D AF_INET6) { + addr->sadb_address_prefixlen =3D 128; + + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, x->props.saddr.a6, + sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + } +#endif + else + BUG(); + + /* dst address */ + addr =3D (struct sadb_address*) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_DST; + addr->sadb_address_proto =3D 0;=20 + addr->sadb_address_prefixlen =3D 32; /* XXX */=20 + addr->sadb_address_reserved =3D 0; + if (x->props.family =3D=3D AF_INET) { + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D x->id.daddr.a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + + if (x->sel.saddr.a4 !=3D x->props.saddr.a4) { + addr =3D (struct sadb_address*) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_PROXY; + addr->sadb_address_proto =3D + pfkey_proto_from_xfrm(x->sel.proto); + addr->sadb_address_prefixlen =3D x->sel.prefixlen_s; + addr->sadb_address_reserved =3D 0; + + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D x->sel.saddr.a4; + sin->sin_port =3D x->sel.sport; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (x->props.family =3D=3D AF_INET6) { + addr->sadb_address_prefixlen =3D 128; + + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + + if (memcmp (x->sel.saddr.a6, x->props.saddr.a6, + sizeof(struct in6_addr))) { + addr =3D (struct sadb_address *) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_PROXY; + addr->sadb_address_proto =3D + pfkey_proto_from_xfrm(x->sel.proto); + addr->sadb_address_prefixlen =3D x->sel.prefixlen_s; + addr->sadb_address_reserved =3D 0; + + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D x->sel.sport; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, x->sel.saddr.a6, + sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + } + } +#endif + else + BUG(); + + /* auth key */ + if (add_keys && auth_key_size) { + key =3D (struct sadb_key *) skb_put(skb,=20 + sizeof(struct sadb_key)+auth_key_size); + key->sadb_key_len =3D (sizeof(struct sadb_key) + auth_key_size) / + sizeof(uint64_t); + key->sadb_key_exttype =3D SADB_EXT_KEY_AUTH; + key->sadb_key_bits =3D x->aalg->alg_key_len; + key->sadb_key_reserved =3D 0; + memcpy(key + 1, x->aalg->alg_key, (x->aalg->alg_key_len+7)/8); + } + /* encrypt key */ + if (add_keys && encrypt_key_size) { + key =3D (struct sadb_key *) skb_put(skb,=20 + sizeof(struct sadb_key)+encrypt_key_size); + key->sadb_key_len =3D (sizeof(struct sadb_key) +=20 + encrypt_key_size) / sizeof(uint64_t); + key->sadb_key_exttype =3D SADB_EXT_KEY_ENCRYPT; + key->sadb_key_bits =3D x->ealg->alg_key_len; + key->sadb_key_reserved =3D 0; + memcpy(key + 1, x->ealg->alg_key,=20 + (x->ealg->alg_key_len+7)/8); + } + + /* sa */ + sa2 =3D (struct sadb_x_sa2 *) skb_put(skb, sizeof(struct sadb_x_sa2)); + sa2->sadb_x_sa2_len =3D sizeof(struct sadb_x_sa2)/sizeof(uint64_t); + sa2->sadb_x_sa2_exttype =3D SADB_X_EXT_SA2; + sa2->sadb_x_sa2_mode =3D x->props.mode + 1; + sa2->sadb_x_sa2_reserved1 =3D 0; + sa2->sadb_x_sa2_reserved2 =3D 0; + sa2->sadb_x_sa2_sequence =3D 0; + sa2->sadb_x_sa2_reqid =3D x->props.reqid; + + if (natt && natt->encap_type) { + struct sadb_x_nat_t_type *n_type; + struct sadb_x_nat_t_port *n_port; + + /* type */ + n_type =3D (struct sadb_x_nat_t_type*) skb_put(skb, sizeof(*n_type)); + n_type->sadb_x_nat_t_type_len =3D sizeof(*n_type)/sizeof(uint64_t); + n_type->sadb_x_nat_t_type_exttype =3D SADB_X_EXT_NAT_T_TYPE; + n_type->sadb_x_nat_t_type_type =3D natt->encap_type; + n_type->sadb_x_nat_t_type_reserved[0] =3D 0; + n_type->sadb_x_nat_t_type_reserved[1] =3D 0; + n_type->sadb_x_nat_t_type_reserved[2] =3D 0; + + /* source port */ + n_port =3D (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); + n_port->sadb_x_nat_t_port_len =3D sizeof(*n_port)/sizeof(uint64_t); + n_port->sadb_x_nat_t_port_exttype =3D SADB_X_EXT_NAT_T_SPORT; + n_port->sadb_x_nat_t_port_port =3D natt->encap_sport; + n_port->sadb_x_nat_t_port_reserved =3D 0; + + /* dest port */ + n_port =3D (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); + n_port->sadb_x_nat_t_port_len =3D sizeof(*n_port)/sizeof(uint64_t); + n_port->sadb_x_nat_t_port_exttype =3D SADB_X_EXT_NAT_T_DPORT; + n_port->sadb_x_nat_t_port_port =3D natt->encap_dport; + n_port->sadb_x_nat_t_port_reserved =3D 0; + } + + return skb; +} + +static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,=20 + void **ext_hdrs) +{ + struct xfrm_state *x;=20 + struct sadb_lifetime *lifetime; + struct sadb_sa *sa; + struct sadb_key *key; + uint16_t proto; +=09 + + sa =3D (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; + if (!sa || + !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], + ext_hdrs[SADB_EXT_ADDRESS_DST-1])) + return ERR_PTR(-EINVAL); + if (hdr->sadb_msg_satype =3D=3D SADB_SATYPE_ESP && + !ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]) + return ERR_PTR(-EINVAL); + if (hdr->sadb_msg_satype =3D=3D SADB_SATYPE_AH && + !ext_hdrs[SADB_EXT_KEY_AUTH-1]) + return ERR_PTR(-EINVAL); + if (!!ext_hdrs[SADB_EXT_LIFETIME_HARD-1] !=3D + !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) + return ERR_PTR(-EINVAL); + + proto =3D pfkey_satype2proto(hdr->sadb_msg_satype); + if (proto =3D=3D 0) + return ERR_PTR(-EINVAL); + + /* RFC2367: + + Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message. + SADB_SASTATE_LARVAL SAs are created by SADB_GETSPI and it is not + sensible to add a new SA in the DYING or SADB_SASTATE_DEAD state. + Therefore, the sadb_sa_state field of all submitted SAs MUST be + SADB_SASTATE_MATURE and the kernel MUST return an error if this is + not true. + + However, KAME setkey always uses SADB_SASTATE_LARVAL. + Hence, we have to _ignore_ sadb_sa_state, which is also reasonable. + */ + if (sa->sadb_sa_auth > SADB_AALG_MAX || + (hdr->sadb_msg_satype =3D=3D SADB_X_SATYPE_IPCOMP && + sa->sadb_sa_encrypt > SADB_X_CALG_MAX) || + sa->sadb_sa_encrypt > SADB_EALG_MAX) + return ERR_PTR(-EINVAL); + key =3D (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; + if (key !=3D NULL && + sa->sadb_sa_auth !=3D SADB_X_AALG_NULL && + ((key->sadb_key_bits+7) / 8 =3D=3D 0 || + (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + return ERR_PTR(-EINVAL); + key =3D ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; + if (key !=3D NULL && + sa->sadb_sa_encrypt !=3D SADB_EALG_NULL && + ((key->sadb_key_bits+7) / 8 =3D=3D 0 || + (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + return ERR_PTR(-EINVAL); + + x =3D xfrm_state_alloc(); + if (x =3D=3D NULL) + return ERR_PTR(-ENOBUFS); + + x->id.proto =3D proto; + x->id.spi =3D sa->sadb_sa_spi; + x->props.replay_window =3D sa->sadb_sa_replay; + + lifetime =3D (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; + if (lifetime !=3D NULL) { + x->lft.hard_packet_limit =3D _KEY2X(lifetime->sadb_lifetime_allocations)= ; + x->lft.hard_byte_limit =3D _KEY2X(lifetime->sadb_lifetime_bytes); + x->lft.hard_add_expires_seconds =3D lifetime->sadb_lifetime_addtime; + x->lft.hard_use_expires_seconds =3D lifetime->sadb_lifetime_usetime; + } + lifetime =3D (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]; + if (lifetime !=3D NULL) { + x->lft.soft_packet_limit =3D _KEY2X(lifetime->sadb_lifetime_allocations)= ; + x->lft.soft_byte_limit =3D _KEY2X(lifetime->sadb_lifetime_bytes); + x->lft.soft_add_expires_seconds =3D lifetime->sadb_lifetime_addtime; + x->lft.soft_use_expires_seconds =3D lifetime->sadb_lifetime_usetime; + } + key =3D (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; + if (sa->sadb_sa_auth) { + int keysize =3D 0; + struct xfrm_algo_desc *a =3D xfrm_aalg_get_byid(sa->sadb_sa_auth); + if (!a) + goto out; + if (key) + keysize =3D (key->sadb_key_bits + 7) / 8; + x->aalg =3D kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL); + if (!x->aalg) + goto out; + strcpy(x->aalg->alg_name, a->name); + x->aalg->alg_key_len =3D 0; + if (key) { + x->aalg->alg_key_len =3D key->sadb_key_bits; + memcpy(x->aalg->alg_key, key+1, keysize); + } + x->props.aalgo =3D sa->sadb_sa_auth; + /* x->algo.flags =3D sa->sadb_sa_flags; */ + } + if (sa->sadb_sa_encrypt) { + if (hdr->sadb_msg_satype =3D=3D SADB_X_SATYPE_IPCOMP) { + struct xfrm_algo_desc *a =3D xfrm_calg_get_byid(sa->sadb_sa_encrypt); + if (!a) + goto out; + x->calg =3D kmalloc(sizeof(*x->calg), GFP_KERNEL); + if (!x->calg) + goto out; + strcpy(x->calg->alg_name, a->name); + x->props.calgo =3D sa->sadb_sa_encrypt; + } else { + int keysize =3D 0; + struct xfrm_algo_desc *a =3D xfrm_ealg_get_byid(sa->sadb_sa_encrypt); + if (!a) + goto out; + key =3D (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; + if (key) + keysize =3D (key->sadb_key_bits + 7) / 8; + x->ealg =3D kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL); + if (!x->ealg) + goto out; + strcpy(x->ealg->alg_name, a->name); + x->ealg->alg_key_len =3D 0; + if (key) { + x->ealg->alg_key_len =3D key->sadb_key_bits; + memcpy(x->ealg->alg_key, key+1, keysize); + } + x->props.ealgo =3D sa->sadb_sa_encrypt; + } + } + /* x->algo.flags =3D sa->sadb_sa_flags; */ + + x->props.family =3D pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext= _hdrs[SADB_EXT_ADDRESS_SRC-1],=20 + &x->props.saddr); + if (!x->props.family) + goto out; + pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRE= SS_DST-1],=20 + &x->id.daddr); + + if (ext_hdrs[SADB_X_EXT_SA2-1]) { + struct sadb_x_sa2 *sa2 =3D (void*)ext_hdrs[SADB_X_EXT_SA2-1]; + x->props.mode =3D sa2->sadb_x_sa2_mode; + if (x->props.mode) + x->props.mode--; + x->props.reqid =3D sa2->sadb_x_sa2_reqid; + } + + if (ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]) { + struct sadb_address *addr =3D ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]; + + /* Nobody uses this, but we try. */ + pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr); + x->sel.prefixlen_s =3D addr->sadb_address_prefixlen; + } + + if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) { + struct sadb_x_nat_t_type* n_type; + struct xfrm_encap_tmpl *natt; + + x->encap =3D kmalloc(sizeof(*x->encap), GFP_KERNEL); + if (!x->encap) + goto out; + + natt =3D x->encap; + n_type =3D ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]; + natt->encap_type =3D n_type->sadb_x_nat_t_type_type; + + if (ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]) { + struct sadb_x_nat_t_port* n_port =3D + ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]; + natt->encap_sport =3D n_port->sadb_x_nat_t_port_port; + } + if (ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]) { + struct sadb_x_nat_t_port* n_port =3D + ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]; + natt->encap_dport =3D n_port->sadb_x_nat_t_port_port; + } + } + + x->type =3D xfrm_get_type(proto, x->props.family); + if (x->type =3D=3D NULL) + goto out; + if (x->type->init_state(x, NULL)) + goto out; + x->km.seq =3D hdr->sadb_msg_seq; + x->km.state =3D XFRM_STATE_VALID; + return x; + +out: + if (x->aalg) + kfree(x->aalg); + if (x->ealg) + kfree(x->ealg); + if (x->calg) + kfree(x->calg); + if (x->encap) + kfree(x->encap); + kfree(x); + return ERR_PTR(-ENOBUFS); +} + +static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, struct sad= b_msg *hdr, void **ext_hdrs) +{ + return -EOPNOTSUPP; +} + +static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_= msg *hdr, void **ext_hdrs) +{ + struct sk_buff *resp_skb; + struct sadb_x_sa2 *sa2; + struct sadb_address *saddr, *daddr; + struct sadb_msg *out_hdr; + struct xfrm_state *x =3D NULL; + u8 mode; + u16 reqid; + u8 proto; + unsigned short family; + xfrm_address_t *xsaddr =3D NULL, *xdaddr =3D NULL; + + if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], + ext_hdrs[SADB_EXT_ADDRESS_DST-1])) + return -EINVAL; + + proto =3D pfkey_satype2proto(hdr->sadb_msg_satype); + if (proto =3D=3D 0) + return -EINVAL; + + if ((sa2 =3D ext_hdrs[SADB_X_EXT_SA2-1]) !=3D NULL) { + mode =3D sa2->sadb_x_sa2_mode - 1; + reqid =3D sa2->sadb_x_sa2_reqid; + } else { + mode =3D 0; + reqid =3D 0; + } + + saddr =3D ext_hdrs[SADB_EXT_ADDRESS_SRC-1]; + daddr =3D ext_hdrs[SADB_EXT_ADDRESS_DST-1]; + + family =3D ((struct sockaddr *)(saddr + 1))->sa_family; + switch (family) { + case AF_INET: + xdaddr =3D (xfrm_address_t *)&((struct sockaddr_in *)(daddr + 1))->sin_a= ddr.s_addr; + xsaddr =3D (xfrm_address_t *)&((struct sockaddr_in *)(saddr + 1))->sin_a= ddr.s_addr; + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + xdaddr =3D (xfrm_address_t *)&((struct sockaddr_in6 *)(daddr + 1))->sin6= _addr; + xsaddr =3D (xfrm_address_t *)&((struct sockaddr_in6 *)(saddr + 1))->sin6= _addr; + break; +#endif + } + if (xdaddr) + x =3D xfrm_find_acq(mode, reqid, proto, xdaddr, xsaddr, 1, family); + + if (x =3D=3D NULL) + return -ENOENT; + + resp_skb =3D ERR_PTR(-ENOENT); + + spin_lock_bh(&x->lock); + if (x->km.state !=3D XFRM_STATE_DEAD) { + struct sadb_spirange *range =3D ext_hdrs[SADB_EXT_SPIRANGE-1]; + u32 min_spi, max_spi; + + if (range !=3D NULL) { + min_spi =3D range->sadb_spirange_min; + max_spi =3D range->sadb_spirange_max; + } else { + min_spi =3D htonl(0x100); + max_spi =3D htonl(0x0fffffff); + } + xfrm_alloc_spi(x, min_spi, max_spi); + if (x->id.spi) + resp_skb =3D pfkey_xfrm_state2msg(x, 0, 3); + } + spin_unlock_bh(&x->lock); + + if (IS_ERR(resp_skb)) { + xfrm_state_put(x); + return PTR_ERR(resp_skb); + } + + out_hdr =3D (struct sadb_msg *) resp_skb->data; + out_hdr->sadb_msg_version =3D hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D SADB_GETSPI; + out_hdr->sadb_msg_satype =3D pfkey_proto2satype(proto); + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_reserved =3D 0; + out_hdr->sadb_msg_seq =3D hdr->sadb_msg_seq; + out_hdr->sadb_msg_pid =3D hdr->sadb_msg_pid; + + xfrm_state_put(x); + + pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk); + + return 0; +} + +static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb= _msg *hdr, void **ext_hdrs) +{ + struct xfrm_state *x; + + if (hdr->sadb_msg_len !=3D sizeof(struct sadb_msg)/8) + return -EOPNOTSUPP; + + if (hdr->sadb_msg_seq =3D=3D 0 || hdr->sadb_msg_errno =3D=3D 0) + return 0; + + x =3D xfrm_find_acq_byseq(hdr->sadb_msg_seq); + if (x =3D=3D NULL) + return 0; + + spin_lock_bh(&x->lock); + if (x->km.state =3D=3D XFRM_STATE_ACQ) { + x->km.state =3D XFRM_STATE_ERROR; + wake_up(&km_waitq); + } + spin_unlock_bh(&x->lock); + xfrm_state_put(x); + return 0; +} + + +static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg= *hdr, void **ext_hdrs) +{ + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + struct xfrm_state *x; + struct xfrm_state *x1; + + xfrm_probe_algs(); +=09 + x =3D pfkey_msg2xfrm_state(hdr, ext_hdrs); + if (IS_ERR(x)) + return PTR_ERR(x); + + /* XXX there is race condition */ + x1 =3D pfkey_xfrm_state_lookup(hdr, ext_hdrs); + if (!x1) { + x1 =3D xfrm_find_acq(x->props.mode, x->props.reqid, x->id.proto, + &x->id.daddr, + &x->props.saddr, 0, x->props.family); + if (x1 && x1->id.spi !=3D x->id.spi && x1->id.spi) { + xfrm_state_put(x1); + x1 =3D NULL; + } + } + + if (x1 && x1->id.spi && hdr->sadb_msg_type =3D=3D SADB_ADD) { + x->km.state =3D XFRM_STATE_DEAD; + xfrm_state_put(x); + xfrm_state_put(x1); + return -EEXIST; + } + + xfrm_state_insert(x); + + if (x1) { + xfrm_state_delete(x1); + xfrm_state_put(x1); + } + + out_skb =3D pfkey_xfrm_state2msg(x, 0, 3); + if (IS_ERR(out_skb)) + return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */ + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D hdr->sadb_msg_type; + out_hdr->sadb_msg_satype =3D pfkey_proto2satype(x->id.proto); + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_reserved =3D 0; + out_hdr->sadb_msg_seq =3D hdr->sadb_msg_seq; + out_hdr->sadb_msg_pid =3D hdr->sadb_msg_pid; + + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); + + return 0; +} + +static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_= msg *hdr, void **ext_hdrs) +{ + struct xfrm_state *x; + + if (!ext_hdrs[SADB_EXT_SA-1] || + !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], + ext_hdrs[SADB_EXT_ADDRESS_DST-1])) + return -EINVAL; + + x =3D pfkey_xfrm_state_lookup(hdr, ext_hdrs); + if (x =3D=3D NULL) + return -ESRCH; + + xfrm_state_delete(x); + xfrm_state_put(x); + + pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,=20 + BROADCAST_ALL, sk); + + return 0; +} + +static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg= *hdr, void **ext_hdrs) +{ + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + struct xfrm_state *x; + + if (!ext_hdrs[SADB_EXT_SA-1] || + !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], + ext_hdrs[SADB_EXT_ADDRESS_DST-1])) + return -EINVAL; + + x =3D pfkey_xfrm_state_lookup(hdr, ext_hdrs); + if (x =3D=3D NULL) + return -ESRCH; + + out_skb =3D pfkey_xfrm_state2msg(x, 1, 3); + xfrm_state_put(x); + if (IS_ERR(out_skb)) + return PTR_ERR(out_skb); + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D SADB_DUMP; + out_hdr->sadb_msg_satype =3D pfkey_proto2satype(x->id.proto); + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_reserved =3D 0; + out_hdr->sadb_msg_seq =3D hdr->sadb_msg_seq; + out_hdr->sadb_msg_pid =3D hdr->sadb_msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); + + return 0; +} + +static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, int a= llocation) +{ + struct sk_buff *skb; + struct sadb_msg *hdr; + int len, auth_len, enc_len, i; + + auth_len =3D xfrm_count_auth_supported(); + if (auth_len) { + auth_len *=3D sizeof(struct sadb_alg); + auth_len +=3D sizeof(struct sadb_supported); + } +=09 + enc_len =3D xfrm_count_enc_supported(); + if (enc_len) { + enc_len *=3D sizeof(struct sadb_alg); + enc_len +=3D sizeof(struct sadb_supported); + } +=09 + len =3D enc_len + auth_len + sizeof(struct sadb_msg); + + skb =3D alloc_skb(len + 16, allocation); + if (!skb) + goto out_put_algs; + + hdr =3D (struct sadb_msg *) skb_put(skb, sizeof(*hdr)); + pfkey_hdr_dup(hdr, orig); + hdr->sadb_msg_errno =3D 0; + hdr->sadb_msg_len =3D len / sizeof(uint64_t); + + if (auth_len) { + struct sadb_supported *sp; + struct sadb_alg *ap; + + sp =3D (struct sadb_supported *) skb_put(skb, auth_len); + ap =3D (struct sadb_alg *) (sp + 1); + + sp->sadb_supported_len =3D auth_len / sizeof(uint64_t); + sp->sadb_supported_exttype =3D SADB_EXT_SUPPORTED_AUTH; + + for (i =3D 0; ; i++) { + struct xfrm_algo_desc *aalg =3D xfrm_aalg_get_byidx(i); + if (!aalg) + break; + if (aalg->available) + *ap++ =3D aalg->desc; + } + } + + if (enc_len) { + struct sadb_supported *sp; + struct sadb_alg *ap; + + sp =3D (struct sadb_supported *) skb_put(skb, enc_len); + ap =3D (struct sadb_alg *) (sp + 1); + + sp->sadb_supported_len =3D enc_len / sizeof(uint64_t); + sp->sadb_supported_exttype =3D SADB_EXT_SUPPORTED_ENCRYPT; + + for (i =3D 0; ; i++) { + struct xfrm_algo_desc *ealg =3D xfrm_ealg_get_byidx(i); + if (!ealg) + break; + if (ealg->available) + *ap++ =3D ealg->desc; + } + } + +out_put_algs: + return skb; +} + +static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sad= b_msg *hdr, void **ext_hdrs) +{ + struct pfkey_opt *pfk =3D pfkey_sk(sk); + struct sk_buff *supp_skb; + + if (hdr->sadb_msg_satype > SADB_SATYPE_MAX) + return -EINVAL; + + if (hdr->sadb_msg_satype !=3D SADB_SATYPE_UNSPEC) { + if (pfk->registered&(1<sadb_msg_satype)) + return -EEXIST; + pfk->registered |=3D (1<sadb_msg_satype); + } + + xfrm_probe_algs(); +=09 + supp_skb =3D compose_sadb_supported(hdr, GFP_KERNEL); + if (!supp_skb) { + if (hdr->sadb_msg_satype !=3D SADB_SATYPE_UNSPEC) + pfk->registered &=3D ~(1<sadb_msg_satype); + + return -ENOBUFS; + } + + pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk); + + return 0; +} + +static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_m= sg *hdr, void **ext_hdrs) +{ + unsigned proto; + struct sk_buff *skb_out; + struct sadb_msg *hdr_out; + + proto =3D pfkey_satype2proto(hdr->sadb_msg_satype); + if (proto =3D=3D 0) + return -EINVAL; + + skb_out =3D alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); + if (!skb_out) + return -ENOBUFS; + + xfrm_state_flush(proto); + + hdr_out =3D (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg))= ; + pfkey_hdr_dup(hdr_out, hdr); + hdr_out->sadb_msg_errno =3D (uint8_t) 0; + hdr_out->sadb_msg_len =3D (sizeof(struct sadb_msg) / sizeof(uint64_t)); + + pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL); + + return 0; +} + +struct pfkey_dump_data +{ + struct sk_buff *skb; + struct sadb_msg *hdr; + struct sock *sk; +}; + +static int dump_sa(struct xfrm_state *x, int count, void *ptr) +{ + struct pfkey_dump_data *data =3D ptr; + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + + out_skb =3D pfkey_xfrm_state2msg(x, 1, 3); + if (IS_ERR(out_skb)) + return PTR_ERR(out_skb); + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D data->hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D SADB_DUMP; + out_hdr->sadb_msg_satype =3D pfkey_proto2satype(x->id.proto); + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_reserved =3D 0; + out_hdr->sadb_msg_seq =3D count; + out_hdr->sadb_msg_pid =3D data->hdr->sadb_msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); + return 0; +} + +static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_ms= g *hdr, void **ext_hdrs) +{ + u8 proto; + struct pfkey_dump_data data =3D { .skb =3D skb, .hdr =3D hdr, .sk =3D sk = }; + + proto =3D pfkey_satype2proto(hdr->sadb_msg_satype); + if (proto =3D=3D 0) + return -EINVAL; + + return xfrm_state_walk(proto, dump_sa, &data); +} + +static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb= _msg *hdr, void **ext_hdrs) +{ + struct pfkey_opt *pfk =3D pfkey_sk(sk); + int satype =3D hdr->sadb_msg_satype; + + if (hdr->sadb_msg_len =3D=3D (sizeof(*hdr) / sizeof(uint64_t))) { + /* XXX we mangle packet... */ + hdr->sadb_msg_errno =3D 0; + if (satype !=3D 0 && satype !=3D 1) + return -EINVAL; + pfk->promisc =3D satype; + } + pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NU= LL); + return 0; +} + +static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *p= tr) +{ + int i; + u16 reqid =3D *(u16*)ptr; + + for (i=3D0; ixfrm_nr; i++) { + if (xp->xfrm_vec[i].reqid =3D=3D reqid) + return -EEXIST; + } + return 0; +} + +static u16 gen_reqid(void) +{ + u16 start; + static u16 reqid =3D IPSEC_MANUAL_REQID_MAX; + + start =3D reqid; + do { + ++reqid; + if (reqid =3D=3D 0) + reqid =3D IPSEC_MANUAL_REQID_MAX+1; + if (xfrm_policy_walk(check_reqid, (void*)&reqid) !=3D -EEXIST) + return reqid; + } while (reqid !=3D start); + return 0; +} + +static int +parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) +{ + struct xfrm_tmpl *t =3D xp->xfrm_vec + xp->xfrm_nr; + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + + if (xp->xfrm_nr >=3D XFRM_MAX_DEPTH) + return -ELOOP; + + if (rq->sadb_x_ipsecrequest_mode =3D=3D 0) + return -EINVAL; + + t->id.proto =3D rq->sadb_x_ipsecrequest_proto; /* XXX check proto */ + t->mode =3D rq->sadb_x_ipsecrequest_mode-1; + if (rq->sadb_x_ipsecrequest_level =3D=3D IPSEC_LEVEL_USE) + t->optional =3D 1; + else if (rq->sadb_x_ipsecrequest_level =3D=3D IPSEC_LEVEL_UNIQUE) { + t->reqid =3D rq->sadb_x_ipsecrequest_reqid; + if (t->reqid > IPSEC_MANUAL_REQID_MAX) + t->reqid =3D 0; + if (!t->reqid && !(t->reqid =3D gen_reqid())) + return -ENOBUFS; + } + + /* addresses present only in tunnel mode */ + if (t->mode) { + switch (xp->family) { + case AF_INET: + sin =3D (void*)(rq+1); + if (sin->sin_family !=3D AF_INET) + return -EINVAL; + t->saddr.a4 =3D sin->sin_addr.s_addr; + sin++; + if (sin->sin_family !=3D AF_INET) + return -EINVAL; + t->id.daddr.a4 =3D sin->sin_addr.s_addr; + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + sin6 =3D (void *)(rq+1); + if (sin6->sin6_family !=3D AF_INET6) + return -EINVAL; + memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); + sin6++; + if (sin6->sin6_family !=3D AF_INET6) + return -EINVAL; + memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); + break; +#endif + default: + return -EINVAL; + } + } + /* No way to set this via kame pfkey */ + t->aalgos =3D t->ealgos =3D t->calgos =3D ~0; + xp->xfrm_nr++; + return 0; +} + +static int +parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol) +{ + int err; + int len =3D pol->sadb_x_policy_len*8 - sizeof(struct sadb_x_policy); + struct sadb_x_ipsecrequest *rq =3D (void*)(pol+1); + + while (len >=3D sizeof(struct sadb_x_ipsecrequest)) { + if ((err =3D parse_ipsecrequest(xp, rq)) < 0) + return err; + len -=3D rq->sadb_x_ipsecrequest_len; + rq =3D (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len); + } + return 0; +} + +static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp) +{ + int sockaddr_size =3D pfkey_sockaddr_size(xp->family); + int socklen =3D (xp->family =3D=3D AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + + return sizeof(struct sadb_msg) + + (sizeof(struct sadb_lifetime) * 3) + + (sizeof(struct sadb_address) * 2) +=20 + (sockaddr_size * 2) + + sizeof(struct sadb_x_policy) + + (xp->xfrm_nr * (sizeof(struct sadb_x_ipsecrequest) + + (socklen * 2))); +} + +static struct sk_buff * pfkey_xfrm_policy2msg_prep(struct xfrm_policy *xp) +{ + struct sk_buff *skb; + int size; + + size =3D pfkey_xfrm_policy2msg_size(xp); + + skb =3D alloc_skb(size + 16, GFP_ATOMIC); + if (skb =3D=3D NULL) + return ERR_PTR(-ENOBUFS); + + return skb; +} + +static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy = *xp, int dir) +{ + struct sadb_msg *hdr; + struct sadb_address *addr; + struct sadb_lifetime *lifetime; + struct sadb_x_policy *pol; + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + int i; + int size; + int sockaddr_size =3D pfkey_sockaddr_size(xp->family); + int socklen =3D (xp->family =3D=3D AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + + size =3D pfkey_xfrm_policy2msg_size(xp); + + /* call should fill header later */ + hdr =3D (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); + memset(hdr, 0, size); /* XXX do we need this ? */ + + /* src address */ + addr =3D (struct sadb_address*) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_SRC; + addr->sadb_address_proto =3D pfkey_proto_from_xfrm(xp->selector.proto); + addr->sadb_address_prefixlen =3D xp->selector.prefixlen_s; + addr->sadb_address_reserved =3D 0; + /* src address */ + if (xp->family =3D=3D AF_INET) { + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D xp->selector.saddr.a4; + sin->sin_port =3D xp->selector.sport; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (xp->family =3D=3D AF_INET6) { + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D xp->selector.sport; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, xp->selector.saddr.a6, + sizeof(struct in6_addr));; + sin6->sin6_scope_id =3D 0; + } +#endif + else + BUG(); + + /* dst address */ + addr =3D (struct sadb_address*) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_DST; + addr->sadb_address_proto =3D pfkey_proto_from_xfrm(xp->selector.proto); + addr->sadb_address_prefixlen =3D xp->selector.prefixlen_d;=20 + addr->sadb_address_reserved =3D 0; + if (xp->family =3D=3D AF_INET) { + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D xp->selector.daddr.a4; + sin->sin_port =3D xp->selector.dport; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (xp->family =3D=3D AF_INET6) { + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D xp->selector.dport; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, xp->selector.daddr.a6, + sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + } +#endif + else + BUG(); + + /* hard time */ + lifetime =3D (struct sadb_lifetime *) skb_put(skb,=20 + sizeof(struct sadb_lifetime)); + lifetime->sadb_lifetime_len =3D + sizeof(struct sadb_lifetime)/sizeof(uint64_t); + lifetime->sadb_lifetime_exttype =3D SADB_EXT_LIFETIME_HARD; + lifetime->sadb_lifetime_allocations =3D _X2KEY(xp->lft.hard_packet_limit= ); + lifetime->sadb_lifetime_bytes =3D _X2KEY(xp->lft.hard_byte_limit); + lifetime->sadb_lifetime_addtime =3D xp->lft.hard_add_expires_seconds; + lifetime->sadb_lifetime_usetime =3D xp->lft.hard_use_expires_seconds; + /* soft time */ + lifetime =3D (struct sadb_lifetime *) skb_put(skb,=20 + sizeof(struct sadb_lifetime)); + lifetime->sadb_lifetime_len =3D + sizeof(struct sadb_lifetime)/sizeof(uint64_t); + lifetime->sadb_lifetime_exttype =3D SADB_EXT_LIFETIME_SOFT; + lifetime->sadb_lifetime_allocations =3D _X2KEY(xp->lft.soft_packet_limit= ); + lifetime->sadb_lifetime_bytes =3D _X2KEY(xp->lft.soft_byte_limit); + lifetime->sadb_lifetime_addtime =3D xp->lft.soft_add_expires_seconds; + lifetime->sadb_lifetime_usetime =3D xp->lft.soft_use_expires_seconds; + /* current time */ + lifetime =3D (struct sadb_lifetime *) skb_put(skb,=20 + sizeof(struct sadb_lifetime)); + lifetime->sadb_lifetime_len =3D + sizeof(struct sadb_lifetime)/sizeof(uint64_t); + lifetime->sadb_lifetime_exttype =3D SADB_EXT_LIFETIME_CURRENT; + lifetime->sadb_lifetime_allocations =3D xp->curlft.packets; + lifetime->sadb_lifetime_bytes =3D xp->curlft.bytes; + lifetime->sadb_lifetime_addtime =3D xp->curlft.add_time; + lifetime->sadb_lifetime_usetime =3D xp->curlft.use_time; + + pol =3D (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_polic= y)); + pol->sadb_x_policy_len =3D sizeof(struct sadb_x_policy)/sizeof(uint64_t); + pol->sadb_x_policy_exttype =3D SADB_X_EXT_POLICY; + pol->sadb_x_policy_type =3D IPSEC_POLICY_DISCARD; + if (xp->action =3D=3D XFRM_POLICY_ALLOW) { + if (xp->xfrm_nr) + pol->sadb_x_policy_type =3D IPSEC_POLICY_IPSEC; + else + pol->sadb_x_policy_type =3D IPSEC_POLICY_NONE; + } + pol->sadb_x_policy_dir =3D dir+1; + pol->sadb_x_policy_id =3D xp->index; + + for (i=3D0; ixfrm_nr; i++) { + struct sadb_x_ipsecrequest *rq; + struct xfrm_tmpl *t =3D xp->xfrm_vec + i; + int req_size; + + req_size =3D sizeof(struct sadb_x_ipsecrequest); + if (t->mode) + req_size +=3D 2*socklen; + else + size -=3D 2*socklen; + rq =3D (void*)skb_put(skb, req_size); + pol->sadb_x_policy_len +=3D req_size/8; + rq->sadb_x_ipsecrequest_len =3D req_size; + rq->sadb_x_ipsecrequest_proto =3D t->id.proto; + rq->sadb_x_ipsecrequest_mode =3D t->mode+1; + rq->sadb_x_ipsecrequest_level =3D IPSEC_LEVEL_REQUIRE; + if (t->reqid) + rq->sadb_x_ipsecrequest_level =3D IPSEC_LEVEL_UNIQUE; + if (t->optional) + rq->sadb_x_ipsecrequest_level =3D IPSEC_LEVEL_USE; + rq->sadb_x_ipsecrequest_reqid =3D t->reqid; + if (t->mode) { + switch (xp->family) { + case AF_INET: + sin =3D (void*)(rq+1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D t->saddr.a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + sin++; + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D t->id.daddr.a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + sin6 =3D (void*)(rq+1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, t->saddr.a6, + sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + + sin6++; + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, t->id.daddr.a6, + sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + break; +#endif + default: + break; + } + } + } + hdr->sadb_msg_len =3D size / sizeof(uint64_t); + hdr->sadb_msg_reserved =3D atomic_read(&xp->refcnt); +} + +static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_= msg *hdr, void **ext_hdrs) +{ + int err; + struct sadb_lifetime *lifetime; + struct sadb_address *sa; + struct sadb_x_policy *pol; + struct xfrm_policy *xp; + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + + if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], + ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || + !ext_hdrs[SADB_X_EXT_POLICY-1]) + return -EINVAL; + + pol =3D ext_hdrs[SADB_X_EXT_POLICY-1]; + if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC) + return -EINVAL; + if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >=3D IPSEC_DIR_MAX) + return -EINVAL; + + xp =3D xfrm_policy_alloc(GFP_KERNEL); + if (xp =3D=3D NULL) + return -ENOBUFS; + + xp->action =3D (pol->sadb_x_policy_type =3D=3D IPSEC_POLICY_DISCARD ? + XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); + + sa =3D ext_hdrs[SADB_EXT_ADDRESS_SRC-1],=20 + xp->family =3D pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr); + if (!xp->family) { + err =3D -EINVAL; + goto out; + } + xp->selector.prefixlen_s =3D sa->sadb_address_prefixlen; + xp->selector.proto =3D pfkey_proto_to_xfrm(sa->sadb_address_proto); + xp->selector.sport =3D ((struct sockaddr_in *)(sa+1))->sin_port; + if (xp->selector.sport) + xp->selector.sport_mask =3D ~0; + + sa =3D ext_hdrs[SADB_EXT_ADDRESS_DST-1],=20 + pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr); + xp->selector.prefixlen_d =3D sa->sadb_address_prefixlen; + + /* Amusing, we set this twice. KAME apps appear to set same value + * in both addresses. + */ + xp->selector.proto =3D pfkey_proto_to_xfrm(sa->sadb_address_proto); + + xp->selector.dport =3D ((struct sockaddr_in *)(sa+1))->sin_port; + if (xp->selector.dport) + xp->selector.dport_mask =3D ~0; + + xp->lft.soft_byte_limit =3D XFRM_INF; + xp->lft.hard_byte_limit =3D XFRM_INF; + xp->lft.soft_packet_limit =3D XFRM_INF; + xp->lft.hard_packet_limit =3D XFRM_INF; + if ((lifetime =3D ext_hdrs[SADB_EXT_LIFETIME_HARD-1]) !=3D NULL) { + xp->lft.hard_packet_limit =3D _KEY2X(lifetime->sadb_lifetime_allocations= ); + xp->lft.hard_byte_limit =3D _KEY2X(lifetime->sadb_lifetime_bytes); + xp->lft.hard_add_expires_seconds =3D lifetime->sadb_lifetime_addtime; + xp->lft.hard_use_expires_seconds =3D lifetime->sadb_lifetime_usetime; + } + if ((lifetime =3D ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) !=3D NULL) { + xp->lft.soft_packet_limit =3D _KEY2X(lifetime->sadb_lifetime_allocations= ); + xp->lft.soft_byte_limit =3D _KEY2X(lifetime->sadb_lifetime_bytes); + xp->lft.soft_add_expires_seconds =3D lifetime->sadb_lifetime_addtime; + xp->lft.soft_use_expires_seconds =3D lifetime->sadb_lifetime_usetime; + } + xp->xfrm_nr =3D 0; + if (pol->sadb_x_policy_type =3D=3D IPSEC_POLICY_IPSEC && + (err =3D parse_ipsecrequests(xp, pol)) < 0) + goto out; + + out_skb =3D pfkey_xfrm_policy2msg_prep(xp); + if (IS_ERR(out_skb)) { + err =3D PTR_ERR(out_skb); + goto out; + } + + err =3D xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, + hdr->sadb_msg_type !=3D SADB_X_SPDUPDATE); + if (err) { + kfree_skb(out_skb); + goto out; + } + + pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1); + + xfrm_pol_put(xp); + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D hdr->sadb_msg_type; + out_hdr->sadb_msg_satype =3D 0; + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_seq =3D hdr->sadb_msg_seq; + out_hdr->sadb_msg_pid =3D hdr->sadb_msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); + return 0; + +out: + kfree(xp); + return err; +} + +static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sa= db_msg *hdr, void **ext_hdrs) +{ + int err; + struct sadb_address *sa; + struct sadb_x_policy *pol; + struct xfrm_policy *xp; + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + struct xfrm_selector sel; + + if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], + ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || + !ext_hdrs[SADB_X_EXT_POLICY-1]) + return -EINVAL; + + pol =3D ext_hdrs[SADB_X_EXT_POLICY-1]; + if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >=3D IPSEC_DIR_MAX) + return -EINVAL; + + memset(&sel, 0, sizeof(sel)); + + sa =3D ext_hdrs[SADB_EXT_ADDRESS_SRC-1],=20 + pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); + sel.prefixlen_s =3D sa->sadb_address_prefixlen; + sel.proto =3D pfkey_proto_to_xfrm(sa->sadb_address_proto); + sel.sport =3D ((struct sockaddr_in *)(sa+1))->sin_port; + if (sel.sport) + sel.sport_mask =3D ~0; + + sa =3D ext_hdrs[SADB_EXT_ADDRESS_DST-1],=20 + pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); + sel.prefixlen_d =3D sa->sadb_address_prefixlen; + sel.proto =3D pfkey_proto_to_xfrm(sa->sadb_address_proto); + sel.dport =3D ((struct sockaddr_in *)(sa+1))->sin_port; + if (sel.dport) + sel.dport_mask =3D ~0; + + xp =3D xfrm_policy_delete(pol->sadb_x_policy_dir-1, &sel); + if (xp =3D=3D NULL) + return -ENOENT; + + err =3D 0; + + out_skb =3D pfkey_xfrm_policy2msg_prep(xp); + if (IS_ERR(out_skb)) { + err =3D PTR_ERR(out_skb); + goto out; + } + pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1); + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D SADB_X_SPDDELETE; + out_hdr->sadb_msg_satype =3D 0; + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_seq =3D hdr->sadb_msg_seq; + out_hdr->sadb_msg_pid =3D hdr->sadb_msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); + err =3D 0; + +out: + if (xp) { + xfrm_policy_kill(xp); + xfrm_pol_put(xp); + } + return err; +} + +static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_= msg *hdr, void **ext_hdrs) +{ + int err; + struct sadb_x_policy *pol; + struct xfrm_policy *xp; + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + + if ((pol =3D ext_hdrs[SADB_X_EXT_POLICY-1]) =3D=3D NULL) + return -EINVAL; + + xp =3D xfrm_policy_byid(0, pol->sadb_x_policy_id, + hdr->sadb_msg_type =3D=3D SADB_X_SPDDELETE2); + if (xp =3D=3D NULL) + return -ENOENT; + + err =3D 0; + + out_skb =3D pfkey_xfrm_policy2msg_prep(xp); + if (IS_ERR(out_skb)) { + err =3D PTR_ERR(out_skb); + goto out; + } + pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1); + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D hdr->sadb_msg_type; + out_hdr->sadb_msg_satype =3D 0; + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_seq =3D hdr->sadb_msg_seq; + out_hdr->sadb_msg_pid =3D hdr->sadb_msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); + err =3D 0; + +out: + if (xp) { + if (hdr->sadb_msg_type =3D=3D SADB_X_SPDDELETE2) + xfrm_policy_kill(xp); + xfrm_pol_put(xp); + } + return err; +} + +static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) +{ + struct pfkey_dump_data *data =3D ptr; + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + + out_skb =3D pfkey_xfrm_policy2msg_prep(xp); + if (IS_ERR(out_skb)) + return PTR_ERR(out_skb); + + pfkey_xfrm_policy2msg(out_skb, xp, dir); + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D data->hdr->sadb_msg_version; + out_hdr->sadb_msg_type =3D SADB_X_SPDDUMP; + out_hdr->sadb_msg_satype =3D SADB_SATYPE_UNSPEC; + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_seq =3D count; + out_hdr->sadb_msg_pid =3D data->hdr->sadb_msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); + return 0; +} + +static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb= _msg *hdr, void **ext_hdrs) +{ + struct pfkey_dump_data data =3D { .skb =3D skb, .hdr =3D hdr, .sk =3D sk = }; + + return xfrm_policy_walk(dump_sp, &data); +} + +static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sad= b_msg *hdr, void **ext_hdrs) +{ + struct sk_buff *skb_out; + struct sadb_msg *hdr_out; + + skb_out =3D alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); + if (!skb_out) + return -ENOBUFS; + + xfrm_policy_flush(); + + hdr_out =3D (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg))= ; + pfkey_hdr_dup(hdr_out, hdr); + hdr_out->sadb_msg_errno =3D (uint8_t) 0; + hdr_out->sadb_msg_len =3D (sizeof(struct sadb_msg) / sizeof(uint64_t)); + pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL); + + return 0; +} + +typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb, + struct sadb_msg *hdr, void **ext_hdrs); +static pfkey_handler pfkey_funcs[SADB_MAX + 1] =3D { + [SADB_RESERVED] =3D pfkey_reserved, + [SADB_GETSPI] =3D pfkey_getspi, + [SADB_UPDATE] =3D pfkey_add, + [SADB_ADD] =3D pfkey_add, + [SADB_DELETE] =3D pfkey_delete, + [SADB_GET] =3D pfkey_get, + [SADB_ACQUIRE] =3D pfkey_acquire, + [SADB_REGISTER] =3D pfkey_register, + [SADB_EXPIRE] =3D NULL, + [SADB_FLUSH] =3D pfkey_flush, + [SADB_DUMP] =3D pfkey_dump, + [SADB_X_PROMISC] =3D pfkey_promisc, + [SADB_X_PCHANGE] =3D NULL, + [SADB_X_SPDUPDATE] =3D pfkey_spdadd, + [SADB_X_SPDADD] =3D pfkey_spdadd, + [SADB_X_SPDDELETE] =3D pfkey_spddelete, + [SADB_X_SPDGET] =3D pfkey_spdget, + [SADB_X_SPDACQUIRE] =3D NULL, + [SADB_X_SPDDUMP] =3D pfkey_spddump, + [SADB_X_SPDFLUSH] =3D pfkey_spdflush, + [SADB_X_SPDSETIDX] =3D pfkey_spdadd, + [SADB_X_SPDDELETE2] =3D pfkey_spdget, +}; + +static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb= _msg *hdr) +{ + void *ext_hdrs[SADB_EXT_MAX]; + int err; + + pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, + BROADCAST_PROMISC_ONLY, NULL); + + memset(ext_hdrs, 0, sizeof(ext_hdrs)); + err =3D parse_exthdrs(skb, hdr, ext_hdrs); + if (!err) { + err =3D -EOPNOTSUPP; + if (pfkey_funcs[hdr->sadb_msg_type]) + err =3D pfkey_funcs[hdr->sadb_msg_type](sk, skb, hdr, ext_hdrs); + } + return err; +} + +static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp) +{ + struct sadb_msg *hdr =3D NULL; + + if (skb->len < sizeof(*hdr)) { + *errp =3D -EMSGSIZE; + } else { + hdr =3D (struct sadb_msg *) skb->data; + if (hdr->sadb_msg_version !=3D PF_KEY_V2 || + hdr->sadb_msg_reserved !=3D 0 || + (hdr->sadb_msg_type <=3D SADB_RESERVED || + hdr->sadb_msg_type > SADB_MAX)) { + hdr =3D NULL; + *errp =3D -EINVAL; + } else if (hdr->sadb_msg_len !=3D (skb->len / + sizeof(uint64_t)) || + hdr->sadb_msg_len < (sizeof(struct sadb_msg) / + sizeof(uint64_t))) { + hdr =3D NULL; + *errp =3D -EMSGSIZE; + } else { + *errp =3D 0; + } + } + return hdr; +} + +static inline int aalg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc= *d) +{ + return t->aalgos & (1 << d->desc.sadb_alg_id); +} + +static inline int ealg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc= *d) +{ + return t->ealgos & (1 << d->desc.sadb_alg_id); +} + +static int count_ah_combs(struct xfrm_tmpl *t) +{ + int i, sz =3D 0; + + for (i =3D 0; ; i++) { + struct xfrm_algo_desc *aalg =3D xfrm_aalg_get_byidx(i); + if (!aalg) + break; + if (aalg_tmpl_set(t, aalg) && aalg->available) + sz +=3D sizeof(struct sadb_comb); + } + return sz + sizeof(struct sadb_prop); +} + +static int count_esp_combs(struct xfrm_tmpl *t) +{ + int i, k, sz =3D 0; + + for (i =3D 0; ; i++) { + struct xfrm_algo_desc *ealg =3D xfrm_ealg_get_byidx(i); + if (!ealg) + break; + =09 + if (!(ealg_tmpl_set(t, ealg) && ealg->available)) + continue; + =09 + for (k =3D 1; ; k++) { + struct xfrm_algo_desc *aalg =3D xfrm_aalg_get_byidx(k); + if (!aalg) + break; + =09 + if (aalg_tmpl_set(t, aalg) && aalg->available) + sz +=3D sizeof(struct sadb_comb); + } + } + return sz + sizeof(struct sadb_prop); +} + +static void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t) +{ + struct sadb_prop *p; + int i; + + p =3D (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); + p->sadb_prop_len =3D sizeof(struct sadb_prop)/8; + p->sadb_prop_exttype =3D SADB_EXT_PROPOSAL; + p->sadb_prop_replay =3D 32; + + for (i =3D 0; ; i++) { + struct xfrm_algo_desc *aalg =3D xfrm_aalg_get_byidx(i); + if (!aalg) + break; + + if (aalg_tmpl_set(t, aalg) && aalg->available) { + struct sadb_comb *c; + c =3D (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); + memset(c, 0, sizeof(*c)); + p->sadb_prop_len +=3D sizeof(struct sadb_comb)/8; + c->sadb_comb_auth =3D aalg->desc.sadb_alg_id; + c->sadb_comb_auth_minbits =3D aalg->desc.sadb_alg_minbits; + c->sadb_comb_auth_maxbits =3D aalg->desc.sadb_alg_maxbits; + c->sadb_comb_hard_addtime =3D 24*60*60; + c->sadb_comb_soft_addtime =3D 20*60*60; + c->sadb_comb_hard_usetime =3D 8*60*60; + c->sadb_comb_soft_usetime =3D 7*60*60; + } + } +} + +static void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) +{ + struct sadb_prop *p; + int i, k; + + p =3D (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); + p->sadb_prop_len =3D sizeof(struct sadb_prop)/8; + p->sadb_prop_exttype =3D SADB_EXT_PROPOSAL; + p->sadb_prop_replay =3D 32; + + for (i=3D0; ; i++) { + struct xfrm_algo_desc *ealg =3D xfrm_ealg_get_byidx(i); + if (!ealg) + break; +=09 + if (!(ealg_tmpl_set(t, ealg) && ealg->available)) + continue; + =09 + for (k =3D 1; ; k++) { + struct sadb_comb *c; + struct xfrm_algo_desc *aalg =3D xfrm_aalg_get_byidx(k); + if (!aalg) + break; + if (!(aalg_tmpl_set(t, aalg) && aalg->available)) + continue; + c =3D (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); + memset(c, 0, sizeof(*c)); + p->sadb_prop_len +=3D sizeof(struct sadb_comb)/8; + c->sadb_comb_auth =3D aalg->desc.sadb_alg_id; + c->sadb_comb_auth_minbits =3D aalg->desc.sadb_alg_minbits; + c->sadb_comb_auth_maxbits =3D aalg->desc.sadb_alg_maxbits; + c->sadb_comb_encrypt =3D ealg->desc.sadb_alg_id; + c->sadb_comb_encrypt_minbits =3D ealg->desc.sadb_alg_minbits; + c->sadb_comb_encrypt_maxbits =3D ealg->desc.sadb_alg_maxbits; + c->sadb_comb_hard_addtime =3D 24*60*60; + c->sadb_comb_soft_addtime =3D 20*60*60; + c->sadb_comb_hard_usetime =3D 8*60*60; + c->sadb_comb_soft_usetime =3D 7*60*60; + } + } +} + +static int pfkey_send_notify(struct xfrm_state *x, int hard) +{ + struct sk_buff *out_skb; + struct sadb_msg *out_hdr; + int hsc =3D (hard ? 2 : 1); + + out_skb =3D pfkey_xfrm_state2msg(x, 0, hsc); + if (IS_ERR(out_skb)) + return PTR_ERR(out_skb); + + out_hdr =3D (struct sadb_msg *) out_skb->data; + out_hdr->sadb_msg_version =3D PF_KEY_V2; + out_hdr->sadb_msg_type =3D SADB_EXPIRE; + out_hdr->sadb_msg_satype =3D pfkey_proto2satype(x->id.proto); + out_hdr->sadb_msg_errno =3D 0; + out_hdr->sadb_msg_reserved =3D 0; + out_hdr->sadb_msg_seq =3D 0; + out_hdr->sadb_msg_pid =3D 0; + + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); + return 0; +} + +static u32 get_acqseq(void) +{ + u32 res; + static u32 acqseq; + static spinlock_t acqseq_lock =3D SPIN_LOCK_UNLOCKED; + + spin_lock_bh(&acqseq_lock); + res =3D (++acqseq ? : ++acqseq); + spin_unlock_bh(&acqseq_lock); + return res; +} + +static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, s= truct xfrm_policy *xp, int dir) +{ + struct sk_buff *skb; + struct sadb_msg *hdr; + struct sadb_address *addr; + struct sadb_x_policy *pol; + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + int sockaddr_size; + int size; +=09 + sockaddr_size =3D pfkey_sockaddr_size(x->props.family); + if (!sockaddr_size) + return -EINVAL; + + size =3D sizeof(struct sadb_msg) + + (sizeof(struct sadb_address) * 2) + + (sockaddr_size * 2) + + sizeof(struct sadb_x_policy); +=09 + if (x->id.proto =3D=3D IPPROTO_AH) + size +=3D count_ah_combs(t); + else if (x->id.proto =3D=3D IPPROTO_ESP) + size +=3D count_esp_combs(t); + + skb =3D alloc_skb(size + 16, GFP_ATOMIC); + if (skb =3D=3D NULL) + return -ENOMEM; +=09 + hdr =3D (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); + hdr->sadb_msg_version =3D PF_KEY_V2; + hdr->sadb_msg_type =3D SADB_ACQUIRE; + hdr->sadb_msg_satype =3D pfkey_proto2satype(x->id.proto); + hdr->sadb_msg_len =3D size / sizeof(uint64_t); + hdr->sadb_msg_errno =3D 0; + hdr->sadb_msg_reserved =3D 0; + hdr->sadb_msg_seq =3D x->km.seq =3D get_acqseq(); + hdr->sadb_msg_pid =3D 0; + + /* src address */ + addr =3D (struct sadb_address*) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_SRC; + addr->sadb_address_proto =3D 0; + addr->sadb_address_reserved =3D 0; + if (x->props.family =3D=3D AF_INET) { + addr->sadb_address_prefixlen =3D 32; + + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D x->props.saddr.a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (x->props.family =3D=3D AF_INET6) { + addr->sadb_address_prefixlen =3D 128; + + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, + x->props.saddr.a6, sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + } +#endif + else + BUG(); +=09 + /* dst address */ + addr =3D (struct sadb_address*) skb_put(skb,=20 + sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_DST; + addr->sadb_address_proto =3D 0; + addr->sadb_address_reserved =3D 0; + if (x->props.family =3D=3D AF_INET) { + addr->sadb_address_prefixlen =3D 32;=20 + + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D x->id.daddr.a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (x->props.family =3D=3D AF_INET6) { + addr->sadb_address_prefixlen =3D 128;=20 + + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, + x->id.daddr.a6, sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + } +#endif + else + BUG(); + + pol =3D (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_polic= y)); + pol->sadb_x_policy_len =3D sizeof(struct sadb_x_policy)/sizeof(uint64_t); + pol->sadb_x_policy_exttype =3D SADB_X_EXT_POLICY; + pol->sadb_x_policy_type =3D IPSEC_POLICY_IPSEC; + pol->sadb_x_policy_dir =3D dir+1; + pol->sadb_x_policy_id =3D xp->index; + + /* Set sadb_comb's. */ + if (x->id.proto =3D=3D IPPROTO_AH) + dump_ah_combs(skb, t); + else if (x->id.proto =3D=3D IPPROTO_ESP) + dump_esp_combs(skb, t); + + return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); +} + +static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, + u8 *data, int len, int *di= r) +{ + struct xfrm_policy *xp; + struct sadb_x_policy *pol =3D (struct sadb_x_policy*)data; + + switch (family) { + case AF_INET: + if (opt !=3D IP_IPSEC_POLICY) { + *dir =3D -EOPNOTSUPP; + return NULL; + } + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + if (opt !=3D IPV6_IPSEC_POLICY) { + *dir =3D -EOPNOTSUPP; + return NULL; + } + break; +#endif + default: + *dir =3D -EINVAL; + return NULL; + } + + *dir =3D -EINVAL; + + if (len < sizeof(struct sadb_x_policy) || + pol->sadb_x_policy_len*8 > len || + pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS || + (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOU= ND)) + return NULL; + + xp =3D xfrm_policy_alloc(GFP_ATOMIC); + if (xp =3D=3D NULL) { + *dir =3D -ENOBUFS; + return NULL; + } + + xp->action =3D (pol->sadb_x_policy_type =3D=3D IPSEC_POLICY_DISCARD ? + XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); + + xp->lft.soft_byte_limit =3D XFRM_INF; + xp->lft.hard_byte_limit =3D XFRM_INF; + xp->lft.soft_packet_limit =3D XFRM_INF; + xp->lft.hard_packet_limit =3D XFRM_INF; + xp->family =3D family; + + xp->xfrm_nr =3D 0; + if (pol->sadb_x_policy_type =3D=3D IPSEC_POLICY_IPSEC && + (*dir =3D parse_ipsecrequests(xp, pol)) < 0) + goto out; + + *dir =3D pol->sadb_x_policy_dir-1; + return xp; + +out: + kfree(xp); + return NULL; +} + +static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ip= addr, u16 sport) +{ + struct sk_buff *skb; + struct sadb_msg *hdr; + struct sadb_sa *sa; + struct sadb_address *addr; + struct sadb_x_nat_t_port *n_port; + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + int sockaddr_size; + int size; + __u8 satype =3D (x->id.proto =3D=3D IPPROTO_ESP ? SADB_SATYPE_ESP : 0); + struct xfrm_encap_tmpl *natt =3D NULL; + + sockaddr_size =3D pfkey_sockaddr_size(x->props.family); + if (!sockaddr_size) + return -EINVAL; + + if (!satype) + return -EINVAL; + + if (!x->encap) + return -EINVAL; + + natt =3D x->encap; + + /* Build an SADB_X_NAT_T_NEW_MAPPING message: + * + * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) | + * ADDRESS_DST (new addr) | NAT_T_DPORT (new port) + */ +=09 + size =3D sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + (sizeof(struct sadb_address) * 2) + + (sockaddr_size * 2) + + (sizeof(struct sadb_x_nat_t_port) * 2); +=09 + skb =3D alloc_skb(size + 16, GFP_ATOMIC); + if (skb =3D=3D NULL) + return -ENOMEM; +=09 + hdr =3D (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); + hdr->sadb_msg_version =3D PF_KEY_V2; + hdr->sadb_msg_type =3D SADB_X_NAT_T_NEW_MAPPING; + hdr->sadb_msg_satype =3D satype; + hdr->sadb_msg_len =3D size / sizeof(uint64_t); + hdr->sadb_msg_errno =3D 0; + hdr->sadb_msg_reserved =3D 0; + hdr->sadb_msg_seq =3D x->km.seq =3D get_acqseq(); + hdr->sadb_msg_pid =3D 0; + + /* SA */ + sa =3D (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); + sa->sadb_sa_len =3D sizeof(struct sadb_sa)/sizeof(uint64_t); + sa->sadb_sa_exttype =3D SADB_EXT_SA; + sa->sadb_sa_spi =3D x->id.spi; + sa->sadb_sa_replay =3D 0; + sa->sadb_sa_state =3D 0; + sa->sadb_sa_auth =3D 0; + sa->sadb_sa_encrypt =3D 0; + sa->sadb_sa_flags =3D 0; + + /* ADDRESS_SRC (old addr) */ + addr =3D (struct sadb_address*) + skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_SRC; + addr->sadb_address_proto =3D 0; + addr->sadb_address_reserved =3D 0; + if (x->props.family =3D=3D AF_INET) { + addr->sadb_address_prefixlen =3D 32; + + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D x->props.saddr.a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (x->props.family =3D=3D AF_INET6) { + addr->sadb_address_prefixlen =3D 128; + + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, + x->props.saddr.a6, sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + } +#endif + else + BUG(); + + /* NAT_T_SPORT (old port) */ + n_port =3D (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); + n_port->sadb_x_nat_t_port_len =3D sizeof(*n_port)/sizeof(uint64_t); + n_port->sadb_x_nat_t_port_exttype =3D SADB_X_EXT_NAT_T_SPORT; + n_port->sadb_x_nat_t_port_port =3D natt->encap_sport; + n_port->sadb_x_nat_t_port_reserved =3D 0; + + /* ADDRESS_DST (new addr) */ + addr =3D (struct sadb_address*) + skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); + addr->sadb_address_len =3D=20 + (sizeof(struct sadb_address)+sockaddr_size)/ + sizeof(uint64_t); + addr->sadb_address_exttype =3D SADB_EXT_ADDRESS_SRC; + addr->sadb_address_proto =3D 0; + addr->sadb_address_reserved =3D 0; + if (x->props.family =3D=3D AF_INET) { + addr->sadb_address_prefixlen =3D 32; + + sin =3D (struct sockaddr_in *) (addr + 1); + sin->sin_family =3D AF_INET; + sin->sin_addr.s_addr =3D ipaddr->a4; + sin->sin_port =3D 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (x->props.family =3D=3D AF_INET6) { + addr->sadb_address_prefixlen =3D 128; + + sin6 =3D (struct sockaddr_in6 *) (addr + 1); + sin6->sin6_family =3D AF_INET6; + sin6->sin6_port =3D 0; + sin6->sin6_flowinfo =3D 0; + memcpy(&sin6->sin6_addr, &ipaddr->a6, sizeof(struct in6_addr)); + sin6->sin6_scope_id =3D 0; + } +#endif + else + BUG(); + + /* NAT_T_DPORT (new port) */ + n_port =3D (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); + n_port->sadb_x_nat_t_port_len =3D sizeof(*n_port)/sizeof(uint64_t); + n_port->sadb_x_nat_t_port_exttype =3D SADB_X_EXT_NAT_T_DPORT; + n_port->sadb_x_nat_t_port_port =3D sport; + n_port->sadb_x_nat_t_port_reserved =3D 0; + + return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); +} + +static int pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +{ + struct sock *sk =3D sock->sk; + struct sk_buff *skb =3D NULL; + struct sadb_msg *hdr =3D NULL; + int err; + + err =3D -EOPNOTSUPP; + if (msg->msg_flags & MSG_OOB) + goto out; + + err =3D -EMSGSIZE; + if ((unsigned)len > sk->sndbuf-32) + goto out; + + err =3D -ENOBUFS; + skb =3D alloc_skb(len, GFP_KERNEL); + if (skb =3D=3D NULL) + goto out; + + err =3D -EFAULT; + if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) + goto out; + + hdr =3D pfkey_get_base_msg(skb, &err); + if (!hdr) + goto out; + + down(&xfrm_cfg_sem); + err =3D pfkey_process(sk, skb, hdr); + up(&xfrm_cfg_sem); + +out: + if (err && hdr && pfkey_error(hdr, err, sk) =3D=3D 0) + err =3D 0; + if (skb) + kfree_skb(skb); + + return err ? : len; +} + +static int pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int len, + int flags, struct scm_cookie *scm) +{ + struct sock *sk =3D sock->sk; + struct sk_buff *skb; + int copied, err; + + err =3D -EINVAL; + if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC)) + goto out; + + msg->msg_namelen =3D 0; + skb =3D skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); + if (skb =3D=3D NULL) + goto out; + + copied =3D skb->len; + if (copied > len) { + msg->msg_flags |=3D MSG_TRUNC; + copied =3D len; + } + + skb->h.raw =3D skb->data; + err =3D skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto out_free; + + sock_recv_timestamp(msg, sk, skb); + + err =3D (flags & MSG_TRUNC) ? skb->len : copied; + +out_free: + skb_free_datagram(sk, skb); +out: + return err; +} + +static struct proto_ops pfkey_ops =3D { + .family =3D PF_KEY, + + /* Operations that make no sense on pfkey sockets. */ + .bind =3D sock_no_bind, + .connect =3D sock_no_connect, + .socketpair =3D sock_no_socketpair, + .accept =3D sock_no_accept, + .getname =3D sock_no_getname, + .ioctl =3D sock_no_ioctl, + .listen =3D sock_no_listen, + .shutdown =3D sock_no_shutdown, + .setsockopt =3D sock_no_setsockopt, + .getsockopt =3D sock_no_getsockopt, + .mmap =3D sock_no_mmap, + .sendpage =3D sock_no_sendpage, + + /* Now the operations that really occur. */ + .release =3D pfkey_release, + .poll =3D datagram_poll, + .sendmsg =3D pfkey_sendmsg, + .recvmsg =3D pfkey_recvmsg, +}; + +static struct net_proto_family pfkey_family_ops =3D { + .family =3D PF_KEY, + .create =3D pfkey_create, +}; + +#ifdef CONFIG_PROC_FS +static int pfkey_read_proc(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + off_t pos =3D 0; + off_t begin =3D 0; + int len =3D 0; + struct sock *s; + + len +=3D sprintf(buffer,"sk RefCnt Rmem Wmem User Inode\n"); + + read_lock(&pfkey_table_lock); + + for (s =3D pfkey_table; s; s =3D s->next) { + len +=3D sprintf(buffer+len,"%p %-6d %-6u %-6u %-6u %-6lu", + s, + atomic_read(&s->refcnt), + atomic_read(&s->rmem_alloc), + atomic_read(&s->wmem_alloc), + sock_i_uid(s), + sock_i_ino(s) + ); + + buffer[len++] =3D '\n'; + =09 + pos =3D begin + len; + if (pos < offset) { + len =3D 0; + begin =3D pos; + } + if(pos > offset + length) + goto done; + } + *eof =3D 1; + +done: + read_unlock(&pfkey_table_lock); + + *start =3D buffer + (offset - begin); + len -=3D (offset - begin); + + if (len > length) + len =3D length; + if (len < 0) + len =3D 0; + + return len; +} +#endif + +static struct xfrm_mgr pfkeyv2_mgr =3D +{ + .id =3D "pfkeyv2", + .notify =3D pfkey_send_notify, + .acquire =3D pfkey_send_acquire, + .compile_policy =3D pfkey_compile_policy, + .new_mapping =3D pfkey_send_new_mapping, +}; + +static void __exit ipsec_pfkey_exit(void) +{ + xfrm_unregister_km(&pfkeyv2_mgr); + remove_proc_entry("net/pfkey", 0); + sock_unregister(PF_KEY); +} + +static int __init ipsec_pfkey_init(void) +{ + sock_register(&pfkey_family_ops); +#ifdef CONFIG_PROC_FS + create_proc_read_entry("net/pfkey", 0, 0, pfkey_read_proc, NULL); +#endif + xfrm_register_km(&pfkeyv2_mgr); + return 0; +} + +module_init(ipsec_pfkey_init); +module_exit(ipsec_pfkey_exit); +MODULE_LICENSE("GPL"); diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c --- a/net/netlink/af_netlink.c Thu May 8 10:41:37 2003 +++ b/net/netlink/af_netlink.c Thu May 8 10:41:37 2003 @@ -490,13 +490,13 @@ return -1; } =20 -void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, - u32 group, int allocation) +int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, + u32 group, int allocation) { struct sock *sk; struct sk_buff *skb2 =3D NULL; int protocol =3D ssk->protocol; - int failure =3D 0; + int failure =3D 0, delivered =3D 0; =20 /* While we sleep in clone, do not allow to change socket list */ =20 @@ -530,8 +530,10 @@ failure =3D 1; } else if (netlink_broadcast_deliver(sk, skb2)) { netlink_overrun(sk); - } else + } else { + delivered =3D 1; skb2 =3D NULL; + } sock_put(sk); } =20 @@ -540,6 +542,12 @@ if (skb2) kfree_skb(skb2); kfree_skb(skb); + + if (delivered) + return 0; + if (failure) + return -ENOBUFS; + return -ESRCH; } =20 void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) diff -Nru a/net/netsyms.c b/net/netsyms.c --- a/net/netsyms.c Thu May 8 10:41:37 2003 +++ b/net/netsyms.c Thu May 8 10:41:37 2003 @@ -53,6 +53,13 @@ #include #include #include +#include +#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(C= ONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE) +#include +#endif +#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined= (CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) +#include +#endif =20 extern struct net_proto_family inet_family_ops; =20 @@ -286,6 +293,81 @@ EXPORT_SYMBOL(dlci_ioctl_hook); #endif =20 +EXPORT_SYMBOL(xfrm_user_policy); +EXPORT_SYMBOL(km_waitq); +EXPORT_SYMBOL(km_new_mapping); +EXPORT_SYMBOL(xfrm_cfg_sem); +EXPORT_SYMBOL(xfrm_policy_alloc); +EXPORT_SYMBOL(__xfrm_policy_destroy); +EXPORT_SYMBOL(xfrm_policy_lookup); +EXPORT_SYMBOL(xfrm_lookup); +EXPORT_SYMBOL(__xfrm_policy_check); +EXPORT_SYMBOL(__xfrm_route_forward); +EXPORT_SYMBOL(xfrm_state_alloc); +EXPORT_SYMBOL(__xfrm_state_destroy); +EXPORT_SYMBOL(xfrm_state_find); +EXPORT_SYMBOL(xfrm_state_insert); +EXPORT_SYMBOL(xfrm_state_check_expire); +EXPORT_SYMBOL(xfrm_state_check_space); +EXPORT_SYMBOL(xfrm_state_lookup); +EXPORT_SYMBOL(xfrm_state_register_afinfo); +EXPORT_SYMBOL(xfrm_state_unregister_afinfo); +EXPORT_SYMBOL(xfrm_state_get_afinfo); +EXPORT_SYMBOL(xfrm_state_put_afinfo); +EXPORT_SYMBOL(xfrm_replay_check); +EXPORT_SYMBOL(xfrm_replay_advance); +EXPORT_SYMBOL(xfrm_check_selectors); +EXPORT_SYMBOL(xfrm_check_output); +EXPORT_SYMBOL(__secpath_destroy); +EXPORT_SYMBOL(xfrm_get_acqseq); +EXPORT_SYMBOL(xfrm_parse_spi); +EXPORT_SYMBOL(xfrm4_rcv); +EXPORT_SYMBOL(xfrm4_tunnel_register); +EXPORT_SYMBOL(xfrm4_tunnel_deregister); +EXPORT_SYMBOL(xfrm4_tunnel_check_size); +EXPORT_SYMBOL(xfrm_register_type); +EXPORT_SYMBOL(xfrm_unregister_type); +EXPORT_SYMBOL(xfrm_get_type); +EXPORT_SYMBOL(inet_peer_idlock); +EXPORT_SYMBOL(xfrm_register_km); +EXPORT_SYMBOL(xfrm_unregister_km); +EXPORT_SYMBOL(xfrm_state_delete); +EXPORT_SYMBOL(xfrm_state_walk); +EXPORT_SYMBOL(xfrm_find_acq_byseq); +EXPORT_SYMBOL(xfrm_find_acq); +EXPORT_SYMBOL(xfrm_alloc_spi); +EXPORT_SYMBOL(xfrm_state_flush); +EXPORT_SYMBOL(xfrm_policy_kill); +EXPORT_SYMBOL(xfrm_policy_delete); +EXPORT_SYMBOL(xfrm_policy_insert); +EXPORT_SYMBOL(xfrm_policy_walk); +EXPORT_SYMBOL(xfrm_policy_flush); +EXPORT_SYMBOL(xfrm_policy_byid); +EXPORT_SYMBOL(xfrm_policy_list); +EXPORT_SYMBOL(xfrm_dst_lookup); +EXPORT_SYMBOL(xfrm_policy_register_afinfo); +EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); +EXPORT_SYMBOL(xfrm_policy_get_afinfo); +EXPORT_SYMBOL(xfrm_policy_put_afinfo); + +EXPORT_SYMBOL_GPL(xfrm_probe_algs); +EXPORT_SYMBOL_GPL(xfrm_count_auth_supported); +EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byidx); +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx); +EXPORT_SYMBOL_GPL(xfrm_calg_get_byidx); +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byid); +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byid); +EXPORT_SYMBOL_GPL(xfrm_calg_get_byid); +EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname); +EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname); +EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); +EXPORT_SYMBOL_GPL(skb_icv_walk); +#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined= (CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) +EXPORT_SYMBOL_GPL(skb_cow_data); +EXPORT_SYMBOL_GPL(pskb_put); +EXPORT_SYMBOL_GPL(skb_to_sgvec); +#endif =20 #ifdef CONFIG_IPV6 EXPORT_SYMBOL(ipv6_addr_type); @@ -478,6 +560,7 @@ EXPORT_SYMBOL(loopback_dev); EXPORT_SYMBOL(register_netdevice); EXPORT_SYMBOL(unregister_netdevice); +EXPORT_SYMBOL(synchronize_net); EXPORT_SYMBOL(netdev_state_change); EXPORT_SYMBOL(dev_new_index); EXPORT_SYMBOL(dev_get_by_flags); diff -Nru a/net/sched/cls_route.c b/net/sched/cls_route.c --- a/net/sched/cls_route.c Thu May 8 10:41:37 2003 +++ b/net/sched/cls_route.c Thu May 8 10:41:37 2003 @@ -154,7 +154,7 @@ if (head =3D=3D NULL) goto old_method; =20 - iif =3D ((struct rtable*)dst)->key.iif; + iif =3D ((struct rtable*)dst)->fl.iif; =20 h =3D route4_fastmap_hash(id, iif); if (id =3D=3D head->fastmap[h].id && diff -Nru a/net/xfrm/Config.in b/net/xfrm/Config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/xfrm/Config.in Thu May 8 10:41:38 2003 @@ -0,0 +1,4 @@ +# +# XFRM configuration +# +tristate ' IP: IPsec user configuration interface' CONFIG_XFRM_USER diff -Nru a/net/xfrm/Makefile b/net/xfrm/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/xfrm/Makefile Thu May 8 10:41:38 2003 @@ -0,0 +1,10 @@ +# +# Makefile for the XFRM subsystem. +# + +O_TARGET :=3D xfrm.o + +obj-y :=3D xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o xfrm_output= .o +obj-$(CONFIG_XFRM_USER) +=3D xfrm_user.o + +include $(TOPDIR)/Rules.make diff -Nru a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/xfrm/xfrm_algo.c Thu May 8 10:41:38 2003 @@ -0,0 +1,695 @@ +/*=20 + * xfrm algorithm interface + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + */ +#include +#include +#include +#include +#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(C= ONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE) +#include +#endif +#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined= (CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) +#include +#endif +#include + +/* + * Algorithms supported by IPsec. These entries contain properties which + * are used in key negotiation and xfrm processing, and are used to verify + * that instantiated crypto transforms have correct parameters for IPsec + * purposes. + */ +static struct xfrm_algo_desc aalg_list[] =3D { +{ + .name =3D "digest_null", +=09 + .uinfo =3D { + .auth =3D { + .icv_truncbits =3D 0, + .icv_fullbits =3D 0, + } + }, +=09 + .desc =3D { + .sadb_alg_id =3D SADB_X_AALG_NULL, + .sadb_alg_ivlen =3D 0, + .sadb_alg_minbits =3D 0, + .sadb_alg_maxbits =3D 0 + } +}, +{ + .name =3D "md5", + + .uinfo =3D { + .auth =3D { + .icv_truncbits =3D 96, + .icv_fullbits =3D 128, + } + }, +=09 + .desc =3D { + .sadb_alg_id =3D SADB_AALG_MD5HMAC, + .sadb_alg_ivlen =3D 0, + .sadb_alg_minbits =3D 128, + .sadb_alg_maxbits =3D 128 + } +}, +{ + .name =3D "sha1", + + .uinfo =3D { + .auth =3D { + .icv_truncbits =3D 96, + .icv_fullbits =3D 160, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_AALG_SHA1HMAC, + .sadb_alg_ivlen =3D 0, + .sadb_alg_minbits =3D 160, + .sadb_alg_maxbits =3D 160 + } +}, +{ + .name =3D "sha256", + + .uinfo =3D { + .auth =3D { + .icv_truncbits =3D 128, + .icv_fullbits =3D 256, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_X_AALG_SHA2_256HMAC, + .sadb_alg_ivlen =3D 0, + .sadb_alg_minbits =3D 256, + .sadb_alg_maxbits =3D 256 + } +}, +{ + .name =3D "ripemd160", + + .uinfo =3D { + .auth =3D { + .icv_truncbits =3D 96, + .icv_fullbits =3D 160, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_X_AALG_RIPEMD160HMAC, + .sadb_alg_ivlen =3D 0, + .sadb_alg_minbits =3D 160, + .sadb_alg_maxbits =3D 160 + } +}, +}; + +static struct xfrm_algo_desc ealg_list[] =3D { +{ + .name =3D "cipher_null", +=09 + .uinfo =3D { + .encr =3D { + .blockbits =3D 8, + .defkeybits =3D 0, + } + }, +=09 + .desc =3D { + .sadb_alg_id =3D SADB_EALG_NULL, + .sadb_alg_ivlen =3D 0, + .sadb_alg_minbits =3D 0, + .sadb_alg_maxbits =3D 0 + } +}, +{ + .name =3D "des", + + .uinfo =3D { + .encr =3D { + .blockbits =3D 64, + .defkeybits =3D 64, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_EALG_DESCBC, + .sadb_alg_ivlen =3D 8, + .sadb_alg_minbits =3D 64, + .sadb_alg_maxbits =3D 64 + } +}, +{ + .name =3D "des3_ede", + + .uinfo =3D { + .encr =3D { + .blockbits =3D 64, + .defkeybits =3D 192, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_EALG_3DESCBC, + .sadb_alg_ivlen =3D 8, + .sadb_alg_minbits =3D 192, + .sadb_alg_maxbits =3D 192 + } +}, +{ + .name =3D "cast128", + + .uinfo =3D { + .encr =3D { + .blockbits =3D 64, + .defkeybits =3D 128, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_X_EALG_CASTCBC, + .sadb_alg_ivlen =3D 8, + .sadb_alg_minbits =3D 40, + .sadb_alg_maxbits =3D 128 + } +}, +{ + .name =3D "blowfish", + + .uinfo =3D { + .encr =3D { + .blockbits =3D 64, + .defkeybits =3D 128, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_X_EALG_BLOWFISHCBC, + .sadb_alg_ivlen =3D 8, + .sadb_alg_minbits =3D 40, + .sadb_alg_maxbits =3D 448 + } +}, +{ + .name =3D "aes", + + .uinfo =3D { + .encr =3D { + .blockbits =3D 128, + .defkeybits =3D 128, + } + }, + + .desc =3D { + .sadb_alg_id =3D SADB_X_EALG_AESCBC, + .sadb_alg_ivlen =3D 8, + .sadb_alg_minbits =3D 128, + .sadb_alg_maxbits =3D 256 + } +}, +}; + +static struct xfrm_algo_desc calg_list[] =3D { +{ + .name =3D "deflate", + .uinfo =3D { + .comp =3D { + .threshold =3D 90, + } + }, + .desc =3D { .sadb_alg_id =3D SADB_X_CALG_DEFLATE } +}, +{ + .name =3D "lzs", + .uinfo =3D { + .comp =3D { + .threshold =3D 90, + } + }, + .desc =3D { .sadb_alg_id =3D SADB_X_CALG_LZS } +}, +{ + .name =3D "lzjh", + .uinfo =3D { + .comp =3D { + .threshold =3D 50, + } + }, + .desc =3D { .sadb_alg_id =3D SADB_X_CALG_LZJH } +}, +}; + +static inline int aalg_entries(void) +{ + return sizeof(aalg_list) / sizeof(aalg_list[0]); +} + +static inline int ealg_entries(void) +{ + return sizeof(ealg_list) / sizeof(ealg_list[0]); +} + +static inline int calg_entries(void) +{ + return sizeof(calg_list) / sizeof(calg_list[0]); +} + +/* Todo: generic iterators */ +struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id) +{ + int i; + + for (i =3D 0; i < aalg_entries(); i++) { + if (aalg_list[i].desc.sadb_alg_id =3D=3D alg_id) { + if (aalg_list[i].available) + return &aalg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id) +{ + int i; + + for (i =3D 0; i < ealg_entries(); i++) { + if (ealg_list[i].desc.sadb_alg_id =3D=3D alg_id) { + if (ealg_list[i].available) + return &ealg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id) +{ + int i; + + for (i =3D 0; i < calg_entries(); i++) { + if (calg_list[i].desc.sadb_alg_id =3D=3D alg_id) { + if (calg_list[i].available) + return &calg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name) +{ + int i; + + if (!name) + return NULL; + + for (i=3D0; i < aalg_entries(); i++) { + if (strcmp(name, aalg_list[i].name) =3D=3D 0) { + if (aalg_list[i].available) + return &aalg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name) +{ + int i; + + if (!name) + return NULL; + + for (i=3D0; i < ealg_entries(); i++) { + if (strcmp(name, ealg_list[i].name) =3D=3D 0) { + if (ealg_list[i].available) + return &ealg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_calg_get_byname(char *name) +{ + int i; + + if (!name) + return NULL; + + for (i=3D0; i < calg_entries(); i++) { + if (strcmp(name, calg_list[i].name) =3D=3D 0) { + if (calg_list[i].available) + return &calg_list[i]; + else + break; + } + } + return NULL; +} + +struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx) +{ + if (idx >=3D aalg_entries()) + return NULL; + + return &aalg_list[idx]; +} + +struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx) +{ + if (idx >=3D ealg_entries()) + return NULL; + + return &ealg_list[idx]; +} + +struct xfrm_algo_desc *xfrm_calg_get_byidx(unsigned int idx) +{ + if (idx >=3D calg_entries()) + return NULL; + + return &calg_list[idx]; +} + +/* + * Probe for the availability of crypto algorithms, and set the available + * flag for any algorithms found on the system. This is typically called = by + * pfkey during userspace SA add, update or register. + */ +void xfrm_probe_algs(void) +{ +#ifdef CONFIG_CRYPTO + int i, status; +=09 + BUG_ON(in_softirq()); + + for (i =3D 0; i < aalg_entries(); i++) { + status =3D crypto_alg_available(aalg_list[i].name, 0); + if (aalg_list[i].available !=3D status) + aalg_list[i].available =3D status; + } +=09 + for (i =3D 0; i < ealg_entries(); i++) { + status =3D crypto_alg_available(ealg_list[i].name, 0); + if (ealg_list[i].available !=3D status) + ealg_list[i].available =3D status; + } +=09 + for (i =3D 0; i < calg_entries(); i++) { + status =3D crypto_alg_available(calg_list[i].name, 0); + if (calg_list[i].available !=3D status) + calg_list[i].available =3D status; + } +#endif +} + +int xfrm_count_auth_supported(void) +{ + int i, n; + + for (i =3D 0, n =3D 0; i < aalg_entries(); i++) + if (aalg_list[i].available) + n++; + return n; +} + +int xfrm_count_enc_supported(void) +{ + int i, n; + + for (i =3D 0, n =3D 0; i < ealg_entries(); i++) + if (ealg_list[i].available) + n++; + return n; +} + +/* Move to common area: it is shared with AH. */ + +void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, + int offset, int len, icv_update_fn_t icv_update) +{ + int start =3D skb->len - skb->data_len; + int i, copy =3D start - offset; + struct scatterlist sg; + + /* Checksum header. */ + if (copy > 0) { + if (copy > len) + copy =3D len; + =09 + sg.page =3D virt_to_page(skb->data + offset); + sg.offset =3D (unsigned long)(skb->data + offset) % PAGE_SIZE; + sg.length =3D copy; + =09 + icv_update(tfm, &sg, 1); + =09 + if ((len -=3D copy) =3D=3D 0) + return; + offset +=3D copy; + } + + for (i =3D 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <=3D offset + len); + + end =3D start + skb_shinfo(skb)->frags[i].size; + if ((copy =3D end - offset) > 0) { + skb_frag_t *frag =3D &skb_shinfo(skb)->frags[i]; + + if (copy > len) + copy =3D len; + =09 + sg.page =3D frag->page; + sg.offset =3D frag->page_offset + offset-start; + sg.length =3D copy; + =09 + icv_update(tfm, &sg, 1); + + if (!(len -=3D copy)) + return; + offset +=3D copy; + } + start =3D end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list =3D skb_shinfo(skb)->frag_list; + + for (; list; list =3D list->next) { + int end; + + BUG_TRAP(start <=3D offset + len); + + end =3D start + list->len; + if ((copy =3D end - offset) > 0) { + if (copy > len) + copy =3D len; + skb_icv_walk(list, tfm, offset-start, copy, icv_update); + if ((len -=3D copy) =3D=3D 0) + return; + offset +=3D copy; + } + start =3D end; + } + } + if (len) + BUG(); +} + +#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined= (CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) + +/* Looking generic it is not used in another places. */ + +int +skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int = len) +{ + int start =3D skb->len - skb->data_len; + int i, copy =3D start - offset; + int elt =3D 0; + + if (copy > 0) { + if (copy > len) + copy =3D len; + sg[elt].page =3D virt_to_page(skb->data + offset); + sg[elt].offset =3D (unsigned long)(skb->data + offset) % PAGE_SIZE; + sg[elt].length =3D copy; + elt++; + if ((len -=3D copy) =3D=3D 0) + return elt; + offset +=3D copy; + } + + for (i =3D 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <=3D offset + len); + + end =3D start + skb_shinfo(skb)->frags[i].size; + if ((copy =3D end - offset) > 0) { + skb_frag_t *frag =3D &skb_shinfo(skb)->frags[i]; + + if (copy > len) + copy =3D len; + sg[elt].page =3D frag->page; + sg[elt].offset =3D frag->page_offset+offset-start; + sg[elt].length =3D copy; + elt++; + if (!(len -=3D copy)) + return elt; + offset +=3D copy; + } + start =3D end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list =3D skb_shinfo(skb)->frag_list; + + for (; list; list =3D list->next) { + int end; + + BUG_TRAP(start <=3D offset + len); + + end =3D start + list->len; + if ((copy =3D end - offset) > 0) { + if (copy > len) + copy =3D len; + elt +=3D skb_to_sgvec(list, sg+elt, offset - start, copy); + if ((len -=3D copy) =3D=3D 0) + return elt; + offset +=3D copy; + } + start =3D end; + } + } + if (len) + BUG(); + return elt; +} + +/* Check that skb data bits are writable. If they are not, copy data + * to newly created private area. If "tailbits" is given, make sure that + * tailbits bytes beyond current end of skb are writable. + * + * Returns amount of elements of scatterlist to load for subsequent + * transformations and pointer to writable trailer skb. + */ + +int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trail= er) +{ + int copyflag; + int elt; + struct sk_buff *skb1, **skb_p; + + /* If skb is cloned or its head is paged, reallocate + * head pulling out all the pages (pages are considered not writable + * at the moment even if they are anonymous). + */ + if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) && + __pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) =3D=3D NULL) + return -ENOMEM; + + /* Easy case. Most of packets will go this way. */ + if (!skb_shinfo(skb)->frag_list) { + /* A little of trouble, not enough of space for trailer. + * This should not happen, when stack is tuned to generate + * good frames. OK, on miss we reallocate and reserve even more + * space, 128 bytes is fair. */ + + if (skb_tailroom(skb) < tailbits && + pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC)= ) + return -ENOMEM; + + /* Voila! */ + *trailer =3D skb; + return 1; + } + + /* Misery. We are in troubles, going to mincer fragments... */ + + elt =3D 1; + skb_p =3D &skb_shinfo(skb)->frag_list; + copyflag =3D 0; + + while ((skb1 =3D *skb_p) !=3D NULL) { + int ntail =3D 0; + + /* The fragment is partially pulled by someone, + * this can happen on input. Copy it and everything + * after it. */ + + if (skb_shared(skb1)) + copyflag =3D 1; + + /* If the skb is the last, worry about trailer. */ + + if (skb1->next =3D=3D NULL && tailbits) { + if (skb_shinfo(skb1)->nr_frags || + skb_shinfo(skb1)->frag_list || + skb_tailroom(skb1) < tailbits) + ntail =3D tailbits + 128; + } + + if (copyflag || + skb_cloned(skb1) || + ntail || + skb_shinfo(skb1)->nr_frags || + skb_shinfo(skb1)->frag_list) { + struct sk_buff *skb2; + + /* Fuck, we are miserable poor guys... */ + if (ntail =3D=3D 0) + skb2 =3D skb_copy(skb1, GFP_ATOMIC); + else + skb2 =3D skb_copy_expand(skb1, + skb_headroom(skb1), + ntail, + GFP_ATOMIC); + if (unlikely(skb2 =3D=3D NULL)) + return -ENOMEM; + + if (skb1->sk) + skb_set_owner_w(skb, skb1->sk); + + /* Looking around. Are we still alive? + * OK, link new skb, drop old one */ + + skb2->next =3D skb1->next; + *skb_p =3D skb2; + kfree_skb(skb1); + skb1 =3D skb2; + } + elt++; + *trailer =3D skb1; + skb_p =3D &skb1->next; + } + + return elt; +} + +void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) +{ + if (tail !=3D skb) { + skb->data_len +=3D len; + skb->len +=3D len; + } + return skb_put(tail, len); +} +#endif diff -Nru a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/xfrm/xfrm_input.c Thu May 8 10:41:38 2003 @@ -0,0 +1,52 @@ +/* + * xfrm_input.c + * + * Changes: + * YOSHIFUJI Hideaki @USAGI + * Split up af-specific portion + * =09 + */ + +#include +#include + +void __secpath_destroy(struct sec_path *sp) +{ + int i; + for (i =3D 0; i < sp->len; i++) + xfrm_state_put(sp->x[i].xvec); + kmem_cache_free(sp->pool, sp); +} + +/* Fetch spi and seq frpm ipsec header */ + +int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) +{ + int offset, offset_seq; + + switch (nexthdr) { + case IPPROTO_AH: + offset =3D offsetof(struct ip_auth_hdr, spi); + offset_seq =3D offsetof(struct ip_auth_hdr, seq_no); + break; + case IPPROTO_ESP: + offset =3D offsetof(struct ip_esp_hdr, spi); + offset_seq =3D offsetof(struct ip_esp_hdr, seq_no); + break; + case IPPROTO_COMP: + if (!pskb_may_pull(skb, 4)) + return -EINVAL; + *spi =3D ntohl(ntohs(*(u16*)(skb->h.raw + 2))); + *seq =3D 0; + return 0; + default: + return 1; + } + + if (!pskb_may_pull(skb, 16)) + return -EINVAL; + + *spi =3D *(u32*)(skb->h.raw + offset); + *seq =3D *(u32*)(skb->h.raw + offset_seq); + return 0; +} diff -Nru a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/xfrm/xfrm_output.c Thu May 8 10:41:38 2003 @@ -0,0 +1,46 @@ +/*=20 + * generic xfrm output routines + * + * Copyright (c) 2003 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the F= ree + * Software Foundation; either version 2 of the License, or (at your optio= n)=20 + * any later version. + */ +#include +#include +#include +#include + +int xfrm_check_output(struct xfrm_state *x, + struct sk_buff *skb, unsigned short family) +{ + int err; +=09 + err =3D xfrm_state_check_expire(x); + if (err) + goto out; + =09 + if (x->props.mode) { + switch (family) { + case AF_INET: + err =3D xfrm4_tunnel_check_size(skb); + break; + =09 + case AF_INET6: + err =3D xfrm6_tunnel_check_size(skb); + break; + =09 + default: + err =3D -EINVAL; + } + =09 + if (err) + goto out; + } + + err =3D xfrm_state_check_space(x, skb); +out: + return err; +} diff -Nru a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/xfrm/xfrm_policy.c Thu May 8 10:41:38 2003 @@ -0,0 +1,1244 @@ +/*=20 + * xfrm_policy.c + * + * Changes: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro + * IPv6 support + * Kazunori MIYAZAWA @USAGI + * YOSHIFUJI Hideaki + * Split up af-specific portion + * Derek Atkins Add the post_input processor + * =09 + */ + +#include +#include +#include + +DECLARE_MUTEX(xfrm_cfg_sem); + +static u32 xfrm_policy_genid; +static rwlock_t xfrm_policy_lock =3D RW_LOCK_UNLOCKED; + +struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; + +static rwlock_t xfrm_policy_afinfo_lock =3D RW_LOCK_UNLOCKED; +static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; + +kmem_cache_t *xfrm_dst_cache; + +/* Limited flow cache. Its function now is to accelerate search for + * policy rules. + * + * Flow cache is private to cpus, at the moment this is important + * mostly for flows which do not match any rule, so that flow lookups + * are absolultely cpu-local. When a rule exists we do some updates + * to rule (refcnt, stats), so that locality is broken. Later this + * can be repaired. + */ + +struct flow_entry +{ + struct flow_entry *next; + struct flowi fl; + u8 dir; + u32 genid; + struct xfrm_policy *pol; +}; + +static kmem_cache_t *flow_cachep; + +struct flow_entry **flow_table; + +static int flow_lwm =3D 2*XFRM_FLOWCACHE_HASH_SIZE; +static int flow_hwm =3D 4*XFRM_FLOWCACHE_HASH_SIZE; + +static int flow_number[NR_CPUS] __cacheline_aligned; + +#define flow_count(cpu) (flow_number[cpu]) + +static void flow_cache_shrink(int cpu) +{ + int i; + struct flow_entry *fle, **flp; + int shrink_to =3D flow_lwm/XFRM_FLOWCACHE_HASH_SIZE; + + for (i=3D0; inext; + } + while ((fle=3D*flp) !=3D NULL) { + *flp =3D fle->next; + if (fle->pol) + xfrm_pol_put(fle->pol); + kmem_cache_free(flow_cachep, fle); + } + } +} + +struct xfrm_policy *flow_lookup(int dir, struct flowi *fl,=20 + unsigned short family) +{ + struct xfrm_policy *pol =3D NULL; + struct flow_entry *fle; + u32 hash; + int cpu; + + hash =3D flow_hash(fl, family); + + local_bh_disable(); + cpu =3D smp_processor_id(); + + for (fle =3D flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash]; + fle; fle =3D fle->next) { + if (memcmp(fl, &fle->fl, sizeof(fle->fl)) =3D=3D 0 && + fle->dir =3D=3D dir) { + if (fle->genid =3D=3D xfrm_policy_genid) { + if ((pol =3D fle->pol) !=3D NULL) + atomic_inc(&pol->refcnt); + local_bh_enable(); + return pol; + } + break; + } + } + + pol =3D xfrm_policy_lookup(dir, fl, family); + + if (fle) { + /* Stale flow entry found. Update it. */ + fle->genid =3D xfrm_policy_genid; + + if (fle->pol) + xfrm_pol_put(fle->pol); + fle->pol =3D pol; + if (pol) + atomic_inc(&pol->refcnt); + } else { + if (flow_count(cpu) > flow_hwm) + flow_cache_shrink(cpu); + + fle =3D kmem_cache_alloc(flow_cachep, SLAB_ATOMIC); + if (fle) { + flow_count(cpu)++; + fle->fl =3D *fl; + fle->genid =3D xfrm_policy_genid; + fle->dir =3D dir; + fle->pol =3D pol; + if (pol) + atomic_inc(&pol->refcnt); + fle->next =3D flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash]; + flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash] =3D fle; + } + } + local_bh_enable(); + return pol; +} + +void __init flow_cache_init(void) +{ + int order; + + flow_cachep =3D kmem_cache_create("flow_cache", + sizeof(struct flow_entry), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + + if (!flow_cachep) + panic("NET: failed to allocate flow cache slab\n"); + + for (order =3D 0; + (PAGE_SIZE<type_map; + + write_lock(&typemap->lock); + if (likely(typemap->map[type->proto] =3D=3D NULL)) + typemap->map[type->proto] =3D type; + else + err =3D -EEXIST; + write_unlock(&typemap->lock); + xfrm_policy_put_afinfo(afinfo); + return err; +} + +int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) +{ + struct xfrm_policy_afinfo *afinfo =3D xfrm_policy_get_afinfo(family); + struct xfrm_type_map *typemap; + int err =3D 0; + + if (unlikely(afinfo =3D=3D NULL)) + return -EAFNOSUPPORT; + typemap =3D afinfo->type_map; + + write_lock(&typemap->lock); + if (unlikely(typemap->map[type->proto] !=3D type)) + err =3D -ENOENT; + else + typemap->map[type->proto] =3D NULL; + write_unlock(&typemap->lock); + xfrm_policy_put_afinfo(afinfo); + return err; +} + +struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) +{ + struct xfrm_policy_afinfo *afinfo =3D xfrm_policy_get_afinfo(family); + struct xfrm_type_map *typemap; + struct xfrm_type *type; + + if (unlikely(afinfo =3D=3D NULL)) + return NULL; + typemap =3D afinfo->type_map; + + read_lock(&typemap->lock); + type =3D typemap->map[proto]; + if (type && type->owner) + __MOD_INC_USE_COUNT(type->owner); + read_unlock(&typemap->lock); + xfrm_policy_put_afinfo(afinfo); + return type; +} + +int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,=20 + unsigned short family) +{ + struct xfrm_policy_afinfo *afinfo =3D xfrm_policy_get_afinfo(family); + int err =3D 0; + + if (unlikely(afinfo =3D=3D NULL)) + return -EAFNOSUPPORT; + + if (likely(afinfo->dst_lookup !=3D NULL)) + err =3D afinfo->dst_lookup(dst, fl); + else + err =3D -EINVAL; + xfrm_policy_put_afinfo(afinfo); + return err; +} + +void xfrm_put_type(struct xfrm_type *type) +{ + if (type->owner) + __MOD_DEC_USE_COUNT(type->owner); +} + +static inline unsigned long make_jiffies(long secs) +{ + if (secs >=3D (MAX_SCHEDULE_TIMEOUT-1)/HZ) + return MAX_SCHEDULE_TIMEOUT-1; + else + return secs*HZ; +} + +static void xfrm_policy_timer(unsigned long data) +{ + struct xfrm_policy *xp =3D (struct xfrm_policy*)data; + unsigned long now =3D (unsigned long)xtime.tv_sec; + long next =3D LONG_MAX; + u32 index; + + if (xp->dead) + goto out; + + if (xp->lft.hard_add_expires_seconds) { + long tmo =3D xp->lft.hard_add_expires_seconds + + xp->curlft.add_time - now; + if (tmo <=3D 0) + goto expired; + if (tmo < next) + next =3D tmo; + } + if (next !=3D LONG_MAX && + !mod_timer(&xp->timer, jiffies + make_jiffies(next))) + atomic_inc(&xp->refcnt); + +out: + xfrm_pol_put(xp); + return; + +expired: + index =3D xp->index; + xfrm_pol_put(xp); + + /* Not 100% correct. id can be recycled in theory */ + xp =3D xfrm_policy_byid(0, index, 1); + if (xp) { + xfrm_policy_kill(xp); + xfrm_pol_put(xp); + } +} + + +/* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkey= v2 + * SPD calls. + */ + +struct xfrm_policy *xfrm_policy_alloc(int gfp) +{ + struct xfrm_policy *policy; + + policy =3D kmalloc(sizeof(struct xfrm_policy), gfp); + + if (policy) { + memset(policy, 0, sizeof(struct xfrm_policy)); + atomic_set(&policy->refcnt, 1); + policy->lock =3D RW_LOCK_UNLOCKED; + init_timer(&policy->timer); + policy->timer.data =3D (unsigned long)policy; + policy->timer.function =3D xfrm_policy_timer; + } + return policy; +} + +/* Destroy xfrm_policy: descendant resources must be released to this mome= nt. */ + +void __xfrm_policy_destroy(struct xfrm_policy *policy) +{ + if (!policy->dead) + BUG(); + + if (policy->bundles) + BUG(); + + if (del_timer(&policy->timer)) + BUG(); + + kfree(policy); +} + +/* Rule must be locked. Release descentant resources, announce + * entry dead. The rule must be unlinked from lists to the moment. + */ + +void xfrm_policy_kill(struct xfrm_policy *policy) +{ + struct dst_entry *dst; + + write_lock_bh(&policy->lock); + if (policy->dead) + goto out; + + policy->dead =3D 1; + + while ((dst =3D policy->bundles) !=3D NULL) { + policy->bundles =3D dst->next; + dst_free(dst); + } + + if (del_timer(&policy->timer)) + atomic_dec(&policy->refcnt); + +out: + write_unlock_bh(&policy->lock); +} + +/* Generate new index... KAME seems to generate them ordered by cost + * of an absolute inpredictability of ordering of rules. This will not pas= s. */ +static u32 xfrm_gen_index(int dir) +{ + u32 idx; + struct xfrm_policy *p; + static u32 idx_generator; + + for (;;) { + idx =3D (idx_generator | dir); + idx_generator +=3D 8; + if (idx =3D=3D 0) + idx =3D 8; + for (p =3D xfrm_policy_list[dir]; p; p =3D p->next) { + if (p->index =3D=3D idx) + break; + } + if (!p) + return idx; + } +} + +int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) +{ + struct xfrm_policy *pol, **p; + + write_lock_bh(&xfrm_policy_lock); + for (p =3D &xfrm_policy_list[dir]; (pol=3D*p)!=3DNULL; p =3D &pol->next) = { + if (memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) =3D= =3D 0) { + if (excl) { + write_unlock_bh(&xfrm_policy_lock); + return -EEXIST; + } + break; + } + } + atomic_inc(&policy->refcnt); + policy->next =3D pol ? pol->next : NULL; + *p =3D policy; + xfrm_policy_genid++; + policy->index =3D pol ? pol->index : xfrm_gen_index(dir); + policy->curlft.add_time =3D (unsigned long)xtime.tv_sec; + policy->curlft.use_time =3D 0; + if (policy->lft.hard_add_expires_seconds && + !mod_timer(&policy->timer, jiffies + HZ)) + atomic_inc(&policy->refcnt); + write_unlock_bh(&xfrm_policy_lock); + + if (pol) { + atomic_dec(&pol->refcnt); + xfrm_policy_kill(pol); + xfrm_pol_put(pol); + } + return 0; +} + +struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel) +{ + struct xfrm_policy *pol, **p; + + write_lock_bh(&xfrm_policy_lock); + for (p =3D &xfrm_policy_list[dir]; (pol=3D*p)!=3DNULL; p =3D &pol->next) = { + if (memcmp(sel, &pol->selector, sizeof(*sel)) =3D=3D 0) { + *p =3D pol->next; + break; + } + } + if (pol) + xfrm_policy_genid++; + write_unlock_bh(&xfrm_policy_lock); + return pol; +} + +struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) +{ + struct xfrm_policy *pol, **p; + + write_lock_bh(&xfrm_policy_lock); + for (p =3D &xfrm_policy_list[id & 7]; (pol=3D*p)!=3DNULL; p =3D &pol->nex= t) { + if (pol->index =3D=3D id) { + if (delete) + *p =3D pol->next; + break; + } + } + if (pol) { + if (delete) + xfrm_policy_genid++; + else + atomic_inc(&pol->refcnt); + } + write_unlock_bh(&xfrm_policy_lock); + return pol; +} + +void xfrm_policy_flush() +{ + struct xfrm_policy *xp; + int dir; + + write_lock_bh(&xfrm_policy_lock); + for (dir =3D 0; dir < XFRM_POLICY_MAX; dir++) { + while ((xp =3D xfrm_policy_list[dir]) !=3D NULL) { + xfrm_policy_list[dir] =3D xp->next; + write_unlock_bh(&xfrm_policy_lock); + + xfrm_policy_kill(xp); + xfrm_pol_put(xp); + + write_lock_bh(&xfrm_policy_lock); + } + } + xfrm_policy_genid++; + write_unlock_bh(&xfrm_policy_lock); +} + +int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), + void *data) +{ + struct xfrm_policy *xp; + int dir; + int count =3D 0; + int error =3D 0; + + read_lock_bh(&xfrm_policy_lock); + for (dir =3D 0; dir < 2*XFRM_POLICY_MAX; dir++) { + for (xp =3D xfrm_policy_list[dir]; xp; xp =3D xp->next) + count++; + } + + if (count =3D=3D 0) { + error =3D -ENOENT; + goto out; + } + + for (dir =3D 0; dir < 2*XFRM_POLICY_MAX; dir++) { + for (xp =3D xfrm_policy_list[dir]; xp; xp =3D xp->next) { + error =3D func(xp, dir%XFRM_POLICY_MAX, --count, data); + if (error) + goto out; + } + } + +out: + read_unlock_bh(&xfrm_policy_lock); + return error; +} + + +/* Find policy to apply to this flow. */ + +struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl,=20 + unsigned short family) +{ + struct xfrm_policy *pol; + + read_lock_bh(&xfrm_policy_lock); + for (pol =3D xfrm_policy_list[dir]; pol; pol =3D pol->next) { + struct xfrm_selector *sel =3D &pol->selector; + int match; + + if (pol->family !=3D family) + continue; + + match =3D xfrm_selector_match(sel, fl, family); + if (match) { + atomic_inc(&pol->refcnt); + break; + } + } + read_unlock_bh(&xfrm_policy_lock); + return pol; +} + +struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct= flowi *fl) +{ + struct xfrm_policy *pol; + + read_lock_bh(&xfrm_policy_lock); + if ((pol =3D sk->policy[dir]) !=3D NULL) { + int match; + + match =3D xfrm_selector_match(&pol->selector, fl, sk->family); + if (match) + atomic_inc(&pol->refcnt); + else + pol =3D NULL; + } + read_unlock_bh(&xfrm_policy_lock); + return pol; +} + +void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) +{ + pol->next =3D xfrm_policy_list[XFRM_POLICY_MAX+dir]; + xfrm_policy_list[XFRM_POLICY_MAX+dir] =3D pol; + atomic_inc(&pol->refcnt); +} + +void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) +{ + struct xfrm_policy **polp; + + for (polp =3D &xfrm_policy_list[XFRM_POLICY_MAX+dir]; + *polp !=3D NULL; polp =3D &(*polp)->next) { + if (*polp =3D=3D pol) { + *polp =3D pol->next; + atomic_dec(&pol->refcnt); + return; + } + } +} + +int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *po= l) +{ + struct xfrm_policy *old_pol; + + write_lock_bh(&xfrm_policy_lock); + old_pol =3D sk->policy[dir]; + sk->policy[dir] =3D pol; + if (pol) { + pol->curlft.add_time =3D (unsigned long)xtime.tv_sec; + pol->index =3D xfrm_gen_index(XFRM_POLICY_MAX+dir); + xfrm_sk_policy_link(pol, dir); + } + if (old_pol) + xfrm_sk_policy_unlink(old_pol, dir); + write_unlock_bh(&xfrm_policy_lock); + + if (old_pol) { + xfrm_policy_kill(old_pol); + xfrm_pol_put(old_pol); + } + return 0; +} + +static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) +{ + struct xfrm_policy *newp =3D xfrm_policy_alloc(GFP_ATOMIC); + + if (newp) { + newp->selector =3D old->selector; + newp->lft =3D old->lft; + newp->curlft =3D old->curlft; + newp->action =3D old->action; + newp->flags =3D old->flags; + newp->xfrm_nr =3D old->xfrm_nr; + newp->index =3D old->index; + memcpy(newp->xfrm_vec, old->xfrm_vec, + newp->xfrm_nr*sizeof(struct xfrm_tmpl)); + write_lock_bh(&xfrm_policy_lock); + xfrm_sk_policy_link(newp, dir); + write_unlock_bh(&xfrm_policy_lock); + } + return newp; +} + +int __xfrm_sk_clone_policy(struct sock *sk) +{ + struct xfrm_policy *p0, *p1; + p0 =3D sk->policy[0]; + p1 =3D sk->policy[1]; + sk->policy[0] =3D NULL; + sk->policy[1] =3D NULL; + if (p0 && (sk->policy[0] =3D clone_policy(p0, 0)) =3D=3D NULL) + return -ENOMEM; + if (p1 && (sk->policy[1] =3D clone_policy(p1, 1)) =3D=3D NULL) + return -ENOMEM; + return 0; +} + +void __xfrm_sk_free_policy(struct xfrm_policy *pol, int dir) +{ + write_lock_bh(&xfrm_policy_lock); + xfrm_sk_policy_unlink(pol, dir); + write_unlock_bh(&xfrm_policy_lock); + + xfrm_policy_kill(pol); + xfrm_pol_put(pol); +} + +/* Resolve list of templates for the flow, given policy. */ + +static int +xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, + struct xfrm_state **xfrm, + unsigned short family) +{ + int nx; + int i, error; + xfrm_address_t *daddr =3D xfrm_flowi_daddr(fl, family); + xfrm_address_t *saddr =3D xfrm_flowi_saddr(fl, family); + + for (nx=3D0, i =3D 0; i < policy->xfrm_nr; i++) { + struct xfrm_state *x; + xfrm_address_t *remote =3D daddr; + xfrm_address_t *local =3D saddr; + struct xfrm_tmpl *tmpl =3D &policy->xfrm_vec[i]; + + if (tmpl->mode) { + remote =3D &tmpl->id.daddr; + local =3D &tmpl->saddr; + } + + x =3D xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); + + if (x && x->km.state =3D=3D XFRM_STATE_VALID) { + xfrm[nx++] =3D x; + daddr =3D remote; + saddr =3D local; + continue; + } + if (x) { + error =3D (x->km.state =3D=3D XFRM_STATE_ERROR ? + -EINVAL : -EAGAIN); + xfrm_state_put(x); + } + + if (!tmpl->optional) + goto fail; + } + return nx; + +fail: + for (nx--; nx>=3D0; nx--) + xfrm_state_put(xfrm[nx]); + return error; +} + +/* Check that the bundle accepts the flow and its components are + * still valid. + */ + +static struct dst_entry * +xfrm_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *= policy, unsigned short family) +{ + struct dst_entry *x; + struct xfrm_policy_afinfo *afinfo =3D xfrm_policy_get_afinfo(family); + if (unlikely(afinfo =3D=3D NULL)) + return ERR_PTR(-EINVAL); + x =3D afinfo->find_bundle(fl, rt, policy); + xfrm_policy_put_afinfo(afinfo); + return x; +} + +/* Allocate chain of dst_entry's, attach known xfrm's, calculate + * all the metrics... Shortly, bundle a bundle. + */ + +static int +xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, i= nt nx, + struct flowi *fl, struct dst_entry **dst_p, + unsigned short family) +{ + int err; + struct xfrm_policy_afinfo *afinfo =3D xfrm_policy_get_afinfo(family); + if (unlikely(afinfo =3D=3D NULL)) + return -EINVAL; + err =3D afinfo->bundle_create(policy, xfrm, nx, fl, dst_p); + xfrm_policy_put_afinfo(afinfo); + return err; +} + +/* Main function: finds/creates a bundle for given flow. + * + * At the moment we eat a raw IP route. Mostly to speed up lookups + * on interfaces with disabled IPsec. + */ +int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, + struct sock *sk, int flags) +{ + struct xfrm_policy *policy; + struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; + struct rtable *rt =3D (struct rtable*)*dst_p; + struct dst_entry *dst; + int nx =3D 0; + int err; + u32 genid; + u16 family =3D (*dst_p)->ops->family; + + switch (family) { + case AF_INET: + if (!fl->fl4_src) + fl->fl4_src =3D rt->rt_src; + if (!fl->fl4_dst) + fl->fl4_dst =3D rt->rt_dst; + case AF_INET6: + /* Still not clear... */ + default: + /* nothing */; + } + +restart: + genid =3D xfrm_policy_genid; + policy =3D NULL; + if (sk && sk->policy[1]) + policy =3D xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); + + if (!policy) { + /* To accelerate a bit... */ + if ((rt->u.dst.flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]= ) + return 0; + + policy =3D flow_lookup(XFRM_POLICY_OUT, fl, family); + } + + if (!policy) + return 0; + + policy->curlft.use_time =3D (unsigned long)xtime.tv_sec; + + switch (policy->action) { + case XFRM_POLICY_BLOCK: + /* Prohibit the flow */ + xfrm_pol_put(policy); + return -EPERM; + + case XFRM_POLICY_ALLOW: + if (policy->xfrm_nr =3D=3D 0) { + /* Flow passes not transformed. */ + xfrm_pol_put(policy); + return 0; + } + + /* Try to find matching bundle. + * + * LATER: help from flow cache. It is optional, this + * is required only for output policy. + */ + dst =3D xfrm_find_bundle(fl, rt, policy, family); + if (IS_ERR(dst)) { + xfrm_pol_put(policy); + return PTR_ERR(dst); + } + + if (dst) + break; + + nx =3D xfrm_tmpl_resolve(policy, fl, xfrm, family); + + if (unlikely(nx<0)) { + err =3D nx; + if (err =3D=3D -EAGAIN) { + struct task_struct *tsk =3D current; + DECLARE_WAITQUEUE(wait, tsk); + if (!flags) + goto error; + + __set_task_state(tsk, TASK_INTERRUPTIBLE); + add_wait_queue(&km_waitq, &wait); + err =3D xfrm_tmpl_resolve(policy, fl, xfrm, family); + if (err =3D=3D -EAGAIN) + schedule(); + __set_task_state(tsk, TASK_RUNNING); + remove_wait_queue(&km_waitq, &wait); + + if (err =3D=3D -EAGAIN && signal_pending(current)) { + err =3D -ERESTART; + goto error; + } + if (err =3D=3D -EAGAIN || + genid !=3D xfrm_policy_genid) + goto restart; + } + if (err) + goto error; + } else if (nx =3D=3D 0) { + /* Flow passes not transformed. */ + xfrm_pol_put(policy); + return 0; + } + + dst =3D &rt->u.dst; + err =3D xfrm_bundle_create(policy, xfrm, nx, fl, &dst, family); + + if (unlikely(err)) { + int i; + for (i=3D0; ilock); + if (unlikely(policy->dead)) { + /* Wow! While we worked on resolving, this + * policy has gone. Retry. It is not paranoia, + * we just cannot enlist new bundle to dead object. + */ + write_unlock_bh(&policy->lock); + + xfrm_pol_put(policy); + if (dst) + dst_free(dst); + goto restart; + } + dst->next =3D policy->bundles; + policy->bundles =3D dst; + dst_hold(dst); + write_unlock_bh(&policy->lock); + } + *dst_p =3D dst; + ip_rt_put(rt); + xfrm_pol_put(policy); + return 0; + +error: + ip_rt_put(rt); + xfrm_pol_put(policy); + *dst_p =3D NULL; + return err; +} + +/* When skb is transformed back to its "native" form, we have to + * check policy restrictions. At the moment we make this in maximally + * stupid way. Shame on me. :-) Of course, connected sockets must + * have policy cached at them. + */ + +static inline int +xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x,=20 + unsigned short family) +{ + return x->id.proto =3D=3D tmpl->id.proto && + (x->id.spi =3D=3D tmpl->id.spi || !tmpl->id.spi) && + x->props.mode =3D=3D tmpl->mode && + (tmpl->aalgos & (1<props.aalgo)) && + !(x->props.mode && xfrm_state_addr_cmp(tmpl, x, family)); +} + +static inline int +xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int idx, + unsigned short family) +{ + for (; idx < sp->len; idx++) { + if (xfrm_state_ok(tmpl, sp->x[idx].xvec, family)) + return ++idx; + } + return -1; +} + +static int +_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short fami= ly) +{ + struct xfrm_policy_afinfo *afinfo =3D xfrm_policy_get_afinfo(family); + + if (unlikely(afinfo =3D=3D NULL)) + return -EAFNOSUPPORT; + + afinfo->decode_session(skb, fl); + xfrm_policy_put_afinfo(afinfo); + return 0; +} + +int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,=20 + unsigned short family) +{ + struct xfrm_policy *pol; + struct flowi fl; + + if (_decode_session(skb, &fl, family) < 0) + return 0; + + /* First, check used SA against their selectors. */ + if (skb->sp) { + int i; + + for (i=3Dskb->sp->len-1; i>=3D0; i--) { + struct sec_decap_state *xvec =3D &(skb->sp->x[i]); + if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) + return 0; + + /* If there is a post_input processor, try running it */ + if (xvec->xvec->type->post_input && + (xvec->xvec->type->post_input)(xvec->xvec, + &(xvec->decap), + skb) !=3D 0) + return 0; + } + } + + pol =3D NULL; + if (sk && sk->policy[dir]) + pol =3D xfrm_sk_policy_lookup(sk, dir, &fl); + + if (!pol) + pol =3D flow_lookup(dir, &fl, family); + + if (!pol) + return 1; + + pol->curlft.use_time =3D (unsigned long)xtime.tv_sec; + + if (pol->action =3D=3D XFRM_POLICY_ALLOW) { + if (pol->xfrm_nr !=3D 0) { + struct sec_path *sp; + static struct sec_path dummy; + int i, k; + + if ((sp =3D skb->sp) =3D=3D NULL) + sp =3D &dummy; + + /* For each tmpl search corresponding xfrm. + * Order is _important_. Later we will implement + * some barriers, but at the moment barriers + * are implied between each two transformations. + */ + for (i =3D pol->xfrm_nr-1, k =3D 0; i >=3D 0; i--) { + if (pol->xfrm_vec[i].optional) + continue; + k =3D xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); + if (k < 0) + goto reject; + } + } + xfrm_pol_put(pol); + return 1; + } + +reject: + xfrm_pol_put(pol); + return 0; +} + +int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) +{ + struct flowi fl; + + if (_decode_session(skb, &fl, family) < 0) + return 0; + + return xfrm_lookup(&skb->dst, &fl, NULL, 0) =3D=3D 0; +} + +/* Optimize later using cookies and generation ids. */ + +static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) +{ + struct dst_entry *child =3D dst; + + while (child) { + if (child->obsolete > 0 || + (child->xfrm && child->xfrm->km.state !=3D XFRM_STATE_VALID)) { + dst_release(dst); + return NULL; + } + child =3D child->child; + } + + return dst; +} + +static void xfrm_dst_destroy(struct dst_entry *dst) +{ + xfrm_state_put(dst->xfrm); + dst->xfrm =3D NULL; +} + +static void xfrm_link_failure(struct sk_buff *skb) +{ + /* Impossible. Such dst must be popped before reaches point of failure. *= / + return; +} + +static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) +{ + if (dst) { + if (dst->obsolete) { + dst_release(dst); + dst =3D NULL; + } + } + return dst; +} + +static void __xfrm_garbage_collect(void) +{ + int i; + struct xfrm_policy *pol; + struct dst_entry *dst, **dstp, *gc_list =3D NULL; + + read_lock_bh(&xfrm_policy_lock); + for (i=3D0; i<2*XFRM_POLICY_MAX; i++) { + for (pol =3D xfrm_policy_list[i]; pol; pol =3D pol->next) { + write_lock(&pol->lock); + dstp =3D &pol->bundles; + while ((dst=3D*dstp) !=3D NULL) { + if (atomic_read(&dst->__refcnt) =3D=3D 0) { + *dstp =3D dst->next; + dst->next =3D gc_list; + gc_list =3D dst; + } else { + dstp =3D &dst->next; + } + } + write_unlock(&pol->lock); + } + } + read_unlock_bh(&xfrm_policy_lock); + + while (gc_list) { + dst =3D gc_list; + gc_list =3D dst->next; + dst_free(dst); + } +} + +static int bundle_depends_on(struct dst_entry *dst, struct xfrm_state *x) +{ + do { + if (dst->xfrm =3D=3D x) + return 1; + } while ((dst =3D dst->child) !=3D NULL); + return 0; +} + +int xfrm_flush_bundles(struct xfrm_state *x) +{ + int i; + struct xfrm_policy *pol; + struct dst_entry *dst, **dstp, *gc_list =3D NULL; + + read_lock_bh(&xfrm_policy_lock); + for (i=3D0; i<2*XFRM_POLICY_MAX; i++) { + for (pol =3D xfrm_policy_list[i]; pol; pol =3D pol->next) { + write_lock(&pol->lock); + dstp =3D &pol->bundles; + while ((dst=3D*dstp) !=3D NULL) { + if (bundle_depends_on(dst, x)) { + *dstp =3D dst->next; + dst->next =3D gc_list; + gc_list =3D dst; + } else { + dstp =3D &dst->next; + } + } + write_unlock(&pol->lock); + } + } + read_unlock_bh(&xfrm_policy_lock); + + while (gc_list) { + dst =3D gc_list; + gc_list =3D dst->next; + dst_free(dst); + } + + return 0; +} + +/* Well... that's _TASK_. We need to scan through transformation + * list and figure out what mss tcp should generate in order to + * final datagram fit to mtu. Mama mia... :-) + * + * Apparently, some easy way exists, but we used to choose the most + * bizarre ones. :-) So, raising Kalashnikov... tra-ta-ta. + * + * Consider this function as something like dark humour. :-) + */ +static int xfrm_get_mss(struct dst_entry *dst, u32 mtu) +{ + int res =3D mtu - dst->header_len; + + for (;;) { + struct dst_entry *d =3D dst; + int m =3D res; + + do { + struct xfrm_state *x =3D d->xfrm; + if (x) { + spin_lock_bh(&x->lock); + if (x->km.state =3D=3D XFRM_STATE_VALID && + x->type && x->type->get_max_size) + m =3D x->type->get_max_size(d->xfrm, m); + else + m +=3D x->props.header_len; + spin_unlock_bh(&x->lock); + } + } while ((d =3D d->child) !=3D NULL); + + if (m <=3D mtu) + break; + res -=3D (m - mtu); + if (res < 88) + return mtu; + } + + return res + dst->header_len; +} + +int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) +{ + int err =3D 0; + if (unlikely(afinfo =3D=3D NULL)) + return -EINVAL; + if (unlikely(afinfo->family >=3D NPROTO)) + return -EAFNOSUPPORT; + write_lock(&xfrm_policy_afinfo_lock); + if (unlikely(xfrm_policy_afinfo[afinfo->family] !=3D NULL)) + err =3D -ENOBUFS; + else { + struct dst_ops *dst_ops =3D afinfo->dst_ops; + if (likely(dst_ops->kmem_cachep =3D=3D NULL)) + dst_ops->kmem_cachep =3D xfrm_dst_cache; + if (likely(dst_ops->check =3D=3D NULL)) + dst_ops->check =3D xfrm_dst_check; + if (likely(dst_ops->destroy =3D=3D NULL)) + dst_ops->destroy =3D xfrm_dst_destroy; + if (likely(dst_ops->negative_advice =3D=3D NULL)) + dst_ops->negative_advice =3D xfrm_negative_advice; + if (likely(dst_ops->link_failure =3D=3D NULL)) + dst_ops->link_failure =3D xfrm_link_failure; + if (likely(dst_ops->get_mss =3D=3D NULL)) + dst_ops->get_mss =3D xfrm_get_mss; + if (likely(afinfo->garbage_collect =3D=3D NULL)) + afinfo->garbage_collect =3D __xfrm_garbage_collect; + xfrm_policy_afinfo[afinfo->family] =3D afinfo; + } + write_unlock(&xfrm_policy_afinfo_lock); + return err; +} + +int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) +{ + int err =3D 0; + if (unlikely(afinfo =3D=3D NULL)) + return -EINVAL; + if (unlikely(afinfo->family >=3D NPROTO)) + return -EAFNOSUPPORT; + write_lock(&xfrm_policy_afinfo_lock); + if (likely(xfrm_policy_afinfo[afinfo->family] !=3D NULL)) { + if (unlikely(xfrm_policy_afinfo[afinfo->family] !=3D afinfo)) + err =3D -EINVAL; + else { + struct dst_ops *dst_ops =3D afinfo->dst_ops; + xfrm_policy_afinfo[afinfo->family] =3D NULL; + dst_ops->kmem_cachep =3D NULL; + dst_ops->check =3D NULL; + dst_ops->destroy =3D NULL; + dst_ops->negative_advice =3D NULL; + dst_ops->link_failure =3D NULL; + dst_ops->get_mss =3D NULL; + afinfo->garbage_collect =3D NULL; + } + } + write_unlock(&xfrm_policy_afinfo_lock); + return err; +} + +struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) +{ + struct xfrm_policy_afinfo *afinfo; + if (unlikely(family >=3D NPROTO)) + return NULL; + read_lock(&xfrm_policy_afinfo_lock); + afinfo =3D xfrm_policy_afinfo[family]; + if (likely(afinfo !=3D NULL)) + read_lock(&afinfo->lock); + read_unlock(&xfrm_policy_afinfo_lock); + return afinfo; +} + +void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) +{ + if (unlikely(afinfo =3D=3D NULL)) + return; + read_unlock(&afinfo->lock); +} + +void __init xfrm_policy_init(void) +{ + xfrm_dst_cache =3D kmem_cache_create("xfrm_dst_cache", + sizeof(struct xfrm_dst), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!xfrm_dst_cache) + panic("XFRM: failed to allocate xfrm_dst_cache\n"); +} + +void __init xfrm_init(void) +{ + xfrm_state_init(); + flow_cache_init(); + xfrm_policy_init(); +} + diff -Nru a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/xfrm/xfrm_state.c Thu May 8 10:41:38 2003 @@ -0,0 +1,803 @@ +/* + * xfrm_state.c + * + * Changes: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro + * IPv6 support + * YOSHIFUJI Hideaki @USAGI + * Split up af-specific functions + * Derek Atkins + * Add UDP Encapsulation + * =09 + */ + +#include +#include +#include +#include +#include + +/* Each xfrm_state may be linked to two tables: + + 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) + 2. Hash table by daddr to find what SAs exist for given + destination/tunnel endpoint. (output) + */ + +static spinlock_t xfrm_state_lock =3D SPIN_LOCK_UNLOCKED; + +/* Hash table to find appropriate SA towards given target (endpoint + * of tunnel or destination of transport mode) allowed by selector. + * + * Main use is finding SA after policy selected tunnel or transport mode. + * Also, it can be used by ah/esp icmp error handler to find offending SA. + */ +static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE]; +static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; + +DECLARE_WAIT_QUEUE_HEAD(km_waitq); + +static rwlock_t xfrm_state_afinfo_lock =3D RW_LOCK_UNLOCKED; +static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; + +static struct tq_struct xfrm_state_gc_work; +static struct list_head xfrm_state_gc_list =3D LIST_HEAD_INIT(xfrm_state_g= c_list); +static spinlock_t xfrm_state_gc_lock =3D SPIN_LOCK_UNLOCKED; + +static void __xfrm_state_delete(struct xfrm_state *x); + +static void xfrm_state_gc_destroy(struct xfrm_state *x) +{ + if (del_timer(&x->timer)) + BUG(); + if (x->aalg) + kfree(x->aalg); + if (x->ealg) + kfree(x->ealg); + if (x->calg) + kfree(x->calg); + if (x->encap) + kfree(x->encap); + if (x->type) { + x->type->destructor(x); + xfrm_put_type(x->type); + } + kfree(x); + wake_up(&km_waitq); +} + +static void xfrm_state_gc_task(void *data) +{ + struct xfrm_state *x; + struct list_head *entry, *tmp; + struct list_head gc_list =3D LIST_HEAD_INIT(gc_list); + + spin_lock_bh(&xfrm_state_gc_lock); + list_splice_init(&xfrm_state_gc_list, &gc_list); + spin_unlock_bh(&xfrm_state_gc_lock); + + list_for_each_safe(entry, tmp, &gc_list) { + x =3D list_entry(entry, struct xfrm_state, bydst); + xfrm_state_gc_destroy(x); + } +} + +static inline unsigned long make_jiffies(long secs) +{ + if (secs >=3D (MAX_SCHEDULE_TIMEOUT-1)/HZ) + return MAX_SCHEDULE_TIMEOUT-1; + else + return secs*HZ; +} + +static void xfrm_timer_handler(unsigned long data) +{ + struct xfrm_state *x =3D (struct xfrm_state*)data; + unsigned long now =3D (unsigned long)xtime.tv_sec; + long next =3D LONG_MAX; + int warn =3D 0; + + spin_lock(&x->lock); + if (x->km.state =3D=3D XFRM_STATE_DEAD) + goto out; + if (x->km.state =3D=3D XFRM_STATE_EXPIRED) + goto expired; + if (x->lft.hard_add_expires_seconds) { + long tmo =3D x->lft.hard_add_expires_seconds + + x->curlft.add_time - now; + if (tmo <=3D 0) + goto expired; + if (tmo < next) + next =3D tmo; + } + if (x->lft.hard_use_expires_seconds && x->curlft.use_time) { + long tmo =3D x->lft.hard_use_expires_seconds + + x->curlft.use_time - now; + if (tmo <=3D 0) + goto expired; + if (tmo < next) + next =3D tmo; + } + if (x->km.dying) + goto resched; + if (x->lft.soft_add_expires_seconds) { + long tmo =3D x->lft.soft_add_expires_seconds + + x->curlft.add_time - now; + if (tmo <=3D 0) + warn =3D 1; + else if (tmo < next) + next =3D tmo; + } + if (x->lft.soft_use_expires_seconds && x->curlft.use_time) { + long tmo =3D x->lft.soft_use_expires_seconds + + x->curlft.use_time - now; + if (tmo <=3D 0) + warn =3D 1; + else if (tmo < next) + next =3D tmo; + } + + if (warn) + km_warn_expired(x); +resched: + if (next !=3D LONG_MAX && + !mod_timer(&x->timer, jiffies + make_jiffies(next))) + atomic_inc(&x->refcnt); + goto out; + +expired: + if (x->km.state =3D=3D XFRM_STATE_ACQ && x->id.spi =3D=3D 0) { + x->km.state =3D XFRM_STATE_EXPIRED; + wake_up(&km_waitq); + next =3D 2; + goto resched; + } + if (x->id.spi !=3D 0) + km_expired(x); + __xfrm_state_delete(x); + +out: + spin_unlock(&x->lock); + xfrm_state_put(x); +} + +struct xfrm_state *xfrm_state_alloc(void) +{ + struct xfrm_state *x; + + x =3D kmalloc(sizeof(struct xfrm_state), GFP_ATOMIC); + + if (x) { + memset(x, 0, sizeof(struct xfrm_state)); + atomic_set(&x->refcnt, 1); + INIT_LIST_HEAD(&x->bydst); + INIT_LIST_HEAD(&x->byspi); + init_timer(&x->timer); + x->timer.function =3D xfrm_timer_handler; + x->timer.data =3D (unsigned long)x; + x->curlft.add_time =3D (unsigned long)xtime.tv_sec; + x->lft.soft_byte_limit =3D XFRM_INF; + x->lft.soft_packet_limit =3D XFRM_INF; + x->lft.hard_byte_limit =3D XFRM_INF; + x->lft.hard_packet_limit =3D XFRM_INF; + x->lock =3D SPIN_LOCK_UNLOCKED; + } + return x; +} + +void __xfrm_state_destroy(struct xfrm_state *x) +{ + BUG_TRAP(x->km.state =3D=3D XFRM_STATE_DEAD); + + spin_lock_bh(&xfrm_state_gc_lock); + list_add(&x->bydst, &xfrm_state_gc_list); + spin_unlock_bh(&xfrm_state_gc_lock); + schedule_task(&xfrm_state_gc_work); +} + +static void __xfrm_state_delete(struct xfrm_state *x) +{ + if (x->km.state !=3D XFRM_STATE_DEAD) { + x->km.state =3D XFRM_STATE_DEAD; + spin_lock(&xfrm_state_lock); + list_del(&x->bydst); + atomic_dec(&x->refcnt); + if (x->id.spi) { + list_del(&x->byspi); + atomic_dec(&x->refcnt); + } + spin_unlock(&xfrm_state_lock); + if (del_timer(&x->timer)) + atomic_dec(&x->refcnt); + + /* The number two in this test is the reference + * mentioned in the comment below plus the reference + * our caller holds. A larger value means that + * there are DSTs attached to this xfrm_state. + */ + if (atomic_read(&x->refcnt) > 2) + xfrm_flush_bundles(x); + + /* All xfrm_state objects are created by one of two possible + * paths: + * + * 2) xfrm_state_lookup --> xfrm_state_insert + * + * The xfrm_state_lookup or xfrm_state_alloc call gives a + * reference, and that is what we are dropping here. + */ + atomic_dec(&x->refcnt); + } +} + +void xfrm_state_delete(struct xfrm_state *x) +{ + spin_lock_bh(&x->lock); + __xfrm_state_delete(x); + spin_unlock_bh(&x->lock); +} + +void xfrm_state_flush(u8 proto) +{ + int i; + struct xfrm_state *x; + + spin_lock_bh(&xfrm_state_lock); + for (i =3D 0; i < XFRM_DST_HSIZE; i++) { +restart: + list_for_each_entry(x, xfrm_state_bydst+i, bydst) { + if (proto =3D=3D IPSEC_PROTO_ANY || x->id.proto =3D=3D proto) { + atomic_inc(&x->refcnt); + spin_unlock_bh(&xfrm_state_lock); + + xfrm_state_delete(x); + xfrm_state_put(x); + + spin_lock_bh(&xfrm_state_lock); + goto restart; + } + } + } + spin_unlock_bh(&xfrm_state_lock); + wake_up(&km_waitq); +} + +static int +xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, + struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr, + unsigned short family) +{ + struct xfrm_state_afinfo *afinfo =3D xfrm_state_get_afinfo(family); + if (!afinfo) + return -1; + afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); + xfrm_state_put_afinfo(afinfo); + return 0; +} + +struct xfrm_state * +xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,=20 + struct flowi *fl, struct xfrm_tmpl *tmpl, + struct xfrm_policy *pol, int *err, + unsigned short family) +{ + unsigned h =3D xfrm_dst_hash(daddr, family); + struct xfrm_state *x; + int acquire_in_progress =3D 0; + int error =3D 0; + struct xfrm_state *best =3D NULL; + + spin_lock_bh(&xfrm_state_lock); + list_for_each_entry(x, xfrm_state_bydst+h, bydst) { + if (x->props.family =3D=3D family && + x->props.reqid =3D=3D tmpl->reqid && + xfrm_state_addr_check(x, daddr, saddr, family) && + tmpl->mode =3D=3D x->props.mode && + tmpl->id.proto =3D=3D x->id.proto) { + /* Resolution logic: + 1. There is a valid state with matching selector. + Done. + 2. Valid state with inappropriate selector. Skip. + + Entering area of "sysdeps". + + 3. If state is not valid, selector is temporary, + it selects only session which triggered + previous resolution. Key manager will do + something to install a state with proper + selector. + */ + if (x->km.state =3D=3D XFRM_STATE_VALID) { + if (!xfrm_selector_match(&x->sel, fl, family)) + continue; + if (!best || + best->km.dying > x->km.dying || + (best->km.dying =3D=3D x->km.dying && + best->curlft.add_time < x->curlft.add_time)) + best =3D x; + } else if (x->km.state =3D=3D XFRM_STATE_ACQ) { + acquire_in_progress =3D 1; + } else if (x->km.state =3D=3D XFRM_STATE_ERROR || + x->km.state =3D=3D XFRM_STATE_EXPIRED) { + if (xfrm_selector_match(&x->sel, fl, family)) + error =3D 1; + } + } + } + + if (best) { + atomic_inc(&best->refcnt); + spin_unlock_bh(&xfrm_state_lock); + return best; + } + + x =3D NULL; + if (!error && !acquire_in_progress && + ((x =3D xfrm_state_alloc()) !=3D NULL)) { + /* Initialize temporary selector matching only + * to current session. */ + xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); + + if (km_query(x, tmpl, pol) =3D=3D 0) { + x->km.state =3D XFRM_STATE_ACQ; + list_add_tail(&x->bydst, xfrm_state_bydst+h); + atomic_inc(&x->refcnt); + if (x->id.spi) { + h =3D xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); + list_add(&x->byspi, xfrm_state_byspi+h); + atomic_inc(&x->refcnt); + } + x->lft.hard_add_expires_seconds =3D XFRM_ACQ_EXPIRES; + atomic_inc(&x->refcnt); + mod_timer(&x->timer, XFRM_ACQ_EXPIRES*HZ); + } else { + x->km.state =3D XFRM_STATE_DEAD; + xfrm_state_put(x); + x =3D NULL; + error =3D 1; + } + } + spin_unlock_bh(&xfrm_state_lock); + if (!x) + *err =3D acquire_in_progress ? -EAGAIN : + (error ? -ESRCH : -ENOMEM); + return x; +} + +void xfrm_state_insert(struct xfrm_state *x) +{ + unsigned h =3D xfrm_dst_hash(&x->id.daddr, x->props.family); + + spin_lock_bh(&xfrm_state_lock); + list_add(&x->bydst, xfrm_state_bydst+h); + atomic_inc(&x->refcnt); + + h =3D xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family= ); + + list_add(&x->byspi, xfrm_state_byspi+h); + atomic_inc(&x->refcnt); + + if (!mod_timer(&x->timer, jiffies + HZ)) + atomic_inc(&x->refcnt); + + spin_unlock_bh(&xfrm_state_lock); + wake_up(&km_waitq); +} + +int xfrm_state_check_expire(struct xfrm_state *x) +{ + if (!x->curlft.use_time) + x->curlft.use_time =3D (unsigned long)xtime.tv_sec; + + if (x->km.state !=3D XFRM_STATE_VALID) + return -EINVAL; + + if (x->curlft.bytes >=3D x->lft.hard_byte_limit || + x->curlft.packets >=3D x->lft.hard_packet_limit) { + km_expired(x); + if (!mod_timer(&x->timer, jiffies + XFRM_ACQ_EXPIRES*HZ)) + atomic_inc(&x->refcnt); + return -EINVAL; + } + + if (!x->km.dying && + (x->curlft.bytes >=3D x->lft.soft_byte_limit || + x->curlft.packets >=3D x->lft.soft_packet_limit)) + km_warn_expired(x); + return 0; +} + +int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) +{ + int nhead =3D x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev) + - skb_headroom(skb); + + if (nhead > 0) + return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); + + /* Check tail too... */ + return 0; +} + +struct xfrm_state * +xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, + unsigned short family) +{ + struct xfrm_state *x; + struct xfrm_state_afinfo *afinfo =3D xfrm_state_get_afinfo(family); + if (!afinfo) + return NULL; + + spin_lock_bh(&xfrm_state_lock); + x =3D afinfo->state_lookup(daddr, spi, proto); + spin_unlock_bh(&xfrm_state_lock); + xfrm_state_put_afinfo(afinfo); + return x; +} + +struct xfrm_state * +xfrm_find_acq(u8 mode, u16 reqid, u8 proto,=20 + xfrm_address_t *daddr, xfrm_address_t *saddr,=20 + int create, unsigned short family) +{ + struct xfrm_state *x; + struct xfrm_state_afinfo *afinfo =3D xfrm_state_get_afinfo(family); + if (!afinfo) + return NULL; + + spin_lock_bh(&xfrm_state_lock); + x =3D afinfo->find_acq(mode, reqid, proto, daddr, saddr, create); + spin_unlock_bh(&xfrm_state_lock); + xfrm_state_put_afinfo(afinfo); + return x; +} + +/* Silly enough, but I'm lazy to build resolution list */ + +struct xfrm_state * xfrm_find_acq_byseq(u32 seq) +{ + int i; + struct xfrm_state *x; + + spin_lock_bh(&xfrm_state_lock); + for (i =3D 0; i < XFRM_DST_HSIZE; i++) { + list_for_each_entry(x, xfrm_state_bydst+i, bydst) { + if (x->km.seq =3D=3D seq) { + atomic_inc(&x->refcnt); + spin_unlock_bh(&xfrm_state_lock); + return x; + } + } + } + spin_unlock_bh(&xfrm_state_lock); + return NULL; +} +=20 +u32 xfrm_get_acqseq(void) +{ + u32 res; + static u32 acqseq; + static spinlock_t acqseq_lock =3D SPIN_LOCK_UNLOCKED; + + spin_lock_bh(&acqseq_lock); + res =3D (++acqseq ? : ++acqseq); + spin_unlock_bh(&acqseq_lock); + return res; +} + +void +xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) +{ + u32 h; + struct xfrm_state *x0; + + if (x->id.spi) + return; + + if (minspi =3D=3D maxspi) { + x0 =3D xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.fam= ily); + if (x0) { + xfrm_state_put(x0); + return; + } + x->id.spi =3D minspi; + } else { + u32 spi =3D 0; + minspi =3D ntohl(minspi); + maxspi =3D ntohl(maxspi); + for (h=3D0; hid.daddr, minspi, x->id.proto, x->props.fa= mily); + if (x0 =3D=3D NULL) + break; + xfrm_state_put(x0); + } + x->id.spi =3D htonl(spi); + } + if (x->id.spi) { + spin_lock_bh(&xfrm_state_lock); + h =3D xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.famil= y); + list_add(&x->byspi, xfrm_state_byspi+h); + atomic_inc(&x->refcnt); + spin_unlock_bh(&xfrm_state_lock); + wake_up(&km_waitq); + } +} + +int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*)= , + void *data) +{ + int i; + struct xfrm_state *x; + int count =3D 0; + int err =3D 0; + + spin_lock_bh(&xfrm_state_lock); + for (i =3D 0; i < XFRM_DST_HSIZE; i++) { + list_for_each_entry(x, xfrm_state_bydst+i, bydst) { + if (proto =3D=3D IPSEC_PROTO_ANY || x->id.proto =3D=3D proto) + count++; + } + } + if (count =3D=3D 0) { + err =3D -ENOENT; + goto out; + } + + for (i =3D 0; i < XFRM_DST_HSIZE; i++) { + list_for_each_entry(x, xfrm_state_bydst+i, bydst) { + if (proto !=3D IPSEC_PROTO_ANY && x->id.proto !=3D proto) + continue; + err =3D func(x, --count, data); + if (err) + goto out; + } + } +out: + spin_unlock_bh(&xfrm_state_lock); + return err; +} + + +int xfrm_replay_check(struct xfrm_state *x, u32 seq) +{ + u32 diff; + + seq =3D ntohl(seq); + + if (unlikely(seq =3D=3D 0)) + return -EINVAL; + + if (likely(seq > x->replay.seq)) + return 0; + + diff =3D x->replay.seq - seq; + if (diff >=3D x->props.replay_window) { + x->stats.replay_window++; + return -EINVAL; + } + + if (x->replay.bitmap & (1U << diff)) { + x->stats.replay++; + return -EINVAL; + } + return 0; +} + +void xfrm_replay_advance(struct xfrm_state *x, u32 seq) +{ + u32 diff; + + seq =3D ntohl(seq); + + if (seq > x->replay.seq) { + diff =3D seq - x->replay.seq; + if (diff < x->props.replay_window) + x->replay.bitmap =3D ((x->replay.bitmap) << diff) | 1; + else + x->replay.bitmap =3D 1; + x->replay.seq =3D seq; + } else { + diff =3D x->replay.seq - seq; + x->replay.bitmap |=3D (1U << diff); + } +} + +int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl) +{ + int i; + + for (i=3D0; isel, fl, x[i]->props.family); + if (!match) + return -EINVAL; + } + return 0; +} + +static struct list_head xfrm_km_list =3D LIST_HEAD_INIT(xfrm_km_list); +static rwlock_t xfrm_km_lock =3D RW_LOCK_UNLOCKED; + +void km_warn_expired(struct xfrm_state *x) +{ + struct xfrm_mgr *km; + + x->km.dying =3D 1; + read_lock(&xfrm_km_lock); + list_for_each_entry(km, &xfrm_km_list, list) + km->notify(x, 0); + read_unlock(&xfrm_km_lock); +} + +void km_expired(struct xfrm_state *x) +{ + struct xfrm_mgr *km; + + x->km.state =3D XFRM_STATE_EXPIRED; + + read_lock(&xfrm_km_lock); + list_for_each_entry(km, &xfrm_km_list, list) + km->notify(x, 1); + read_unlock(&xfrm_km_lock); + wake_up(&km_waitq); +} + +int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy= *pol) +{ + int err =3D -EINVAL; + struct xfrm_mgr *km; + + read_lock(&xfrm_km_lock); + list_for_each_entry(km, &xfrm_km_list, list) { + err =3D km->acquire(x, t, pol, XFRM_POLICY_OUT); + if (!err) + break; + } + read_unlock(&xfrm_km_lock); + return err; +} + +int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport= ) +{ + int err =3D -EINVAL; + struct xfrm_mgr *km; + + read_lock(&xfrm_km_lock); + list_for_each_entry(km, &xfrm_km_list, list) { + if (km->new_mapping) + err =3D km->new_mapping(x, ipaddr, sport); + if (!err) + break; + } + read_unlock(&xfrm_km_lock); + return err; +} + +int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen) +{ + int err; + u8 *data; + struct xfrm_mgr *km; + struct xfrm_policy *pol =3D NULL; + + if (optlen <=3D 0 || optlen > PAGE_SIZE) + return -EMSGSIZE; + + data =3D kmalloc(optlen, GFP_KERNEL); + if (!data) + return -ENOMEM; + + err =3D -EFAULT; + if (copy_from_user(data, optval, optlen)) + goto out; + + err =3D -EINVAL; + read_lock(&xfrm_km_lock); + list_for_each_entry(km, &xfrm_km_list, list) { + pol =3D km->compile_policy(sk->family, optname, data, optlen, &err); + if (err >=3D 0) + break; + } + read_unlock(&xfrm_km_lock); + + if (err >=3D 0) { + xfrm_sk_policy_insert(sk, err, pol); + err =3D 0; + } + +out: + kfree(data); + return err; +} + +int xfrm_register_km(struct xfrm_mgr *km) +{ + write_lock_bh(&xfrm_km_lock); + list_add_tail(&km->list, &xfrm_km_list); + write_unlock_bh(&xfrm_km_lock); + return 0; +} + +int xfrm_unregister_km(struct xfrm_mgr *km) +{ + write_lock_bh(&xfrm_km_lock); + list_del(&km->list); + write_unlock_bh(&xfrm_km_lock); + return 0; +} + +int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) +{ + int err =3D 0; + if (unlikely(afinfo =3D=3D NULL)) + return -EINVAL; + if (unlikely(afinfo->family >=3D NPROTO)) + return -EAFNOSUPPORT; + write_lock(&xfrm_state_afinfo_lock); + if (unlikely(xfrm_state_afinfo[afinfo->family] !=3D NULL)) + err =3D -ENOBUFS; + else { + afinfo->state_bydst =3D xfrm_state_bydst; + afinfo->state_byspi =3D xfrm_state_byspi; + xfrm_state_afinfo[afinfo->family] =3D afinfo; + } + write_unlock(&xfrm_state_afinfo_lock); + return err; +} + +int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) +{ + int err =3D 0; + if (unlikely(afinfo =3D=3D NULL)) + return -EINVAL; + if (unlikely(afinfo->family >=3D NPROTO)) + return -EAFNOSUPPORT; + write_lock(&xfrm_state_afinfo_lock); + if (likely(xfrm_state_afinfo[afinfo->family] !=3D NULL)) { + if (unlikely(xfrm_state_afinfo[afinfo->family] !=3D afinfo)) + err =3D -EINVAL; + else { + xfrm_state_afinfo[afinfo->family] =3D NULL; + afinfo->state_byspi =3D NULL; + afinfo->state_bydst =3D NULL; + } + } + write_unlock(&xfrm_state_afinfo_lock); + return err; +} + +struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) +{ + struct xfrm_state_afinfo *afinfo; + if (unlikely(family >=3D NPROTO)) + return NULL; + read_lock(&xfrm_state_afinfo_lock); + afinfo =3D xfrm_state_afinfo[family]; + if (likely(afinfo !=3D NULL)) + read_lock(&afinfo->lock); + read_unlock(&xfrm_state_afinfo_lock); + return afinfo; +} + +void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) +{ + if (unlikely(afinfo =3D=3D NULL)) + return; + read_unlock(&afinfo->lock); +} + +void __init xfrm_state_init(void) +{ + int i; + + for (i=3D0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct sock *xfrm_nl; + +static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t typ= e) +{ + struct rtattr *rt =3D xfrma[type - 1]; + struct xfrm_algo *algp; + + if (!rt) + return 0; + + if ((rt->rta_len - sizeof(*rt)) < sizeof(*algp)) + return -EINVAL; + + algp =3D RTA_DATA(rt); + switch (type) { + case XFRMA_ALG_AUTH: + if (!algp->alg_key_len && + strcmp(algp->alg_name, "digest_null") !=3D 0) + return -EINVAL; + break; + + case XFRMA_ALG_CRYPT: + if (!algp->alg_key_len && + strcmp(algp->alg_name, "cipher_null") !=3D 0) + return -EINVAL; + break; + + case XFRMA_ALG_COMP: + /* Zero length keys are legal. */ + break; + + default: + return -EINVAL; + }; + + algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] =3D '\0'; + return 0; +} + +static int verify_encap_tmpl(struct rtattr **xfrma) +{ + struct rtattr *rt =3D xfrma[XFRMA_ENCAP - 1]; + struct xfrm_encap_tmpl *encap; + + if (!rt) + return 0; + + if ((rt->rta_len - sizeof(*rt)) < sizeof(*encap)) + return -EINVAL; + + return 0; +} + +static int verify_newsa_info(struct xfrm_usersa_info *p, + struct rtattr **xfrma) +{ + int err; + + err =3D -EINVAL; + switch (p->family) { + case AF_INET: + break; + + case AF_INET6: +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + break; +#else + err =3D -EAFNOSUPPORT; + goto out; +#endif + + default: + goto out; + }; + + err =3D -EINVAL; + switch (p->id.proto) { + case IPPROTO_AH: + if (!xfrma[XFRMA_ALG_AUTH-1] || + xfrma[XFRMA_ALG_CRYPT-1] || + xfrma[XFRMA_ALG_COMP-1]) + goto out; + break; + + case IPPROTO_ESP: + if ((!xfrma[XFRMA_ALG_AUTH-1] && + !xfrma[XFRMA_ALG_CRYPT-1]) || + xfrma[XFRMA_ALG_COMP-1]) + goto out; + break; + + case IPPROTO_COMP: + if (!xfrma[XFRMA_ALG_COMP-1] || + xfrma[XFRMA_ALG_AUTH-1] || + xfrma[XFRMA_ALG_CRYPT-1]) + goto out; + break; + + default: + goto out; + }; + + if ((err =3D verify_one_alg(xfrma, XFRMA_ALG_AUTH))) + goto out; + if ((err =3D verify_one_alg(xfrma, XFRMA_ALG_CRYPT))) + goto out; + if ((err =3D verify_one_alg(xfrma, XFRMA_ALG_COMP))) + goto out; + if ((err =3D verify_encap_tmpl(xfrma))) + goto out; + + err =3D -EINVAL; + switch (p->mode) { + case 0: + case 1: + break; + + default: + goto out; + }; + + err =3D 0; + +out: + return err; +} + +static int attach_one_algo(struct xfrm_algo **algpp, struct rtattr *u_arg) +{ + struct rtattr *rta =3D u_arg; + struct xfrm_algo *p, *ualg; + + if (!rta) + return 0; + + ualg =3D RTA_DATA(rta); + p =3D kmalloc(sizeof(*ualg) + ualg->alg_key_len, GFP_KERNEL); + if (!p) + return -ENOMEM; + + memcpy(p, ualg, sizeof(*ualg) + ualg->alg_key_len); + *algpp =3D p; + return 0; +} + +static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtatt= r *u_arg) +{ + struct rtattr *rta =3D u_arg; + struct xfrm_encap_tmpl *p, *uencap; + + if (!rta) + return 0; + + uencap =3D RTA_DATA(rta); + p =3D kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + memcpy(p, uencap, sizeof(*p)); + *encapp =3D p; + return 0; +} + +static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_= info *p) +{ + memcpy(&x->id, &p->id, sizeof(x->id)); + memcpy(&x->sel, &p->sel, sizeof(x->sel)); + memcpy(&x->lft, &p->lft, sizeof(x->lft)); + x->props.mode =3D p->mode; + x->props.replay_window =3D p->replay_window; + x->props.reqid =3D p->reqid; + x->props.family =3D p->family; + x->props.saddr =3D x->sel.saddr; +} + +static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, + struct rtattr **xfrma, + int *errp) +{ + struct xfrm_state *x =3D xfrm_state_alloc(); + int err =3D -ENOMEM; + + if (!x) + goto error_no_put; + + copy_from_user_state(x, p); + + if ((err =3D attach_one_algo(&x->aalg, xfrma[XFRMA_ALG_AUTH-1]))) + goto error; + if ((err =3D attach_one_algo(&x->ealg, xfrma[XFRMA_ALG_CRYPT-1]))) + goto error; + if ((err =3D attach_one_algo(&x->calg, xfrma[XFRMA_ALG_COMP-1]))) + goto error; + if ((err =3D attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) + goto error; + + err =3D -ENOENT; + x->type =3D xfrm_get_type(x->id.proto, x->props.family); + if (x->type =3D=3D NULL) + goto error; + + err =3D x->type->init_state(x, NULL); + if (err) + goto error; + + x->curlft.add_time =3D (unsigned long) xtime.tv_sec; + x->km.state =3D XFRM_STATE_VALID; + x->km.seq =3D p->seq; + + return x; + +error: + xfrm_state_put(x); +error_no_put: + *errp =3D err; + return NULL; +} + +static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **x= frma) +{ + struct xfrm_usersa_info *p =3D NLMSG_DATA(nlh); + struct xfrm_state *x, *x1; + int err; + + err =3D verify_newsa_info(p, (struct rtattr **) xfrma); + if (err) + return err; + + x =3D xfrm_state_construct(p, (struct rtattr **) xfrma, &err); + if (!x) + return err; + + x1 =3D xfrm_state_lookup(&x->props.saddr, x->id.spi, x->id.proto, x->prop= s.family); + if (x1) { + xfrm_state_put(x); + xfrm_state_put(x1); + return -EEXIST; + } + + xfrm_state_insert(x); + + return 0; +} + +static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **x= frma) +{ + struct xfrm_state *x; + struct xfrm_usersa_id *p =3D NLMSG_DATA(nlh); + + x =3D xfrm_state_lookup(&p->saddr, p->spi, p->proto, p->family); + if (x =3D=3D NULL) + return -ESRCH; + + xfrm_state_delete(x); + xfrm_state_put(x); + + return 0; +} + +static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_in= fo *p) +{ + memcpy(&p->id, &x->id, sizeof(p->id)); + memcpy(&p->sel, &x->sel, sizeof(p->sel)); + memcpy(&p->lft, &x->lft, sizeof(p->lft)); + memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); + memcpy(&p->stats, &x->stats, sizeof(p->stats)); + p->mode =3D x->props.mode; + p->replay_window =3D x->props.replay_window; + p->reqid =3D x->props.reqid; + p->family =3D x->props.family; + p->seq =3D x->km.seq; +} + +struct xfrm_dump_info { + struct sk_buff *in_skb; + struct sk_buff *out_skb; + u32 nlmsg_seq; + int start_idx; + int this_idx; +}; + +static int dump_one_state(struct xfrm_state *x, int count, void *ptr) +{ + struct xfrm_dump_info *sp =3D ptr; + struct sk_buff *in_skb =3D sp->in_skb; + struct sk_buff *skb =3D sp->out_skb; + struct xfrm_usersa_info *p; + struct nlmsghdr *nlh; + unsigned char *b =3D skb->tail; + + if (sp->this_idx < sp->start_idx) + goto out; + + nlh =3D NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, + sp->nlmsg_seq, + XFRM_MSG_NEWSA, sizeof(*p)); + nlh->nlmsg_flags =3D 0; + + p =3D NLMSG_DATA(nlh); + copy_to_user_state(x, p); + + if (x->aalg) + RTA_PUT(skb, XFRMA_ALG_AUTH, + sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); + if (x->ealg) + RTA_PUT(skb, XFRMA_ALG_CRYPT, + sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); + if (x->calg) + RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); + + if (x->encap) + RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); + + nlh->nlmsg_len =3D skb->tail - b; +out: + sp->this_idx++; + return 0; + +nlmsg_failure: +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct xfrm_dump_info info; + + info.in_skb =3D cb->skb; + info.out_skb =3D skb; + info.nlmsg_seq =3D cb->nlh->nlmsg_seq; + info.this_idx =3D 0; + info.start_idx =3D cb->args[0]; + (void) xfrm_state_walk(IPSEC_PROTO_ANY, dump_one_state, &info); + cb->args[0] =3D info.this_idx; + + return skb->len; +} + +static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, + struct xfrm_state *x, u32 seq) +{ + struct xfrm_dump_info info; + struct sk_buff *skb; + + skb =3D alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + NETLINK_CB(skb).dst_pid =3D NETLINK_CB(in_skb).pid; + info.in_skb =3D in_skb; + info.out_skb =3D skb; + info.nlmsg_seq =3D seq; + info.this_idx =3D info.start_idx =3D 0; + + if (dump_one_state(x, 0, &info)) { + kfree_skb(skb); + return NULL; + } + + return skb; +} + +static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **x= frma) +{ + struct xfrm_usersa_id *p =3D NLMSG_DATA(nlh); + struct xfrm_state *x; + struct sk_buff *resp_skb; + int err; + + x =3D xfrm_state_lookup(&p->saddr, p->spi, p->proto, p->family); + err =3D -ESRCH; + if (x =3D=3D NULL) + goto out_noput; + + resp_skb =3D xfrm_state_netlink(skb, x, nlh->nlmsg_seq); + if (IS_ERR(resp_skb)) { + err =3D PTR_ERR(resp_skb); + } else { + err =3D netlink_unicast(xfrm_nl, resp_skb, + NETLINK_CB(skb).pid, MSG_DONTWAIT); + } + xfrm_state_put(x); +out_noput: + return err; +} + +static int verify_userspi_info(struct xfrm_userspi_info *p) +{ + switch (p->info.id.proto) { + case IPPROTO_AH: + case IPPROTO_ESP: + break; + + case IPPROTO_COMP: + /* IPCOMP spi is 16-bits. */ + if (p->min >=3D 0x10000 || + p->max >=3D 0x10000) + return -EINVAL; + + default: + return -EINVAL; + }; + + if (p->min > p->max) + return -EINVAL; + + return 0; +} + +static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, v= oid **xfrma) +{ + struct xfrm_state *x; + struct xfrm_userspi_info *p; + struct sk_buff *resp_skb; + int err; + + p =3D NLMSG_DATA(nlh); + err =3D verify_userspi_info(p); + if (err) + goto out_noput; + x =3D xfrm_find_acq(p->info.mode, p->info.reqid, p->info.id.proto, + &p->info.sel.daddr, + &p->info.sel.saddr, 1, + p->info.family); + err =3D -ENOENT; + if (x =3D=3D NULL) + goto out_noput; + + resp_skb =3D ERR_PTR(-ENOENT); + + spin_lock_bh(&x->lock); + if (x->km.state !=3D XFRM_STATE_DEAD) { + xfrm_alloc_spi(x, p->min, p->max); + if (x->id.spi) + resp_skb =3D xfrm_state_netlink(skb, x, nlh->nlmsg_seq); + } + spin_unlock_bh(&x->lock); + + if (IS_ERR(resp_skb)) { + err =3D PTR_ERR(resp_skb); + goto out; + } + + err =3D netlink_unicast(xfrm_nl, resp_skb, + NETLINK_CB(skb).pid, MSG_DONTWAIT); + +out: + xfrm_state_put(x); +out_noput: + return err; +} + +static int verify_policy_dir(__u8 dir) +{ + switch (dir) { + case XFRM_POLICY_IN: + case XFRM_POLICY_OUT: + case XFRM_POLICY_FWD: + break; + + default: + return -EINVAL; + }; + + return 0; +} + +static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) +{ + switch (p->share) { + case XFRM_SHARE_ANY: + case XFRM_SHARE_SESSION: + case XFRM_SHARE_USER: + case XFRM_SHARE_UNIQUE: + break; + + default: + return -EINVAL; + }; + + switch (p->action) { + case XFRM_POLICY_ALLOW: + case XFRM_POLICY_BLOCK: + break; + + default: + return -EINVAL; + }; + + switch (p->family) { + case AF_INET: + break; + + case AF_INET6: +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + break; +#else + return -EAFNOSUPPORT; +#endif + + default: + return -EINVAL; + }; + + return verify_policy_dir(p->dir); +} + +static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *= ut, + int nr) +{ + int i; + + xp->xfrm_nr =3D nr; + for (i =3D 0; i < nr; i++, ut++) { + struct xfrm_tmpl *t =3D &xp->xfrm_vec[i]; + + memcpy(&t->id, &ut->id, sizeof(struct xfrm_id)); + memcpy(&t->saddr, &ut->saddr, + sizeof(xfrm_address_t)); + t->reqid =3D ut->reqid; + t->mode =3D ut->mode; + t->share =3D ut->share; + t->optional =3D ut->optional; + t->aalgos =3D ut->aalgos; + t->ealgos =3D ut->ealgos; + t->calgos =3D ut->calgos; + } +} + +static int copy_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) +{ + struct rtattr *rt =3D xfrma[XFRMA_TMPL-1]; + struct xfrm_user_tmpl *utmpl; + int nr; + + if (!rt) { + pol->xfrm_nr =3D 0; + } else { + nr =3D (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); + + if (nr > XFRM_MAX_DEPTH) + return -EINVAL; + + copy_templates(pol, RTA_DATA(rt), nr); + } + return 0; +} + +static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_user= policy_info *p) +{ + xp->priority =3D p->priority; + xp->index =3D p->index; + memcpy(&xp->selector, &p->sel, sizeof(xp->selector)); + memcpy(&xp->lft, &p->lft, sizeof(xp->lft)); + xp->action =3D p->action; + xp->flags =3D p->flags; + xp->family =3D p->family; + /* XXX xp->share =3D p->share; */ +} + +static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpo= licy_info *p, int dir) +{ + memcpy(&p->sel, &xp->selector, sizeof(p->sel)); + memcpy(&p->lft, &xp->lft, sizeof(p->lft)); + memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); + p->priority =3D xp->priority; + p->index =3D xp->index; + p->family =3D xp->family; + p->dir =3D dir; + p->action =3D xp->action; + p->flags =3D xp->flags; + p->share =3D XFRM_SHARE_ANY; /* XXX xp->share */ +} + +static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_in= fo *p, struct rtattr **xfrma, int *errp) +{ + struct xfrm_policy *xp =3D xfrm_policy_alloc(GFP_KERNEL); + int err; + + if (!xp) { + *errp =3D -ENOMEM; + return NULL; + } + + copy_from_user_policy(xp, p); + err =3D copy_user_tmpl(xp, xfrma); + if (err) { + *errp =3D err; + kfree(xp); + xp =3D NULL; + } + + return xp; +} + +static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void= **xfrma) +{ + struct xfrm_userpolicy_info *p =3D NLMSG_DATA(nlh); + struct xfrm_policy *xp; + int err; + + err =3D verify_newpolicy_info(p); + if (err) + return err; + + xp =3D xfrm_policy_construct(p, (struct rtattr **) xfrma, &err); + if (!xp) + return err; + + err =3D xfrm_policy_insert(p->dir, xp, 1); + if (err) { + kfree(xp); + return err; + } + + xfrm_pol_put(xp); + + return 0; +} + +static int xfrm_del_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void= **xfrma) +{ + struct xfrm_policy *xp; + struct xfrm_userpolicy_id *p; + int err; + + p =3D NLMSG_DATA(nlh); + + err =3D verify_policy_dir(p->dir); + if (err) + return err; + + xp =3D xfrm_policy_delete(p->dir, &p->sel); + if (xp =3D=3D NULL) + return -ENOENT; + xfrm_policy_kill(xp); + xfrm_pol_put(xp); + return 0; +} + +static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, voi= d *ptr) +{ + struct xfrm_dump_info *sp =3D ptr; + struct xfrm_userpolicy_info *p; + struct sk_buff *in_skb =3D sp->in_skb; + struct sk_buff *skb =3D sp->out_skb; + struct nlmsghdr *nlh; + unsigned char *b =3D skb->tail; + + if (sp->this_idx < sp->start_idx) + goto out; + + nlh =3D NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, + sp->nlmsg_seq, + XFRM_MSG_NEWPOLICY, sizeof(*p)); + p =3D NLMSG_DATA(nlh); + nlh->nlmsg_flags =3D 0; + + copy_to_user_policy(xp, p, dir); + + if (xp->xfrm_nr) { + struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH]; + int i; + + for (i =3D 0; i < xp->xfrm_nr; i++) { + struct xfrm_user_tmpl *up =3D &vec[i]; + struct xfrm_tmpl *kp =3D &xp->xfrm_vec[i]; + + memcpy(&up->id, &kp->id, sizeof(up->id)); + memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); + up->reqid =3D kp->reqid; + up->mode =3D kp->mode; + up->share =3D kp->share; + up->optional =3D kp->optional; + up->aalgos =3D kp->aalgos; + up->ealgos =3D kp->ealgos; + up->calgos =3D kp->calgos; + } + RTA_PUT(skb, XFRMA_TMPL, + (sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr), + vec); + } + + nlh->nlmsg_len =3D skb->tail - b; +out: + sp->this_idx++; + return 0; + +nlmsg_failure: +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *= cb) +{ + struct xfrm_dump_info info; + + info.in_skb =3D cb->skb; + info.out_skb =3D skb; + info.nlmsg_seq =3D cb->nlh->nlmsg_seq; + info.this_idx =3D 0; + info.start_idx =3D cb->args[0]; + (void) xfrm_policy_walk(dump_one_policy, &info); + cb->args[0] =3D info.this_idx; + + return skb->len; +} + +static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, + struct xfrm_policy *xp, + int dir, u32 seq) +{ + struct xfrm_dump_info info; + struct sk_buff *skb; + + skb =3D alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); + + NETLINK_CB(skb).dst_pid =3D NETLINK_CB(in_skb).pid; + info.in_skb =3D in_skb; + info.out_skb =3D skb; + info.nlmsg_seq =3D seq; + info.this_idx =3D info.start_idx =3D 0; + + if (dump_one_policy(xp, dir, 0, &info) < 0) { + kfree_skb(skb); + return NULL; + } + + return skb; +} + +static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void= **xfrma) +{ + struct xfrm_policy *xp; + struct xfrm_userpolicy_id *p; + struct sk_buff *resp_skb; + int err; + + p =3D NLMSG_DATA(nlh); + xp =3D xfrm_policy_byid(p->dir, p->index, 0); + if (xp =3D=3D NULL) + return -ENOENT; + + resp_skb =3D xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); + if (IS_ERR(resp_skb)) { + err =3D PTR_ERR(resp_skb); + } else { + err =3D netlink_unicast(xfrm_nl, resp_skb, + NETLINK_CB(skb).pid, MSG_DONTWAIT); + } + + xfrm_pol_put(xp); + + return err; +} + +static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] =3D { + NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)), /* NEW SA */ + NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)), /* DEL SA */ + NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)), /* GET SA */ + NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* NEW POLICY */ + NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)), /* DEL POLICY */ + NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)), /* GET POLICY */ + NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)), /* ALLOC SPI */ + NLMSG_LENGTH(sizeof(struct xfrm_user_acquire)), /* ACQUIRE */ + NLMSG_LENGTH(sizeof(struct xfrm_user_expire)), /* EXPIRE */ +}; + +static struct xfrm_link { + int (*doit)(struct sk_buff *, struct nlmsghdr *, void **); + int (*dump)(struct sk_buff *, struct netlink_callback *); +} xfrm_dispatch[] =3D { + { .doit =3D xfrm_add_sa, }, + { .doit =3D xfrm_del_sa, }, + { + .doit =3D xfrm_get_sa, + .dump =3D xfrm_dump_sa, + }, + { .doit =3D xfrm_add_policy }, + { .doit =3D xfrm_del_policy }, + { + .doit =3D xfrm_get_policy, + .dump =3D xfrm_dump_policy, + }, + { .doit =3D xfrm_alloc_userspi }, +}; + +static int xfrm_done(struct netlink_callback *cb) +{ + return 0; +} + +static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, in= t *errp) +{ + struct rtattr *xfrma[XFRMA_MAX]; + struct xfrm_link *link; + int type, min_len; + + if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) + return 0; + + type =3D nlh->nlmsg_type; + + /* A control message: ignore them */ + if (type < XFRM_MSG_BASE) + return 0; + + /* Unknown message: reply with EINVAL */ + if (type > XFRM_MSG_MAX) + goto err_einval; + + type -=3D XFRM_MSG_BASE; + link =3D &xfrm_dispatch[type]; + + /* All operations require privileges, even GET */ + if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { + *errp =3D -EPERM; + return -1; + } + + if ((type =3D=3D 2 || type =3D=3D 5) && (nlh->nlmsg_flags & NLM_F_DUMP)) = { + u32 rlen; + + if (link->dump =3D=3D NULL) + goto err_einval; + + if ((*errp =3D netlink_dump_start(xfrm_nl, skb, nlh, + link->dump, + xfrm_done)) !=3D 0) { + return -1; + } + rlen =3D NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen =3D skb->len; + skb_pull(skb, rlen); + return -1; + } + + memset(xfrma, 0, sizeof(xfrma)); + + if (nlh->nlmsg_len < (min_len =3D xfrm_msg_min[type])) + goto err_einval; + + if (nlh->nlmsg_len > min_len) { + int attrlen =3D nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct rtattr *attr =3D (void *) nlh + NLMSG_ALIGN(min_len); + + while (RTA_OK(attr, attrlen)) { + unsigned short flavor =3D attr->rta_type; + if (flavor) { + if (flavor > XFRMA_MAX) + goto err_einval; + xfrma[flavor - 1] =3D attr; + } + attr =3D RTA_NEXT(attr, attrlen); + } + } + + if (link->doit =3D=3D NULL) + goto err_einval; + *errp =3D link->doit(skb, nlh, (void **) &xfrma); + + return *errp; + +err_einval: + *errp =3D -EINVAL; + return -1; +} + +static int xfrm_user_rcv_skb(struct sk_buff *skb) +{ + int err; + struct nlmsghdr *nlh; + + while (skb->len >=3D NLMSG_SPACE(0)) { + u32 rlen; + + nlh =3D (struct nlmsghdr *) skb->data; + if (nlh->nlmsg_len < sizeof(*nlh) || + skb->len < nlh->nlmsg_len) + return 0; + rlen =3D NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen =3D skb->len; + if (xfrm_user_rcv_msg(skb, nlh, &err)) { + if (err =3D=3D 0) + return -1; + netlink_ack(skb, nlh, err); + } else if (nlh->nlmsg_flags & NLM_F_ACK) + netlink_ack(skb, nlh, 0); + skb_pull(skb, rlen); + } + + return 0; +} + +static void xfrm_netlink_rcv(struct sock *sk, int len) +{ + do { + struct sk_buff *skb; + + down(&xfrm_cfg_sem); + + while ((skb =3D skb_dequeue(&sk->receive_queue)) !=3D NULL) { + if (xfrm_user_rcv_skb(skb)) { + if (skb->len) + skb_queue_head(&sk->receive_queue, skb); + else + kfree_skb(skb); + break; + } + kfree_skb(skb); + } + + up(&xfrm_cfg_sem); + + } while (xfrm_nl && xfrm_nl->receive_queue.qlen); +} + +static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int har= d) +{ + struct xfrm_user_expire *ue; + struct nlmsghdr *nlh; + unsigned char *b =3D skb->tail; + + nlh =3D NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE, + sizeof(*ue)); + ue =3D NLMSG_DATA(nlh); + nlh->nlmsg_flags =3D 0; + + copy_to_user_state(x, &ue->state); + ue->hard =3D (hard !=3D 0) ? 1 : 0; + + nlh->nlmsg_len =3D skb->tail - b; + return skb->len; + +nlmsg_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int xfrm_send_notify(struct xfrm_state *x, int hard) +{ + struct sk_buff *skb; + + skb =3D alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC); + if (skb =3D=3D NULL) + return -ENOMEM; + + if (build_expire(skb, x, hard) < 0) + BUG(); + + NETLINK_CB(skb).dst_groups =3D XFRMGRP_EXPIRE; + + return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); +} + +static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, + struct xfrm_tmpl *xt, struct xfrm_policy *xp, + int dir) +{ + struct xfrm_user_acquire *ua; + struct nlmsghdr *nlh; + unsigned char *b =3D skb->tail; + __u32 seq =3D xfrm_get_acqseq(); + + nlh =3D NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE, + sizeof(*ua)); + ua =3D NLMSG_DATA(nlh); + nlh->nlmsg_flags =3D 0; + + memcpy(&ua->id, &x->id, sizeof(ua->id)); + memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); + copy_to_user_policy(xp, &ua->policy, dir); + ua->aalgos =3D xt->aalgos; + ua->ealgos =3D xt->ealgos; + ua->calgos =3D xt->calgos; + ua->seq =3D x->km.seq =3D seq; + + nlh->nlmsg_len =3D skb->tail - b; + return skb->len; + +nlmsg_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, + struct xfrm_policy *xp, int dir) +{ + struct sk_buff *skb; + + skb =3D alloc_skb(sizeof(struct xfrm_user_acquire) + 16, GFP_ATOMIC); + if (skb =3D=3D NULL) + return -ENOMEM; + + if (build_acquire(skb, x, xt, xp, dir) < 0) + BUG(); + + NETLINK_CB(skb).dst_groups =3D XFRMGRP_ACQUIRE; + + return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_ACQUIRE, GFP_ATOMIC); +} + +/* User gives us xfrm_user_policy_info followed by an array of 0 + * or more templates. + */ +struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, + u8 *data, int len, int *dir) +{ + struct xfrm_userpolicy_info *p =3D (struct xfrm_userpolicy_info *)data; + struct xfrm_user_tmpl *ut =3D (struct xfrm_user_tmpl *) (p + 1); + struct xfrm_policy *xp; + int nr; + + switch (family) { + case AF_INET: + if (opt !=3D IP_XFRM_POLICY) { + *dir =3D -EOPNOTSUPP; + return NULL; + } + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + if (opt !=3D IPV6_XFRM_POLICY) { + *dir =3D -EOPNOTSUPP; + return NULL; + } + break; +#endif + default: + *dir =3D -EINVAL; + return NULL; + } + + *dir =3D -EINVAL; + + if (len < sizeof(*p) || + verify_newpolicy_info(p)) + return NULL; + + nr =3D ((len - sizeof(*p)) / sizeof(*ut)); + if (nr > XFRM_MAX_DEPTH) + return NULL; + + xp =3D xfrm_policy_alloc(GFP_KERNEL); + if (xp =3D=3D NULL) { + *dir =3D -ENOBUFS; + return NULL; + } + + copy_from_user_policy(xp, p); + copy_templates(xp, ut, nr); + + *dir =3D p->dir; + + return xp; +} + +static struct xfrm_mgr netlink_mgr =3D { + .id =3D "netlink", + .notify =3D xfrm_send_notify, + .acquire =3D xfrm_send_acquire, + .compile_policy =3D xfrm_compile_policy, +}; + +static int __init xfrm_user_init(void) +{ + printk(KERN_INFO "Initializing IPsec netlink socket\n"); + + xfrm_nl =3D netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv); + if (xfrm_nl =3D=3D NULL) + panic("xfrm_user_init: cannot initialize xfrm_nl\n"); + + + xfrm_register_km(&netlink_mgr); + + return 0; +} + +static void __exit xfrm_user_exit(void) +{ + xfrm_unregister_km(&netlink_mgr); + sock_release(xfrm_nl->socket); +} + +module_init(xfrm_user_init); +module_exit(xfrm_user_exit); --=-5BrkI45hpvPGN31OmYHz-- -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: aart@kvack.org