diff --git a/debian/changelog b/debian/changelog index 0194219eb..47ccc606e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,37 @@ +linux-2.6 (2.6.17-3) UNRELEASED; urgency=low + + * Add stable release 2.6.17.2: + - ide-io: increase timeout value to allow for slave wakeup + - NTFS: Critical bug fix (affects MIPS and possibly others) + - Link error when futexes are disabled on 64bit architectures + - SCTP: Reset rtt_in_progress for the chunk when processing its sack. + - SPARC32: Fix iommu_flush_iotlb end address + - ETHTOOL: Fix UFO typo + - UML: fix uptime + - x86: compile fix for asm-i386/alternatives.h + - bcm43xx: init fix for possible Machine Check + - SCTP: Fix persistent slowdown in sctp when a gap ack consumes rx buffer. + - kbuild: bugfix with initramfs + - Input: return correct size when reading modalias attribute + - ohci1394: Fix broken suspend/resume in ohci1394 + - idr: fix race in idr code + - USB: Whiteheat: fix firmware spurious errors + - libata: minor patch for ATA_DFLAG_PIO + - SCTP: Send only 1 window update SACK per message. + - PFKEYV2: Fix inconsistent typing in struct sadb_x_kmprivate. + - SCTP: Limit association max_retrans setting in setsockopt. + - SCTP: Reject sctp packets with broadcast addresses. + - IPV6: Sum real space for RTAs. + - IPV6 ADDRCONF: Fix default source address selection without + CONFIG_IPV6_PRIVACY + - IPV6: Fix source address selection. + * Add stable release 2.6.17.3: + - NETFILTER: SCTP conntrack: fix crash triggered by packet without chunks + [CVE-2006-2934] + * Deapply merged sparc32-iotlb.patch. + + -- maximilian attems Tue, 4 Jul 2006 09:28:29 +0200 + linux-2.6 (2.6.17-2) unstable; urgency=low [ Jurij Smakov ] diff --git a/debian/patches/2.6.17.2 b/debian/patches/2.6.17.2 new file mode 100644 index 000000000..3cc2b2b91 --- /dev/null +++ b/debian/patches/2.6.17.2 @@ -0,0 +1,661 @@ +diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c +index 77840c8..7215849 100644 +--- a/arch/sparc/mm/iommu.c ++++ b/arch/sparc/mm/iommu.c +@@ -144,8 +144,9 @@ static void iommu_flush_iotlb(iopte_t *i + unsigned long start; + unsigned long end; + +- start = (unsigned long)iopte & PAGE_MASK; ++ start = (unsigned long)iopte; + end = PAGE_ALIGN(start + niopte*sizeof(iopte_t)); ++ start &= PAGE_MASK; + if (viking_mxcc_present) { + while(start < end) { + viking_mxcc_flush_page(start); +diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c +index 86f51d0..87cdbc5 100644 +--- a/arch/um/kernel/time_kern.c ++++ b/arch/um/kernel/time_kern.c +@@ -87,7 +87,7 @@ #endif + + void time_init_kern(void) + { +- unsigned long long nsecs; ++ long long nsecs; + + nsecs = os_nsecs(); + set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, +diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c +index c01615d..5748554 100644 +--- a/drivers/ide/ide-io.c ++++ b/drivers/ide/ide-io.c +@@ -932,7 +932,7 @@ #endif + printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); + SELECT_DRIVE(drive); + HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); +- rc = ide_wait_not_busy(HWIF(drive), 10000); ++ rc = ide_wait_not_busy(HWIF(drive), 100000); + if (rc) + printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); + } +diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c +index 11f1377..8f1292c 100644 +--- a/drivers/ieee1394/ohci1394.c ++++ b/drivers/ieee1394/ohci1394.c +@@ -3539,6 +3539,7 @@ #ifdef CONFIG_PPC_PMAC + } + #endif /* CONFIG_PPC_PMAC */ + ++ pci_restore_state(pdev); + pci_enable_device(pdev); + + return 0; +@@ -3558,6 +3559,8 @@ #ifdef CONFIG_PPC_PMAC + } + #endif + ++ pci_save_state(pdev); ++ + return 0; + } + +diff --git a/drivers/input/input.c b/drivers/input/input.c +index 3038c26..b149c94 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -629,7 +629,7 @@ static ssize_t input_dev_show_modalias(s + + len = input_print_modalias(buf, PAGE_SIZE, id, 1); + +- return max_t(int, len, PAGE_SIZE); ++ return min_t(int, len, PAGE_SIZE); + } + static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); + +diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c +index 7ed18ca..513fc75 100644 +--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c ++++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c +@@ -1870,6 +1870,15 @@ static irqreturn_t bcm43xx_interrupt_han + + spin_lock(&bcm->_lock); + ++ /* Only accept IRQs, if we are initialized properly. ++ * This avoids an RX race while initializing. ++ * We should probably not enable IRQs before we are initialized ++ * completely, but some careful work is needed to fix this. I think it ++ * is best to stay with this cheap workaround for now... . ++ */ ++ if (unlikely(!bcm->initialized)) ++ goto out; ++ + reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) { + /* irq not for us (shared irq) */ +@@ -1891,20 +1900,11 @@ static irqreturn_t bcm43xx_interrupt_han + + bcm43xx_interrupt_ack(bcm, reason); + +- /* Only accept IRQs, if we are initialized properly. +- * This avoids an RX race while initializing. +- * We should probably not enable IRQs before we are initialized +- * completely, but some careful work is needed to fix this. I think it +- * is best to stay with this cheap workaround for now... . +- */ +- if (likely(bcm->initialized)) { +- /* disable all IRQs. They are enabled again in the bottom half. */ +- bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); +- /* save the reason code and call our bottom half. */ +- bcm->irq_reason = reason; +- tasklet_schedule(&bcm->isr_tasklet); +- } +- ++ /* disable all IRQs. They are enabled again in the bottom half. */ ++ bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); ++ /* save the reason code and call our bottom half. */ ++ bcm->irq_reason = reason; ++ tasklet_schedule(&bcm->isr_tasklet); + out: + mmiowb(); + spin_unlock(&bcm->_lock); +diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig +index f63c387..6c8452e 100644 +--- a/drivers/parport/Kconfig ++++ b/drivers/parport/Kconfig +@@ -48,7 +48,7 @@ config PARPORT_PC + + config PARPORT_SERIAL + tristate "Multi-IO cards (parallel and serial)" +- depends on SERIAL_8250 && PARPORT_PC && PCI ++ depends on SERIAL_8250_PCI && PARPORT_PC && PCI + help + This adds support for multi-IO PCI cards that have parallel and + serial ports. You should say Y or M here. If you say M, the module +diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c +index b046ffa..6cd197d 100644 +--- a/drivers/scsi/libata-core.c ++++ b/drivers/scsi/libata-core.c +@@ -1229,7 +1229,7 @@ static int ata_dev_configure(struct ata_ + id[84], id[85], id[86], id[87], id[88]); + + /* initialize to-be-configured parameters */ +- dev->flags = 0; ++ dev->flags &= ~ATA_DFLAG_CFG_MASK; + dev->max_sectors = 0; + dev->cdb_len = 0; + dev->n_sectors = 0; +diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c +index f806553..3ced09c 100644 +--- a/drivers/usb/serial/whiteheat.c ++++ b/drivers/usb/serial/whiteheat.c +@@ -388,7 +388,7 @@ static int whiteheat_attach (struct usb_ + if (ret) { + err("%s: Couldn't send command [%d]", serial->type->description, ret); + goto no_firmware; +- } else if (alen != sizeof(command)) { ++ } else if (alen != 2) { + err("%s: Send command incomplete [%d]", serial->type->description, alen); + goto no_firmware; + } +@@ -400,7 +400,7 @@ static int whiteheat_attach (struct usb_ + if (ret) { + err("%s: Couldn't get results [%d]", serial->type->description, ret); + goto no_firmware; +- } else if (alen != sizeof(result)) { ++ } else if (alen != sizeof(*hw_info) + 1) { + err("%s: Get results incomplete [%d]", serial->type->description, alen); + goto no_firmware; + } else if (result[0] != command[0]) { +diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c +index c63a83e..36e1e13 100644 +--- a/fs/ntfs/file.c ++++ b/fs/ntfs/file.c +@@ -1484,14 +1484,15 @@ static inline void ntfs_flush_dcache_pag + unsigned nr_pages) + { + BUG_ON(!nr_pages); ++ /* ++ * Warning: Do not do the decrement at the same time as the call to ++ * flush_dcache_page() because it is a NULL macro on i386 and hence the ++ * decrement never happens so the loop never terminates. ++ */ + do { +- /* +- * Warning: Do not do the decrement at the same time as the +- * call because flush_dcache_page() is a NULL macro on i386 +- * and hence the decrement never happens. +- */ ++ --nr_pages; + flush_dcache_page(pages[nr_pages]); +- } while (--nr_pages > 0); ++ } while (nr_pages > 0); + } + + /** +diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h +index e201dec..d79e9ee 100644 +--- a/include/asm-i386/alternative.h ++++ b/include/asm-i386/alternative.h +@@ -3,6 +3,8 @@ #define _I386_ALTERNATIVE_H + + #ifdef __KERNEL__ + ++#include ++ + struct alt_instr { + u8 *instr; /* original instruction */ + u8 *replacement; +diff --git a/include/linux/libata.h b/include/linux/libata.h +index b80d2e7..05d3fb3 100644 +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -120,9 +120,12 @@ enum { + ATA_SHT_USE_CLUSTERING = 1, + + /* struct ata_device stuff */ +- ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ +- ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ +- ATA_DFLAG_LBA = (1 << 2), /* device supports LBA */ ++ ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ ++ ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ ++ ++ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ++ ++ ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ + + ATA_DEV_UNKNOWN = 0, /* unknown device */ + ATA_DEV_ATA = 1, /* ATA device */ +diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h +index bac0fb3..d5dd471 100644 +--- a/include/linux/pfkeyv2.h ++++ b/include/linux/pfkeyv2.h +@@ -159,7 +159,7 @@ struct sadb_spirange { + struct sadb_x_kmprivate { + uint16_t sadb_x_kmprivate_len; + uint16_t sadb_x_kmprivate_exttype; +- u_int32_t sadb_x_kmprivate_reserved; ++ uint32_t sadb_x_kmprivate_reserved; + } __attribute__((packed)); + /* sizeof(struct sadb_x_kmprivate) == 8 */ + +diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h +index 7f4fea1..5f69158 100644 +--- a/include/net/sctp/structs.h ++++ b/include/net/sctp/structs.h +@@ -555,7 +555,8 @@ struct sctp_af { + int (*to_addr_param) (const union sctp_addr *, + union sctp_addr_param *); + int (*addr_valid) (union sctp_addr *, +- struct sctp_sock *); ++ struct sctp_sock *, ++ const struct sk_buff *); + sctp_scope_t (*scope) (union sctp_addr *); + void (*inaddr_any) (union sctp_addr *, unsigned short); + int (*is_any) (const union sctp_addr *); +diff --git a/kernel/exit.c b/kernel/exit.c +index e06d0c1..ccf791b 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -899,7 +899,7 @@ fastcall NORET_TYPE void do_exit(long co + } + if (unlikely(tsk->robust_list)) + exit_robust_list(tsk); +-#ifdef CONFIG_COMPAT ++#if defined(CONFIG_FUTEX) && defined(CONFIG_COMPAT) + if (unlikely(tsk->compat_robust_list)) + compat_exit_robust_list(tsk); + #endif +diff --git a/lib/idr.c b/lib/idr.c +index d226259..de19030 100644 +--- a/lib/idr.c ++++ b/lib/idr.c +@@ -48,15 +48,21 @@ static struct idr_layer *alloc_layer(str + return(p); + } + ++/* only called when idp->lock is held */ ++static void __free_layer(struct idr *idp, struct idr_layer *p) ++{ ++ p->ary[0] = idp->id_free; ++ idp->id_free = p; ++ idp->id_free_cnt++; ++} ++ + static void free_layer(struct idr *idp, struct idr_layer *p) + { + /* + * Depends on the return element being zeroed. + */ + spin_lock(&idp->lock); +- p->ary[0] = idp->id_free; +- idp->id_free = p; +- idp->id_free_cnt++; ++ __free_layer(idp, p); + spin_unlock(&idp->lock); + } + +@@ -184,12 +190,14 @@ build_up: + * The allocation failed. If we built part of + * the structure tear it down. + */ ++ spin_lock(&idp->lock); + for (new = p; p && p != idp->top; new = p) { + p = p->ary[0]; + new->ary[0] = NULL; + new->bitmap = new->count = 0; +- free_layer(idp, new); ++ __free_layer(idp, new); + } ++ spin_unlock(&idp->lock); + return -1; + } + new->ary[0] = p; +diff --git a/net/core/ethtool.c b/net/core/ethtool.c +index e6f7610..c680b7e 100644 +--- a/net/core/ethtool.c ++++ b/net/core/ethtool.c +@@ -591,7 +591,7 @@ static int ethtool_set_tso(struct net_de + + static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr) + { +- struct ethtool_value edata = { ETHTOOL_GTSO }; ++ struct ethtool_value edata = { ETHTOOL_GUFO }; + + if (!dev->ethtool_ops->get_ufo) + return -EOPNOTSUPP; +@@ -600,6 +600,7 @@ static int ethtool_get_ufo(struct net_de + return -EFAULT; + return 0; + } ++ + static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) + { + struct ethtool_value edata; +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 445006e..4da6645 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -862,6 +862,8 @@ static int inline ipv6_saddr_label(const + * 2002::/16 2 + * ::/96 3 + * ::ffff:0:0/96 4 ++ * fc00::/7 5 ++ * 2001::/32 6 + */ + if (type & IPV6_ADDR_LOOPBACK) + return 0; +@@ -869,8 +871,12 @@ static int inline ipv6_saddr_label(const + return 3; + else if (type & IPV6_ADDR_MAPPED) + return 4; ++ else if (addr->s6_addr32[0] == htonl(0x20010000)) ++ return 6; + else if (addr->s6_addr16[0] == htons(0x2002)) + return 2; ++ else if ((addr->s6_addr[0] & 0xfe) == 0xfc) ++ return 5; + return 1; + } + +@@ -1069,6 +1075,9 @@ #ifdef CONFIG_IPV6_PRIVACY + if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY) + continue; + } ++#else ++ if (hiscore.rule < 7) ++ hiscore.rule++; + #endif + /* Rule 8: Use longest matching prefix */ + if (hiscore.rule < 8) { +@@ -2860,6 +2869,11 @@ inet6_rtm_newaddr(struct sk_buff *skb, s + return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen); + } + ++/* Maximum length of ifa_cacheinfo attributes */ ++#define INET6_IFADDR_RTA_SPACE \ ++ RTA_SPACE(16) /* IFA_ADDRESS */ + \ ++ RTA_SPACE(sizeof(struct ifa_cacheinfo)) /* CACHEINFO */ ++ + static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, + u32 pid, u32 seq, int event, unsigned int flags) + { +@@ -3092,7 +3106,7 @@ static int inet6_dump_ifacaddr(struct sk + static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) + { + struct sk_buff *skb; +- int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128); ++ int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { +@@ -3142,6 +3156,17 @@ #endif + #endif + } + ++/* Maximum length of ifinfomsg attributes */ ++#define INET6_IFINFO_RTA_SPACE \ ++ RTA_SPACE(IFNAMSIZ) /* IFNAME */ + \ ++ RTA_SPACE(MAX_ADDR_LEN) /* ADDRESS */ + \ ++ RTA_SPACE(sizeof(u32)) /* MTU */ + \ ++ RTA_SPACE(sizeof(int)) /* LINK */ + \ ++ RTA_SPACE(0) /* PROTINFO */ + \ ++ RTA_SPACE(sizeof(u32)) /* FLAGS */ + \ ++ RTA_SPACE(sizeof(struct ifla_cacheinfo)) /* CACHEINFO */ + \ ++ RTA_SPACE(sizeof(__s32[DEVCONF_MAX])) /* CONF */ ++ + static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, + u32 pid, u32 seq, int event, unsigned int flags) + { +@@ -3235,8 +3260,7 @@ static int inet6_dump_ifinfo(struct sk_b + void inet6_ifinfo_notify(int event, struct inet6_dev *idev) + { + struct sk_buff *skb; +- /* 128 bytes ?? */ +- int size = NLMSG_SPACE(sizeof(struct ifinfomsg)+128); ++ int size = NLMSG_SPACE(sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE); + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { +@@ -3252,6 +3276,11 @@ void inet6_ifinfo_notify(int event, stru + netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC); + } + ++/* Maximum length of prefix_cacheinfo attributes */ ++#define INET6_PREFIX_RTA_SPACE \ ++ RTA_SPACE(sizeof(((struct prefix_info *)NULL)->prefix)) /* ADDRESS */ + \ ++ RTA_SPACE(sizeof(struct prefix_cacheinfo)) /* CACHEINFO */ ++ + static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, + struct prefix_info *pinfo, u32 pid, u32 seq, + int event, unsigned int flags) +@@ -3296,7 +3325,7 @@ static void inet6_prefix_notify(int even + struct prefix_info *pinfo) + { + struct sk_buff *skb; +- int size = NLMSG_SPACE(sizeof(struct prefixmsg)+128); ++ int size = NLMSG_SPACE(sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE); + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { +diff --git a/net/sctp/input.c b/net/sctp/input.c +index 1662f9c..70d6606 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -170,7 +170,8 @@ int sctp_rcv(struct sk_buff *skb) + * IP broadcast addresses cannot be used in an SCTP transport + * address." + */ +- if (!af->addr_valid(&src, NULL) || !af->addr_valid(&dest, NULL)) ++ if (!af->addr_valid(&src, NULL, skb) || ++ !af->addr_valid(&dest, NULL, skb)) + goto discard_it; + + asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); +diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c +index c20d282..8ef0807 100644 +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -523,7 +523,9 @@ static int sctp_v6_available(union sctp_ + * Return 0 - If the address is a non-unicast or an illegal address. + * Return 1 - If the address is a unicast. + */ +-static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_sock *sp) ++static int sctp_v6_addr_valid(union sctp_addr *addr, ++ struct sctp_sock *sp, ++ const struct sk_buff *skb) + { + int ret = ipv6_addr_type(&addr->v6.sin6_addr); + +@@ -537,7 +539,7 @@ static int sctp_v6_addr_valid(union sctp + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; + sctp_v6_map_v4(addr); +- return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp); ++ return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb); + } + + /* Is this a non-unicast address */ +diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c +index f148f95..e5faa35 100644 +--- a/net/sctp/outqueue.c ++++ b/net/sctp/outqueue.c +@@ -1262,6 +1262,7 @@ #endif /* SCTP_DEBUG */ + if (!tchunk->tsn_gap_acked && + !tchunk->resent && + tchunk->rtt_in_progress) { ++ tchunk->rtt_in_progress = 0; + rtt = jiffies - tchunk->sent_at; + sctp_transport_update_rto(transport, + rtt); +diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c +index 2088aa9..816c033 100644 +--- a/net/sctp/protocol.c ++++ b/net/sctp/protocol.c +@@ -365,12 +365,18 @@ static int sctp_v4_is_any(const union sc + * Return 0 - If the address is a non-unicast or an illegal address. + * Return 1 - If the address is a unicast. + */ +-static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_sock *sp) ++static int sctp_v4_addr_valid(union sctp_addr *addr, ++ struct sctp_sock *sp, ++ const struct sk_buff *skb) + { + /* Is this a non-unicast address or a unusable SCTP address? */ + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) + return 0; + ++ /* Is this a broadcast address? */ ++ if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST) ++ return 0; ++ + return 1; + } + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 8bc2792..9e58144 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -5293,10 +5293,18 @@ static int sctp_eat_data(const struct sc + * seems a bit troublesome in that frag_point varies based on + * PMTU. In cases, such as loopback, this might be a rather + * large spill over. ++ * NOTE: If we have a full receive buffer here, we only renege if ++ * our receiver can still make progress without the tsn being ++ * received. We do this because in the event that the associations ++ * receive queue is empty we are filling a leading gap, and since ++ * reneging moves the gap to the end of the tsn stream, we are likely ++ * to stall again very shortly. Avoiding the renege when we fill a ++ * leading gap is a good heuristic for avoiding such steady state ++ * stalls. + */ + if (!asoc->rwnd || asoc->rwnd_over || + (datalen > asoc->rwnd + asoc->frag_point) || +- rcvbuf_over) { ++ (rcvbuf_over && (!skb_queue_len(&sk->sk_receive_queue)))) { + + /* If this is the next TSN, consider reneging to make + * room. Note: Playing nice with a confused sender. A +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 174d4d3..b811691 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -172,7 +172,7 @@ static inline int sctp_verify_addr(struc + return -EINVAL; + + /* Is this a valid SCTP address? */ +- if (!af->addr_valid(addr, sctp_sk(sk))) ++ if (!af->addr_valid(addr, sctp_sk(sk), NULL)) + return -EINVAL; + + if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) +@@ -2530,8 +2530,32 @@ static int sctp_setsockopt_associnfo(str + + /* Set the values to the specific association */ + if (asoc) { +- if (assocparams.sasoc_asocmaxrxt != 0) ++ if (assocparams.sasoc_asocmaxrxt != 0) { ++ __u32 path_sum = 0; ++ int paths = 0; ++ struct list_head *pos; ++ struct sctp_transport *peer_addr; ++ ++ list_for_each(pos, &asoc->peer.transport_addr_list) { ++ peer_addr = list_entry(pos, ++ struct sctp_transport, ++ transports); ++ path_sum += peer_addr->pathmaxrxt; ++ paths++; ++ } ++ ++ /* Only validate asocmaxrxt if we have more then ++ * one path/transport. We do this because path ++ * retransmissions are only counted when we have more ++ * then one path. ++ */ ++ if (paths > 1 && ++ assocparams.sasoc_asocmaxrxt > path_sum) ++ return -EINVAL; ++ + asoc->max_retrans = assocparams.sasoc_asocmaxrxt; ++ } ++ + if (assocparams.sasoc_cookie_life != 0) { + asoc->cookie_life.tv_sec = + assocparams.sasoc_cookie_life / 1000; +diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c +index ba97f97..ee23678 100644 +--- a/net/sctp/ulpevent.c ++++ b/net/sctp/ulpevent.c +@@ -51,6 +51,8 @@ #include + static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, + struct sctp_association *asoc); + static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); ++static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event); ++ + + /* Initialize an ULP event from an given skb. */ + SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) +@@ -883,6 +885,7 @@ static void sctp_ulpevent_receive_data(s + static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) + { + struct sk_buff *skb, *frag; ++ unsigned int len; + + /* Current stack structures assume that the rcv buffer is + * per socket. For UDP style sockets this is not true as +@@ -892,7 +895,30 @@ static void sctp_ulpevent_release_data(s + */ + + skb = sctp_event2skb(event); +- sctp_assoc_rwnd_increase(event->asoc, skb_headlen(skb)); ++ len = skb->len; ++ ++ if (!skb->data_len) ++ goto done; ++ ++ /* Don't forget the fragments. */ ++ for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { ++ /* NOTE: skb_shinfos are recursive. Although IP returns ++ * skb's with only 1 level of fragments, SCTP reassembly can ++ * increase the levels. ++ */ ++ sctp_ulpevent_release_frag_data(sctp_skb2event(frag)); ++ } ++ ++done: ++ sctp_assoc_rwnd_increase(event->asoc, len); ++ sctp_ulpevent_release_owner(event); ++} ++ ++static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event) ++{ ++ struct sk_buff *skb, *frag; ++ ++ skb = sctp_event2skb(event); + + if (!skb->data_len) + goto done; +@@ -903,7 +929,7 @@ static void sctp_ulpevent_release_data(s + * skb's with only 1 level of fragments, SCTP reassembly can + * increase the levels. + */ +- sctp_ulpevent_release_data(sctp_skb2event(frag)); ++ sctp_ulpevent_release_frag_data(sctp_skb2event(frag)); + } + + done: +diff --git a/usr/Makefile b/usr/Makefile +index 19d74e6..e938242 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -21,8 +21,7 @@ ramfs-input := $(if $(filter-out "",$(CO + $(CONFIG_INITRAMFS_SOURCE),-d) + ramfs-args := \ + $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \ +- $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) \ +- $(ramfs-input) ++ $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) + + # .initramfs_data.cpio.gz.d is used to identify all files included + # in initramfs and to detect if any files are added/removed. diff --git a/debian/patches/2.6.17.3 b/debian/patches/2.6.17.3 new file mode 100644 index 000000000..4d7658f10 --- /dev/null +++ b/debian/patches/2.6.17.3 @@ -0,0 +1,26 @@ +diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +index 0416073..2d3612c 100644 +--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c ++++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +@@ -254,7 +254,7 @@ static int do_basic_checks(struct ip_con + } + + DEBUGP("Basic checks passed\n"); +- return 0; ++ return count == 0; + } + + static int new_state(enum ip_conntrack_dir dir, +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index 0c6da49..9dab81d 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -259,7 +259,7 @@ static int do_basic_checks(struct nf_con + } + + DEBUGP("Basic checks passed\n"); +- return 0; ++ return count == 0; + } + + static int new_state(enum ip_conntrack_dir dir, diff --git a/debian/patches/series/3 b/debian/patches/series/3 new file mode 100644 index 000000000..fecdab30c --- /dev/null +++ b/debian/patches/series/3 @@ -0,0 +1,3 @@ +- sparc32-iotlb.patch ++ 2.6.17.2 ++ 2.6.17.3