From ff4cc3ac93e1d0369928fd60ec1fe82417afc576 Mon Sep 17 00:00:00 2001 From: Mike Kershaw Date: Thu, 1 Sep 2005 17:40:05 -0700 Subject: [PATCH 01/17] [TUNTAP]: Allow setting the linktype of the tap device from userspace Currently tun/tap only supports the EN10MB ARP type. For use with wireless and other networking types it should be possible to set the ARP type via an ioctl. Patch v2: Included check that the tap interface is down before changing the link type out from underneath it Signed-off-by: Mike Kershaw Signed-off-by: David S. Miller --- drivers/net/tun.c | 15 +++++++++++++++ include/linux/if_tun.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index effab0b9adca..50b8c6754b1e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -18,6 +18,9 @@ /* * Changes: * + * Mike Kershaw 2005/08/14 + * Add TUNSETLINK ioctl to set the link encapsulation + * * Mark Smith * Use random_ether_addr() for tap MAC address. * @@ -612,6 +615,18 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, DBG(KERN_INFO "%s: owner set to %d\n", tun->dev->name, tun->owner); break; + case TUNSETLINK: + /* Only allow setting the type when the interface is down */ + if (tun->dev->flags & IFF_UP) { + DBG(KERN_INFO "%s: Linktype set failed because interface is up\n", + tun->dev->name); + return -EBUSY; + } else { + tun->dev->type = (int) arg; + DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type); + } + break; + #ifdef TUN_DEBUG case TUNSETDEBUG: tun->debug = arg; diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 096a85a58ae5..88aef7b86ef4 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -77,6 +77,7 @@ struct tun_struct { #define TUNSETIFF _IOW('T', 202, int) #define TUNSETPERSIST _IOW('T', 203, int) #define TUNSETOWNER _IOW('T', 204, int) +#define TUNSETLINK _IOW('T', 205, int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 From 732db659b83579b922c18dee9123e1529b5fb5d2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 1 Sep 2005 17:40:26 -0700 Subject: [PATCH 02/17] [IPVS]: "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- include/net/ip_vs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 7a3c43711a17..e426641c519f 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -958,7 +958,7 @@ static __inline__ int ip_vs_todrop(void) */ #define IP_VS_FWD_METHOD(cp) (cp->flags & IP_VS_CONN_F_FWD_MASK) -extern __inline__ char ip_vs_fwd_tag(struct ip_vs_conn *cp) +static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp) { char fwd; From 0014c6156f9e7d034d20742d164d7d4da289b42a Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Thu, 1 Sep 2005 17:40:46 -0700 Subject: [PATCH 03/17] [SUNGEM]: fix minor bug in sungem.h This changes the Sun Gem Ether driver's tx ring buffer length to the proper constant. Currently TX_RING_SIZE and RX_RING_SIZE are equal, so no malfunction occurs. Signed-off-by: Geoff Levand Signed-off-by: David S. Miller --- drivers/net/sungem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index 7143fd7cf3f8..ff8ae5f79970 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -1020,7 +1020,7 @@ struct gem { struct gem_init_block *init_block; struct sk_buff *rx_skbs[RX_RING_SIZE]; - struct sk_buff *tx_skbs[RX_RING_SIZE]; + struct sk_buff *tx_skbs[TX_RING_SIZE]; dma_addr_t gblock_dvma; struct pci_dev *pdev; From 86d9f7f0c9cf06d7d3cfa2a9f0514cf21fa5fda1 Mon Sep 17 00:00:00 2001 From: Eric Lemoine Date: Thu, 1 Sep 2005 17:41:07 -0700 Subject: [PATCH 04/17] [SUNGEM]: Fix netpoll bug in Sun GEM Ether driver From: Eric Lemoine To me the bug is that __LINK_STATE_RX_SCHED can be set while __netif_rx_schedule() hasen't be called. Why don't fix it in the simplest way ? See attached patch (absolutely untested). Signed-off-by: Geoff Levand Signed-off-by: David S. Miller --- drivers/net/sungem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 2608e7a3d214..3f67a42e8503 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -948,6 +948,7 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) u32 gem_status = readl(gp->regs + GREG_STAT); if (gem_status == 0) { + netif_poll_enable(dev); spin_unlock_irqrestore(&gp->lock, flags); return IRQ_NONE; } From 51b9146869ab9492da785c5c9321d85f01655ab6 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 1 Sep 2005 17:41:28 -0700 Subject: [PATCH 05/17] [TG3]: Minimize locking in TX path. This is similar to Eric Dumazet's tx_lock patch for tg3 but takes it one step further to eliminate the tx_lock in the tx_completion path when the tx queue is not stopped. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index af8263a1580e..e877579aab38 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -121,12 +121,9 @@ TG3_RX_RCB_RING_SIZE(tp)) #define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \ TG3_TX_RING_SIZE) -#define TX_RING_GAP(TP) \ - (TG3_TX_RING_SIZE - (TP)->tx_pending) #define TX_BUFFS_AVAIL(TP) \ - (((TP)->tx_cons <= (TP)->tx_prod) ? \ - (TP)->tx_cons + (TP)->tx_pending - (TP)->tx_prod : \ - (TP)->tx_cons - (TP)->tx_prod - TX_RING_GAP(TP)) + ((TP)->tx_pending - \ + (((TP)->tx_prod - (TP)->tx_cons) & (TG3_TX_RING_SIZE - 1))) #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) #define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64) @@ -2880,9 +2877,13 @@ static void tg3_tx(struct tg3 *tp) tp->tx_cons = sw_idx; - if (netif_queue_stopped(tp->dev) && - (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)) - netif_wake_queue(tp->dev); + if (unlikely(netif_queue_stopped(tp->dev))) { + spin_lock(&tp->tx_lock); + if (netif_queue_stopped(tp->dev) && + (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)) + netif_wake_queue(tp->dev); + spin_unlock(&tp->tx_lock); + } } /* Returns size of skb allocated or < 0 on error. @@ -3198,9 +3199,7 @@ static int tg3_poll(struct net_device *netdev, int *budget) /* run TX completion thread */ if (sblk->idx[0].tx_consumer != tp->tx_cons) { - spin_lock(&tp->tx_lock); tg3_tx(tp); - spin_unlock(&tp->tx_lock); } /* run RX thread, within the bounds set by NAPI. @@ -3716,8 +3715,11 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); tp->tx_prod = entry; - if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) + if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) { netif_stop_queue(dev); + if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH) + netif_wake_queue(tp->dev); + } out_unlock: mmiowb(); From 75c80c382fbd08acf06fbef9d54c9844e806a8b4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 Sep 2005 17:42:23 -0700 Subject: [PATCH 06/17] [TG3]: Update driver version and release date. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e877579aab38..3faf62310f84 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -66,8 +66,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.37" -#define DRV_MODULE_RELDATE "August 25, 2005" +#define DRV_MODULE_VERSION "3.38" +#define DRV_MODULE_RELDATE "September 1, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 From fb4f10ed50f01b0f953068456bfb6e2885921b01 Mon Sep 17 00:00:00 2001 From: Aaron Grothe Date: Thu, 1 Sep 2005 17:42:46 -0700 Subject: [PATCH 07/17] [CRYPTO]: Fix XTEA implementation The XTEA implementation was incorrect due to a misinterpretation of operator precedence. Because of the wide-spread nature of this error, the erroneous implementation will be kept, albeit under the new name of XETA. Signed-off-by: Aaron Grothe Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- Documentation/crypto/api-intro.txt | 1 + crypto/Kconfig | 5 +- crypto/tcrypt.c | 11 ++- crypto/tcrypt.h | 138 ++++++++++++++++++++++++----- crypto/tea.c | 81 ++++++++++++++++- 5 files changed, 207 insertions(+), 29 deletions(-) diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt index a2d5b4900772..74dffc68ff9f 100644 --- a/Documentation/crypto/api-intro.txt +++ b/Documentation/crypto/api-intro.txt @@ -223,6 +223,7 @@ CAST5 algorithm contributors: TEA/XTEA algorithm contributors: Aaron Grothe + Michael Ringe Khazad algorithm contributors: Aaron Grothe diff --git a/crypto/Kconfig b/crypto/Kconfig index 256c0b1fed10..89299f4ffe12 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -219,7 +219,7 @@ config CRYPTO_CAST6 described in RFC2612. config CRYPTO_TEA - tristate "TEA and XTEA cipher algorithms" + tristate "TEA, XTEA and XETA cipher algorithms" depends on CRYPTO help TEA cipher algorithm. @@ -232,6 +232,9 @@ config CRYPTO_TEA the TEA algorithm to address a potential key weakness in the TEA algorithm. + Xtendend Encryption Tiny Algorithm is a mis-implementation + of the XTEA algorithm for compatibility purposes. + config CRYPTO_ARC4 tristate "ARC4 cipher algorithm" depends on CRYPTO diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index bd7524cfff33..68639419c5bd 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -72,7 +72,7 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", - "khazad", "wp512", "wp384", "wp256", "tnepres", NULL + "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL }; static void hexdump(unsigned char *buf, unsigned int len) @@ -859,6 +859,10 @@ static void do_test(void) test_cipher ("anubis", MODE_CBC, ENCRYPT, anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS); test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS); + //XETA + test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS); + test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); @@ -1016,6 +1020,11 @@ static void do_test(void) case 29: test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS); break; + + case 30: + test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS); + test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS); + break; #ifdef CONFIG_CRYPTO_HMAC case 100: diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index c01a0ce9b40a..522ffd4b6f43 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -2211,7 +2211,7 @@ static struct cipher_testvec xtea_enc_tv_template[] = { .klen = 16, .input = { [0 ... 8] = 0x00 }, .ilen = 8, - .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 }, + .result = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 }, .rlen = 8, }, { .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, @@ -2219,31 +2219,31 @@ static struct cipher_testvec xtea_enc_tv_template[] = { .klen = 16, .input = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, .ilen = 8, - .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 }, + .result = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 }, .rlen = 8, }, { .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, .klen = 16, - .input = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + .input = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, .ilen = 16, - .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, + .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c }, .rlen = 16, }, { .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, .klen = 16, - .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, - 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, - 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, .ilen = 32, - .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, - 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, - 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, - 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 }, + .result = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a, + 0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07, + 0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4, + 0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 }, .rlen = 32, } }; @@ -2252,7 +2252,7 @@ static struct cipher_testvec xtea_dec_tv_template[] = { { .key = { [0 ... 15] = 0x00 }, .klen = 16, - .input = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 }, + .input = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 }, .ilen = 8, .result = { [0 ... 8] = 0x00 }, .rlen = 8, @@ -2260,7 +2260,7 @@ static struct cipher_testvec xtea_dec_tv_template[] = { .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 }, .klen = 16, - .input = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 }, + .input = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 }, .ilen = 8, .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, .rlen = 8, @@ -2268,24 +2268,24 @@ static struct cipher_testvec xtea_dec_tv_template[] = { .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, .klen = 16, - .input = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, - 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c }, + .input = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d, + 0x77, 0x4d, 0xd4, 0xb4, 0x87, 0x24, 0xe3, 0x9a }, .ilen = 16, - .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, .rlen = 16, }, { .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, .klen = 16, - .input = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, - 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, - 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, - 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 }, + .input = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a, + 0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07, + 0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4, + 0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 }, .ilen = 32, - .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, - 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, - 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, .rlen = 32, } @@ -2594,6 +2594,98 @@ static struct cipher_testvec anubis_cbc_dec_tv_template[] = { }, }; +/* + * XETA test vectors + */ +#define XETA_ENC_TEST_VECTORS 4 +#define XETA_DEC_TEST_VECTORS 4 + +static struct cipher_testvec xeta_enc_tv_template[] = { + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { [0 ... 8] = 0x00 }, + .ilen = 8, + .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 }, + .rlen = 8, + }, { + .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, + 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 }, + .klen = 16, + .input = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, + .ilen = 8, + .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 }, + .rlen = 8, + }, { + .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, + 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, + .klen = 16, + .input = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, + .ilen = 16, + .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, + 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c }, + .rlen = 16, + }, { + .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, + 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, + .klen = 16, + .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, + .ilen = 32, + .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, + 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, + 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, + 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 }, + .rlen = 32, + } +}; + +static struct cipher_testvec xeta_dec_tv_template[] = { + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 }, + .ilen = 8, + .result = { [0 ... 8] = 0x00 }, + .rlen = 8, + }, { + .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, + 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 }, + .klen = 16, + .input = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 }, + .ilen = 8, + .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, + .rlen = 8, + }, { + .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, + 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, + .klen = 16, + .input = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, + 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c }, + .ilen = 16, + .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, + .rlen = 16, + }, { + .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, + 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, + .klen = 16, + .input = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, + 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, + 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, + 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 }, + .ilen = 32, + .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, + .rlen = 32, + } +}; + /* * Compression stuff. */ diff --git a/crypto/tea.c b/crypto/tea.c index 03c23cbd3afa..5924efdd3a16 100644 --- a/crypto/tea.c +++ b/crypto/tea.c @@ -1,11 +1,15 @@ /* * Cryptographic API. * - * TEA and Xtended TEA Algorithms + * TEA, XTEA, and XETA crypto alogrithms * * The TEA and Xtended TEA algorithms were developed by David Wheeler * and Roger Needham at the Computer Laboratory of Cambridge University. * + * Due to the order of evaluation in XTEA many people have incorrectly + * implemented it. XETA (XTEA in the wrong order), exists for + * compatibility with these implementations. + * * Copyright (c) 2004 Aaron Grothe ajgrothe@yahoo.com * * This program is free software; you can redistribute it and/or modify @@ -153,9 +157,9 @@ static void xtea_encrypt(void *ctx_arg, u8 *dst, const u8 *src) z = u32_in (src + 4); while (sum != limit) { - y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; + y += ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum&3]); sum += XTEA_DELTA; - z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; + z += ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 &3]); } u32_out (dst, y); @@ -174,6 +178,51 @@ static void xtea_decrypt(void *ctx_arg, u8 *dst, const u8 *src) sum = XTEA_DELTA * XTEA_ROUNDS; + while (sum) { + z -= ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 & 3]); + sum -= XTEA_DELTA; + y -= ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum & 3]); + } + + u32_out (dst, y); + u32_out (dst + 4, z); + +} + + +static void xeta_encrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + + u32 y, z, sum = 0; + u32 limit = XTEA_DELTA * XTEA_ROUNDS; + + struct xtea_ctx *ctx = ctx_arg; + + y = u32_in (src); + z = u32_in (src + 4); + + while (sum != limit) { + y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; + sum += XTEA_DELTA; + z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; + } + + u32_out (dst, y); + u32_out (dst + 4, z); + +} + +static void xeta_decrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + + u32 y, z, sum; + struct tea_ctx *ctx = ctx_arg; + + y = u32_in (src); + z = u32_in (src + 4); + + sum = XTEA_DELTA * XTEA_ROUNDS; + while (sum) { z -= (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 & 3]; sum -= XTEA_DELTA; @@ -215,6 +264,21 @@ static struct crypto_alg xtea_alg = { .cia_decrypt = xtea_decrypt } } }; +static struct crypto_alg xeta_alg = { + .cra_name = "xeta", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = XTEA_BLOCK_SIZE, + .cra_ctxsize = sizeof (struct xtea_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(xtea_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = XTEA_KEY_SIZE, + .cia_max_keysize = XTEA_KEY_SIZE, + .cia_setkey = xtea_setkey, + .cia_encrypt = xeta_encrypt, + .cia_decrypt = xeta_decrypt } } +}; + static int __init init(void) { int ret = 0; @@ -229,6 +293,13 @@ static int __init init(void) goto out; } + ret = crypto_register_alg(&xeta_alg); + if (ret < 0) { + crypto_unregister_alg(&tea_alg); + crypto_unregister_alg(&xtea_alg); + goto out; + } + out: return ret; } @@ -237,12 +308,14 @@ static void __exit fini(void) { crypto_unregister_alg(&tea_alg); crypto_unregister_alg(&xtea_alg); + crypto_unregister_alg(&xeta_alg); } MODULE_ALIAS("xtea"); +MODULE_ALIAS("xeta"); module_init(init); module_exit(fini); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("TEA & XTEA Cryptographic Algorithms"); +MODULE_DESCRIPTION("TEA, XTEA & XETA Cryptographic Algorithms"); From 64baf3cfea974d2b9e671ccfdbc03e030ea5ebc6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 1 Sep 2005 17:43:05 -0700 Subject: [PATCH 08/17] [CRYPTO]: Added CRYPTO_TFM_REQ_MAY_SLEEP flag The crypto layer currently uses in_atomic() to determine whether it is allowed to sleep. This is incorrect since spin locks don't always cause in_atomic() to return true. Instead of that, this patch returns to an earlier idea of a per-tfm flag which determines whether sleeping is allowed. Unlike the earlier version, the default is to not allow sleeping. This ensures that no existing code can break. As usual, this flag may either be set through crypto_alloc_tfm(), or just before a specific crypto operation. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/api.c | 3 ++- crypto/cipher.c | 4 ---- crypto/internal.h | 3 ++- include/linux/crypto.h | 1 + 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crypto/api.c b/crypto/api.c index b4728811ce3b..959c4e5f264f 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -66,7 +66,8 @@ static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) { - tfm->crt_flags = 0; + tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK; + flags &= ~CRYPTO_TFM_REQ_MASK; switch (crypto_tfm_alg_type(tfm)) { case CRYPTO_ALG_TYPE_CIPHER: diff --git a/crypto/cipher.c b/crypto/cipher.c index 8da644364cb4..3df47f93c9db 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -377,11 +377,7 @@ static int nocrypt_iv(struct crypto_tfm *tfm, int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) { u32 mode = flags & CRYPTO_TFM_MODE_MASK; - tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; - if (flags & CRYPTO_TFM_REQ_WEAK_KEY) - tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY; - return 0; } diff --git a/crypto/internal.h b/crypto/internal.h index 37515beafc8c..37aa652ce5ce 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -17,6 +17,7 @@ #include #include #include +#include #include extern enum km_type crypto_km_types[]; @@ -38,7 +39,7 @@ static inline void crypto_kunmap(void *vaddr, int out) static inline void crypto_yield(struct crypto_tfm *tfm) { - if (!in_atomic()) + if (tfm->crt_flags & CRYPTO_TFM_REQ_MAY_SLEEP) cond_resched(); } diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 5e2bcc636a02..3c89df6e7768 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -45,6 +45,7 @@ #define CRYPTO_TFM_MODE_CTR 0x00000008 #define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 +#define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200 #define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 #define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 #define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 From eb6f1160ddb2fdadf50f350da79d0796c37f17e2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 1 Sep 2005 17:43:25 -0700 Subject: [PATCH 09/17] [CRYPTO]: Use CRYPTO_TFM_REQ_MAY_SLEEP where appropriate This patch goes through the current users of the crypto layer and sets CRYPTO_TFM_REQ_MAY_SLEEP at crypto_alloc_tfm() where all crypto operations are performed in process context. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/block/cryptoloop.c | 6 ++++-- drivers/md/dm-crypt.c | 7 ++++--- drivers/net/wireless/airo.c | 2 +- fs/nfsd/nfs4recover.c | 2 +- net/sunrpc/auth_gss/gss_krb5_crypto.c | 2 +- security/seclvl.c | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c index 5be6f998d8c5..3d4261c39f16 100644 --- a/drivers/block/cryptoloop.c +++ b/drivers/block/cryptoloop.c @@ -57,9 +57,11 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) mode = strsep(&cmsp, "-"); if (mode == NULL || strcmp(mode, "cbc") == 0) - tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC); + tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC | + CRYPTO_TFM_REQ_MAY_SLEEP); else if (strcmp(mode, "ecb") == 0) - tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB); + tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB | + CRYPTO_TFM_REQ_MAY_SLEEP); if (tfm == NULL) return -EINVAL; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index d0a4bab220e5..b82bc3150476 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -144,7 +144,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, } /* Hash the cipher key with the given hash algorithm */ - hash_tfm = crypto_alloc_tfm(opts, 0); + hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP); if (hash_tfm == NULL) { ti->error = PFX "Error initializing ESSIV hash"; return -EINVAL; @@ -172,7 +172,8 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, /* Setup the essiv_tfm with the given salt */ essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm), - CRYPTO_TFM_MODE_ECB); + CRYPTO_TFM_MODE_ECB | + CRYPTO_TFM_REQ_MAY_SLEEP); if (essiv_tfm == NULL) { ti->error = PFX "Error allocating crypto tfm for ESSIV"; kfree(salt); @@ -587,7 +588,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad1; } - tfm = crypto_alloc_tfm(cipher, crypto_flags); + tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP); if (!tfm) { ti->error = PFX "Error allocating crypto tfm"; goto bad1; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index df20adcd0730..7fdb85dda4e5 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1301,7 +1301,7 @@ static int micsetup(struct airo_info *ai) { int i; if (ai->tfm == NULL) - ai->tfm = crypto_alloc_tfm("aes", 0); + ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP); if (ai->tfm == NULL) { printk(KERN_ERR "airo: failed to load transform for AES\n"); diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 57ed50fe7f85..02132f33320d 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -93,7 +93,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", clname->len, clname->data); - tfm = crypto_alloc_tfm("md5", 0); + tfm = crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP); if (tfm == NULL) goto out; cksum.len = crypto_tfm_alg_digestsize(tfm); diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 5a7265aeaf83..7ad74449b18f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -160,7 +160,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, " unsupported checksum %d", cksumtype); goto out; } - if (!(tfm = crypto_alloc_tfm(cksumname, 0))) + if (!(tfm = crypto_alloc_tfm(cksumname, CRYPTO_TFM_REQ_MAY_SLEEP))) goto out; cksum->len = crypto_tfm_alg_digestsize(tfm); if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL) diff --git a/security/seclvl.c b/security/seclvl.c index c8e87b22c9bd..96b1f2122f67 100644 --- a/security/seclvl.c +++ b/security/seclvl.c @@ -321,7 +321,7 @@ plaintext_to_sha1(unsigned char *hash, const char *plaintext, int len) "bytes.\n", len, PAGE_SIZE); return -ENOMEM; } - tfm = crypto_alloc_tfm("sha1", 0); + tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP); if (tfm == NULL) { seclvl_printk(0, KERN_ERR, "Failed to load transform for SHA1\n"); From 12a49ffd842bf5b07c62eaabf178703ce4fe09d7 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Thu, 1 Sep 2005 17:43:45 -0700 Subject: [PATCH 10/17] [DECNET]: Tidy send side socket SKB allocation. Patch from Steve Whitehouse which I've vetted and tested: "This patch is really intended has a move towards fixing the sendmsg/recvmsg functions in various ways so that we will finally have working nagle. Also reduces code duplication." Signed-off-by: Patrick Caulfield Signed-off-by: David S. Miller --- net/decnet/af_decnet.c | 40 +++++++++++++++++++++----- net/decnet/dn_nsp_out.c | 63 ----------------------------------------- 2 files changed, 33 insertions(+), 70 deletions(-) diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 621680f127af..348f36b529f7 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1876,8 +1876,27 @@ static inline unsigned int dn_current_mss(struct sock *sk, int flags) return mss_now; } +/* + * N.B. We get the timeout wrong here, but then we always did get it + * wrong before and this is another step along the road to correcting + * it. It ought to get updated each time we pass through the routine, + * but in practise it probably doesn't matter too much for now. + */ +static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk, + unsigned long datalen, int noblock, + int *errcode) +{ + struct sk_buff *skb = sock_alloc_send_skb(sk, datalen, + noblock, errcode); + if (skb) { + skb->protocol = __constant_htons(ETH_P_DNA_RT); + skb->pkt_type = PACKET_OUTGOING; + } + return skb; +} + static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size) + struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); @@ -1892,7 +1911,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, struct dn_skb_cb *cb; size_t len; unsigned char fctype; - long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); + long timeo; if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT)) return -EOPNOTSUPP; @@ -1900,18 +1919,21 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) return -EINVAL; + lock_sock(sk); + timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); /* * The only difference between stream sockets and sequenced packet * sockets is that the stream sockets always behave as if MSG_EOR * has been set. */ if (sock->type == SOCK_STREAM) { - if (flags & MSG_EOR) - return -EINVAL; + if (flags & MSG_EOR) { + err = -EINVAL; + goto out; + } flags |= MSG_EOR; } - lock_sock(sk); err = dn_check_state(sk, addr, addr_len, &timeo, flags); if (err) @@ -1980,8 +2002,12 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, /* * Get a suitably sized skb. + * 64 is a bit of a hack really, but its larger than any + * link-layer headers and has served us well as a good + * guess as to their real length. */ - skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, timeo, &err); + skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER, + flags & MSG_DONTWAIT, &err); if (err) break; @@ -1991,7 +2017,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, cb = DN_SKB_CB(skb); - skb_reserve(skb, DN_MAX_NSP_DATA_HEADER); + skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER); if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index e0bebf4bbcad..53633d352868 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -136,69 +136,6 @@ struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri) return skb; } -/* - * Wrapper for the above, for allocs of data skbs. We try and get the - * whole size thats been asked for (plus 11 bytes of header). If this - * fails, then we try for any size over 16 bytes for SOCK_STREAMS. - */ -struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, long timeo, int *err) -{ - int space; - int len; - struct sk_buff *skb = NULL; - - *err = 0; - - while(skb == NULL) { - if (signal_pending(current)) { - *err = sock_intr_errno(timeo); - break; - } - - if (sk->sk_shutdown & SEND_SHUTDOWN) { - *err = EINVAL; - break; - } - - if (sk->sk_err) - break; - - len = *size + 11; - space = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); - - if (space < len) { - if ((sk->sk_socket->type == SOCK_STREAM) && - (space >= (16 + 11))) - len = space; - } - - if (space < len) { - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); - if (noblock) { - *err = EWOULDBLOCK; - break; - } - - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - SOCK_SLEEP_PRE(sk) - - if ((sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc)) < - len) - schedule(); - - SOCK_SLEEP_POST(sk) - continue; - } - - if ((skb = dn_alloc_skb(sk, len, sk->sk_allocation)) == NULL) - continue; - - *size = len - 11; - } - - return skb; -} - /* * Calculate persist timer based upon the smoothed round * trip time and the variance. Backoff according to the From 5170dbebbb2e9159cdf6bbf35e5d79cd7009799a Mon Sep 17 00:00:00 2001 From: KOVACS Krisztian Date: Thu, 1 Sep 2005 17:44:06 -0700 Subject: [PATCH 11/17] [NETFILTER]: CLUSTERIP: fix memcpy() length typo Fix a trivial typo in clusterip_config_init(). Signed-off-by: KOVACS Krisztian Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 2d05cafec221..7d38913754b1 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -144,7 +144,7 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, memcpy(&c->clustermac, &i->clustermac, ETH_ALEN); c->num_total_nodes = i->num_total_nodes; c->num_local_nodes = i->num_local_nodes; - memcpy(&c->local_nodes, &i->local_nodes, sizeof(&c->local_nodes)); + memcpy(&c->local_nodes, &i->local_nodes, sizeof(c->local_nodes)); c->hash_mode = i->hash_mode; c->hash_initval = i->hash_initval; atomic_set(&c->refcount, 1); From 573dbd95964b01a942aa0c68e92b06f2c9536964 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 1 Sep 2005 17:44:29 -0700 Subject: [PATCH 12/17] [CRYPTO]: crypto_free_tfm() callers no longer need to check for NULL Since the patch to add a NULL short-circuit to crypto_free_tfm() went in, there's no longer any need for callers of that function to check for NULL. This patch removes the redundant NULL checks and also a few similar checks for NULL before calls to kfree() that I ran into while doing the crypto_free_tfm bits. I've succesfuly compile tested this patch, and a kernel with the patch applied boots and runs just fine. When I posted the patch to LKML (and other lists/people on Cc) it drew the following comments : J. Bruce Fields commented "I've no problem with the auth_gss or nfsv4 bits.--b." Sridhar Samudrala said "sctp change looks fine." Herbert Xu signed off on the patch. So, I guess this is ready to be dropped into -mm and eventually mainline. Signed-off-by: Jesper Juhl Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/wireless/airo.c | 3 +-- fs/nfsd/nfs4recover.c | 3 +-- net/ipv4/ah4.c | 18 ++++++------------ net/ipv4/esp4.c | 24 ++++++++---------------- net/ipv4/ipcomp.c | 3 +-- net/ipv6/addrconf.c | 6 ++---- net/ipv6/ah6.c | 18 ++++++------------ net/ipv6/esp6.c | 24 ++++++++---------------- net/ipv6/ipcomp6.c | 3 +-- net/sctp/endpointola.c | 3 +-- net/sctp/socket.c | 3 +-- net/sunrpc/auth_gss/gss_krb5_crypto.c | 3 +-- net/sunrpc/auth_gss/gss_krb5_mech.c | 9 +++------ net/sunrpc/auth_gss/gss_spkm3_mech.c | 12 ++++-------- 14 files changed, 44 insertions(+), 88 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 7fdb85dda4e5..2bb8170cf6f1 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2403,8 +2403,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) } } #ifdef MICSUPPORT - if (ai->tfm) - crypto_free_tfm(ai->tfm); + crypto_free_tfm(ai->tfm); #endif del_airo_dev( dev ); free_netdev( dev ); diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 02132f33320d..954cf893d50c 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -114,8 +114,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) kfree(cksum.data); status = nfs_ok; out: - if (tfm) - crypto_free_tfm(tfm); + crypto_free_tfm(tfm); return status; } diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 514c85b2631a..035ad2c9e1ba 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -263,10 +263,8 @@ static int ah_init_state(struct xfrm_state *x) error: if (ahp) { - if (ahp->work_icv) - kfree(ahp->work_icv); - if (ahp->tfm) - crypto_free_tfm(ahp->tfm); + kfree(ahp->work_icv); + crypto_free_tfm(ahp->tfm); kfree(ahp); } return -EINVAL; @@ -279,14 +277,10 @@ static void ah_destroy(struct xfrm_state *x) if (!ahp) return; - if (ahp->work_icv) { - kfree(ahp->work_icv); - ahp->work_icv = NULL; - } - if (ahp->tfm) { - crypto_free_tfm(ahp->tfm); - ahp->tfm = NULL; - } + kfree(ahp->work_icv); + ahp->work_icv = NULL; + crypto_free_tfm(ahp->tfm); + ahp->tfm = NULL; kfree(ahp); } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b31ffc5053d2..1b5a09d1b90b 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -343,22 +343,14 @@ static void esp_destroy(struct xfrm_state *x) if (!esp) return; - if (esp->conf.tfm) { - crypto_free_tfm(esp->conf.tfm); - esp->conf.tfm = NULL; - } - if (esp->conf.ivec) { - kfree(esp->conf.ivec); - esp->conf.ivec = NULL; - } - if (esp->auth.tfm) { - crypto_free_tfm(esp->auth.tfm); - esp->auth.tfm = NULL; - } - if (esp->auth.work_icv) { - kfree(esp->auth.work_icv); - esp->auth.work_icv = NULL; - } + crypto_free_tfm(esp->conf.tfm); + esp->conf.tfm = NULL; + kfree(esp->conf.ivec); + esp->conf.ivec = NULL; + crypto_free_tfm(esp->auth.tfm); + esp->auth.tfm = NULL; + kfree(esp->auth.work_icv); + esp->auth.work_icv = NULL; kfree(esp); } diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index dcb7ee6c4858..fc718df17b40 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -345,8 +345,7 @@ static void ipcomp_free_tfms(struct crypto_tfm **tfms) for_each_cpu(cpu) { struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); - if (tfm) - crypto_free_tfm(tfm); + crypto_free_tfm(tfm); } free_percpu(tfms); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 937ad32db77c..6d6fb74f3b52 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3593,10 +3593,8 @@ void __exit addrconf_cleanup(void) rtnl_unlock(); #ifdef CONFIG_IPV6_PRIVACY - if (likely(md5_tfm != NULL)) { - crypto_free_tfm(md5_tfm); - md5_tfm = NULL; - } + crypto_free_tfm(md5_tfm); + md5_tfm = NULL; #endif #ifdef CONFIG_PROC_FS diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 0ebfad907a03..f3629730eb15 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -401,10 +401,8 @@ static int ah6_init_state(struct xfrm_state *x) error: if (ahp) { - if (ahp->work_icv) - kfree(ahp->work_icv); - if (ahp->tfm) - crypto_free_tfm(ahp->tfm); + kfree(ahp->work_icv); + crypto_free_tfm(ahp->tfm); kfree(ahp); } return -EINVAL; @@ -417,14 +415,10 @@ static void ah6_destroy(struct xfrm_state *x) if (!ahp) return; - if (ahp->work_icv) { - kfree(ahp->work_icv); - ahp->work_icv = NULL; - } - if (ahp->tfm) { - crypto_free_tfm(ahp->tfm); - ahp->tfm = NULL; - } + kfree(ahp->work_icv); + ahp->work_icv = NULL; + crypto_free_tfm(ahp->tfm); + ahp->tfm = NULL; kfree(ahp); } diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index e8bff9d3d96c..9b27460f0cc7 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -276,22 +276,14 @@ static void esp6_destroy(struct xfrm_state *x) if (!esp) return; - if (esp->conf.tfm) { - crypto_free_tfm(esp->conf.tfm); - esp->conf.tfm = NULL; - } - if (esp->conf.ivec) { - kfree(esp->conf.ivec); - esp->conf.ivec = NULL; - } - if (esp->auth.tfm) { - crypto_free_tfm(esp->auth.tfm); - esp->auth.tfm = NULL; - } - if (esp->auth.work_icv) { - kfree(esp->auth.work_icv); - esp->auth.work_icv = NULL; - } + crypto_free_tfm(esp->conf.tfm); + esp->conf.tfm = NULL; + kfree(esp->conf.ivec); + esp->conf.ivec = NULL; + crypto_free_tfm(esp->auth.tfm); + esp->auth.tfm = NULL; + kfree(esp->auth.work_icv); + esp->auth.work_icv = NULL; kfree(esp); } diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 135383ef538f..85bfbc69b2c3 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -341,8 +341,7 @@ static void ipcomp6_free_tfms(struct crypto_tfm **tfms) for_each_cpu(cpu) { struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); - if (tfm) - crypto_free_tfm(tfm); + crypto_free_tfm(tfm); } free_percpu(tfms); } diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index e47ac0d1a6d6..e22ccd655965 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -193,8 +193,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) sctp_unhash_endpoint(ep); /* Free up the HMAC transform. */ - if (sctp_sk(ep->base.sk)->hmac) - sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); + sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); /* Cleanup. */ sctp_inq_free(&ep->base.inqueue); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 4454afe4727e..91ec8c936913 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4194,8 +4194,7 @@ out: sctp_release_sock(sk); return err; cleanup: - if (tfm) - sctp_crypto_free_tfm(tfm); + sctp_crypto_free_tfm(tfm); goto out; } diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 7ad74449b18f..ee6ae74cd1b2 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -199,8 +199,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, crypto_digest_final(tfm, cksum->data); code = 0; out: - if (tfm) - crypto_free_tfm(tfm); + crypto_free_tfm(tfm); return code; } diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index cf726510df8e..606a8a82cafb 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -185,12 +185,9 @@ static void gss_delete_sec_context_kerberos(void *internal_ctx) { struct krb5_ctx *kctx = internal_ctx; - if (kctx->seq) - crypto_free_tfm(kctx->seq); - if (kctx->enc) - crypto_free_tfm(kctx->enc); - if (kctx->mech_used.data) - kfree(kctx->mech_used.data); + crypto_free_tfm(kctx->seq); + crypto_free_tfm(kctx->enc); + kfree(kctx->mech_used.data); kfree(kctx); } diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index dad05994c3eb..6c97d61baa9b 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -214,14 +214,10 @@ static void gss_delete_sec_context_spkm3(void *internal_ctx) { struct spkm3_ctx *sctx = internal_ctx; - if(sctx->derived_integ_key) - crypto_free_tfm(sctx->derived_integ_key); - if(sctx->derived_conf_key) - crypto_free_tfm(sctx->derived_conf_key); - if(sctx->share_key.data) - kfree(sctx->share_key.data); - if(sctx->mech_used.data) - kfree(sctx->mech_used.data); + crypto_free_tfm(sctx->derived_integ_key); + crypto_free_tfm(sctx->derived_conf_key); + kfree(sctx->share_key.data); + kfree(sctx->mech_used.data); kfree(sctx); } From 2dac4b96b9362954a0638317b90e3e7bcb112e83 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 1 Sep 2005 17:44:49 -0700 Subject: [PATCH 13/17] [IPV6]: Repair Incoming Interface Handling for Raw Socket. Due to changes to enforce checking interface bindings, sockets did not see loopback packets bound for our local address on our interface. e.g.) When we ping6 fe80::1%eth0, skb->dev points loopback_dev while IP6CB(skb)->iif indicates eth0. This patch fixes the issue by using appropriate incoming interface, in the sense of scoping architecture. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/icmp.c | 2 +- net/ipv6/raw.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5176fc655ea9..fa8f1bb0aa52 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -549,7 +549,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) read_lock(&raw_v6_lock); if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) { while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, - skb->dev->ifindex))) { + IP6CB(skb)->iif))) { rawv6_err(sk, skb, NULL, type, code, inner_offset, info); sk = sk_next(sk); } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 7a5863298f3f..ed3a76b30fd9 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -166,7 +166,7 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) if (sk == NULL) goto out; - sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex); + sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); while (sk) { delivered = 1; @@ -178,7 +178,7 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) rawv6_rcv(sk, clone); } sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr, - skb->dev->ifindex); + IP6CB(skb)->iif); } out: read_unlock(&raw_v6_lock); From d80d99d643090c3cf2b1f9fb3fadd1256f7e384f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 1 Sep 2005 17:48:23 -0700 Subject: [PATCH 14/17] [NET]: Add sk_stream_wmem_schedule This patch introduces sk_stream_wmem_schedule as a short-hand for the sk_forward_alloc checking on egress. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/sock.h | 12 ++++++++---- net/ipv4/tcp.c | 3 +-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 312cb25cbd18..e51e626e9af1 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -709,6 +709,12 @@ static inline int sk_stream_rmem_schedule(struct sock *sk, struct sk_buff *skb) sk_stream_mem_schedule(sk, skb->truesize, 1); } +static inline int sk_stream_wmem_schedule(struct sock *sk, int size) +{ + return size <= sk->sk_forward_alloc || + sk_stream_mem_schedule(sk, size, 0); +} + /* Used by processes to "lock" a socket state, so that * interrupts and bottom half handlers won't change it * from under us. It essentially blocks any incoming @@ -1203,8 +1209,7 @@ static inline struct sk_buff *sk_stream_alloc_pskb(struct sock *sk, skb = alloc_skb_fclone(size + hdr_len, gfp); if (skb) { skb->truesize += mem; - if (sk->sk_forward_alloc >= (int)skb->truesize || - sk_stream_mem_schedule(sk, skb->truesize, 0)) { + if (sk_stream_wmem_schedule(sk, skb->truesize)) { skb_reserve(skb, hdr_len); return skb; } @@ -1227,8 +1232,7 @@ static inline struct page *sk_stream_alloc_page(struct sock *sk) { struct page *page = NULL; - if (sk->sk_forward_alloc >= (int)PAGE_SIZE || - sk_stream_mem_schedule(sk, PAGE_SIZE, 0)) + if (sk_stream_wmem_schedule(sk, PAGE_SIZE)) page = alloc_pages(sk->sk_allocation, 0); else { sk->sk_prot->enter_memory_pressure(); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 02fdda68718d..854f6d0c4bb3 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -552,8 +552,7 @@ new_segment: tcp_mark_push(tp, skb); goto new_segment; } - if (sk->sk_forward_alloc < copy && - !sk_stream_mem_schedule(sk, copy, 0)) + if (!sk_stream_wmem_schedule(sk, copy)) goto wait_for_memory; if (can_coalesce) { From ef015786152adaff5a6a8bf0c8ea2f70cee8059d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 1 Sep 2005 17:48:59 -0700 Subject: [PATCH 15/17] [TCP]: Fix sk_forward_alloc underflow in tcp_sendmsg I've finally found a potential cause of the sk_forward_alloc underflows that people have been reporting sporadically. When tcp_sendmsg tacks on extra bits to an existing TCP_PAGE we don't check sk_forward_alloc even though a large amount of time may have elapsed since we allocated the page. In the mean time someone could've come along and liberated packets and reclaimed sk_forward_alloc memory. This patch makes tcp_sendmsg check sk_forward_alloc every time as we do in do_tcp_sendpages. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/sock.h | 5 ++--- net/ipv4/tcp.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index e51e626e9af1..cf628261da52 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1232,9 +1232,8 @@ static inline struct page *sk_stream_alloc_page(struct sock *sk) { struct page *page = NULL; - if (sk_stream_wmem_schedule(sk, PAGE_SIZE)) - page = alloc_pages(sk->sk_allocation, 0); - else { + page = alloc_pages(sk->sk_allocation, 0); + if (!page) { sk->sk_prot->enter_memory_pressure(); sk_stream_moderate_sndbuf(sk); } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 854f6d0c4bb3..cbcc9fc47783 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -769,19 +769,23 @@ new_segment: if (off == PAGE_SIZE) { put_page(page); TCP_PAGE(sk) = page = NULL; + TCP_OFF(sk) = off = 0; } - } + } else + BUG_ON(off); + + if (copy > PAGE_SIZE - off) + copy = PAGE_SIZE - off; + + if (!sk_stream_wmem_schedule(sk, copy)) + goto wait_for_memory; if (!page) { /* Allocate new cache page. */ if (!(page = sk_stream_alloc_page(sk))) goto wait_for_memory; - off = 0; } - if (copy > PAGE_SIZE - off) - copy = PAGE_SIZE - off; - /* Time to copy data. We are close to * the end! */ err = skb_copy_to_page(sk, from, skb, page, From 6475be16fd9b3c6746ca4d18959246b13c669ea8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 Sep 2005 22:47:01 -0700 Subject: [PATCH 16/17] [TCP]: Keep TSO enabled even during loss events. All we need to do is resegment the queue so that we record SACK information accurately. The edges of the SACK blocks guide our resegmenting decisions. With help from Herbert Xu. Signed-off-by: David S. Miller --- include/net/tcp.h | 1 + net/ipv4/tcp_input.c | 36 ++++++++++++++++++---------- net/ipv4/tcp_output.c | 55 ++++++++++++++++--------------------------- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index d6bcf1317a6a..97af77c4d096 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -454,6 +454,7 @@ extern int tcp_retransmit_skb(struct sock *, struct sk_buff *); extern void tcp_xmit_retransmit_queue(struct sock *); extern void tcp_simple_retransmit(struct sock *); extern int tcp_trim_head(struct sock *, struct sk_buff *, u32); +extern int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int); extern void tcp_send_probe0(struct sock *); extern void tcp_send_partial(struct sock *); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 1afb080bdf0c..29222b964951 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -923,14 +923,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ int flag = 0; int i; - /* So, SACKs for already sent large segments will be lost. - * Not good, but alternative is to resegment the queue. */ - if (sk->sk_route_caps & NETIF_F_TSO) { - sk->sk_route_caps &= ~NETIF_F_TSO; - sock_set_flag(sk, SOCK_NO_LARGESEND); - tp->mss_cache = tp->mss_cache; - } - if (!tp->sacked_out) tp->fackets_out = 0; prior_fackets = tp->fackets_out; @@ -978,20 +970,40 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ flag |= FLAG_DATA_LOST; sk_stream_for_retrans_queue(skb, sk) { - u8 sacked = TCP_SKB_CB(skb)->sacked; - int in_sack; + int in_sack, pcount; + u8 sacked; /* The retransmission queue is always in order, so * we can short-circuit the walk early. */ - if(!before(TCP_SKB_CB(skb)->seq, end_seq)) + if (!before(TCP_SKB_CB(skb)->seq, end_seq)) break; - fack_count += tcp_skb_pcount(skb); + pcount = tcp_skb_pcount(skb); + + if (pcount > 1 && + (after(start_seq, TCP_SKB_CB(skb)->seq) || + before(end_seq, TCP_SKB_CB(skb)->end_seq))) { + unsigned int pkt_len; + + if (after(start_seq, TCP_SKB_CB(skb)->seq)) + pkt_len = (start_seq - + TCP_SKB_CB(skb)->seq); + else + pkt_len = (end_seq - + TCP_SKB_CB(skb)->seq); + if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size)) + break; + pcount = tcp_skb_pcount(skb); + } + + fack_count += pcount; in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && !before(end_seq, TCP_SKB_CB(skb)->end_seq); + sacked = TCP_SKB_CB(skb)->sacked; + /* Account D-SACK for retransmitted packet. */ if ((dup_sack && in_sack) && (sacked & TCPCB_RETRANS) && diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 75b68116682a..6094db5e11be 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -428,11 +428,11 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned * packet to the list. This won't be called frequently, I hope. * Remember, these are still headerless SKBs at this point. */ -static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now) +int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; - int nsize; + int nsize, old_factor; u16 flags; nsize = skb_headlen(skb) - len; @@ -490,18 +490,29 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned tp->left_out -= tcp_skb_pcount(skb); } + old_factor = tcp_skb_pcount(skb); + /* Fix up tso_factor for both original and new SKB. */ tcp_set_skb_tso_segs(sk, skb, mss_now); tcp_set_skb_tso_segs(sk, buff, mss_now); - if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { - tp->lost_out += tcp_skb_pcount(skb); - tp->left_out += tcp_skb_pcount(skb); - } + /* If this packet has been sent out already, we must + * adjust the various packet counters. + */ + if (after(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { + int diff = old_factor - tcp_skb_pcount(skb) - + tcp_skb_pcount(buff); - if (TCP_SKB_CB(buff)->sacked&TCPCB_LOST) { - tp->lost_out += tcp_skb_pcount(buff); - tp->left_out += tcp_skb_pcount(buff); + tp->packets_out -= diff; + if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { + tp->lost_out -= diff; + tp->left_out -= diff; + } + if (diff > 0) { + tp->fackets_out -= diff; + if ((int)tp->fackets_out < 0) + tp->fackets_out = 0; + } } /* Link BUFF into the send queue. */ @@ -1350,12 +1361,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) BUG(); - - if (sk->sk_route_caps & NETIF_F_TSO) { - sk->sk_route_caps &= ~NETIF_F_TSO; - sock_set_flag(sk, SOCK_NO_LARGESEND); - } - if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) return -ENOMEM; } @@ -1370,22 +1375,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) return -EAGAIN; if (skb->len > cur_mss) { - int old_factor = tcp_skb_pcount(skb); - int diff; - if (tcp_fragment(sk, skb, cur_mss, cur_mss)) return -ENOMEM; /* We'll try again later. */ - - /* New SKB created, account for it. */ - diff = old_factor - tcp_skb_pcount(skb) - - tcp_skb_pcount(skb->next); - tp->packets_out -= diff; - - if (diff > 0) { - tp->fackets_out -= diff; - if ((int)tp->fackets_out < 0) - tp->fackets_out = 0; - } } /* Collapse two adjacent packets if worthwhile and we can. */ @@ -1993,12 +1984,6 @@ int tcp_write_wakeup(struct sock *sk) TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; if (tcp_fragment(sk, skb, seg_size, mss)) return -1; - /* SWS override triggered forced fragmentation. - * Disable TSO, the connection is too sick. */ - if (sk->sk_route_caps & NETIF_F_TSO) { - sock_set_flag(sk, SOCK_NO_LARGESEND); - sk->sk_route_caps &= ~NETIF_F_TSO; - } } else if (!tcp_skb_pcount(skb)) tcp_set_skb_tso_segs(sk, skb, mss); From d70063c4634af060a5387337b7632f6334ca3458 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 2 Sep 2005 12:18:03 -0700 Subject: [PATCH 17/17] [ATM]: Fix dereference of uninitialized pointer in zatm Fixing breakage from [NET]: Kill skb->list - original was assign vcc do a bunch of stuff using ZATM_VCC(vcc)->pool as common subexpression Now we do int pos = ZATM_VCC(vcc)->pool; assign vcc do a bunch of stuff even though vcc is not even initialized when we enter that block... Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/atm/zatm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index c4b75ecf9460..55959e4d1cb7 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -417,9 +417,9 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); chan = (here[3] & uPD98401_AAL5_CHAN) >> uPD98401_AAL5_CHAN_SHIFT; if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) { - int pos = ZATM_VCC(vcc)->pool; - + int pos; vcc = zatm_dev->rx_map[chan]; + pos = ZATM_VCC(vcc)->pool; if (skb == zatm_dev->last_free[pos]) zatm_dev->last_free[pos] = NULL; skb_unlink(skb, zatm_dev->pool + pos);