From e8c56451307455b2aeb2b515383a90625ad266d2 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:12:04 -0500 Subject: [PATCH] Import 2.0.36pre17 --- arch/i386/kernel/irq.c | 20 +++- crud | 236 +++++++++++++++++++++++++++++++++++++++++ drivers/net/shaper.c | 2 +- drivers/pci/pci.c | 2 + drivers/scsi/aic7xxx.c | 23 +++- drivers/scsi/scsicam.c | 6 ++ fs/fat/file.c | 4 +- include/asm-i386/irq.h | 33 +++--- include/linux/pci.h | 3 + net/ipv4/ip_masq.c | 47 ++++---- 10 files changed, 328 insertions(+), 48 deletions(-) create mode 100644 crud diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index ac7a078897be..f29dd176598a 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -345,7 +345,25 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction * action = *(irq + irq_action); int do_random = 0; - + int c,intm,mask; + static int count; + if (smp_processor_id() != 0 && count++ < 1000) + printk("IRQ %d: done by CPU %d\n",irq,smp_processor_id()); + if (irq >= 8) { + c = cache_A1; + intm = inb(0xA1); + mask = 1 << (irq - 8); + } else { + c = cache_21; + intm = inb(0x21); + mask = 1 << irq; + } + if (!(c & mask) || !(intm & mask)) { + printk("IRQ %d (proc %d):cache_x1=0x%x,INT mask=0x%x\n", irq, smp_processor_id(),c,intm); + /* better to return because the interrupt may be asserted again, + the bad thing is that we may loose some interrupts */ + return; + } #ifdef __SMP__ if(smp_threads_ready && active_kernel_processor!=smp_processor_id()) panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id()); diff --git a/crud b/crud new file mode 100644 index 000000000000..f9ccc5a0e304 --- /dev/null +++ b/crud @@ -0,0 +1,236 @@ +Date: Tue, 3 Nov 1998 17:53:44 -0300 +From: Juanjo Ciarlante +To: Linus Torvalds , "David S. Miller" , David Woodhouse +Cc: linux-kernel@vger.rutgers.edu +Subject: [PATCH] IP masq csum fix + + +On Tue, Nov 03, 1998 at 04:51:34PM +0000, David Woodhouse wrote: +> Thanks to Juanjo and Andi, I think this problem is now fixed. +> +> I think both of you simultaneously came up with the idea that the offset of +> the data payload (proto_doff) could be negative, causing csum_partial() to +> checksum the whole of physical memory before oopsing. +> +This patch fixes incorrect ip_masq csuming when faced with corrupted pkts. + +It have been succesfully tested by David "tortured-by-Oops" Woodhouse, +his Oops have stopped so apparently it did fix the problem +(_apart_ from the "apparent-fix" its a REAL code fix). + +Linus, could you please apply it? + +-- +-- Juanjo http://juanjox.home.ml.org/ + + == free collective power ==---. + Linux <------------' + + + +Basically, this patch does an ``anal-tappo'' protocol data size +check at ip_fw_*masq() entry path. + + +--- linux/net/ipv4/ip_masq.c.dist Fri Oct 23 10:39:57 1998 ++++ linux/net/ipv4/ip_masq.c Tue Nov 3 17:15:36 1998 +@@ -337,6 +337,9 @@ + #define PORT_MASQ_MUL 10 + #endif + ++/* ++ * At the moment, hardcore in sync with masq_proto_num ++ */ + atomic_t ip_masq_free_ports[3] = { + ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* UDP */ + ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* TCP */ +@@ -960,15 +963,40 @@ + return NULL; + } + +-static __inline__ unsigned proto_doff(unsigned proto, char *th) ++/* ++ * Get transport protocol data offset, check against size ++ */ ++static __inline__ int proto_doff(unsigned proto, char *th, unsigned size) + { ++ unsigned ret = -1; + switch (proto) { ++ case IPPROTO_ICMP: ++ if (size >= sizeof(struct icmphdr)) ++ ret = sizeof(struct icmphdr); ++ break; + case IPPROTO_UDP: +- return sizeof(struct udphdr); ++ if (size >= sizeof(struct udphdr)) ++ ret = sizeof(struct udphdr); ++ break; + case IPPROTO_TCP: +- return ((struct tcphdr*)th)->doff << 2; ++ /* ++ * Is this case, this check _also_ avoids ++ * touching an invalid pointer if ++ * size is invalid ++ */ ++ if (size >= sizeof(struct tcphdr)) { ++ ret = ((struct tcphdr*)th)->doff << 2; ++ if (ret > size) { ++ ret = -1 ; ++ } ++ } ++ ++ break; + } +- return 0; ++ if (ret < 0) ++ IP_MASQ_DEBUG(0, "mess proto_doff for proto=%d, size =%d\n", ++ proto, size); ++ return ret; + } + + int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr) +@@ -980,19 +1008,26 @@ + int size; + + /* +- * Magic "doff" csum semantics +- * !0: saved payload csum IS valid, doff is correct +- * 0: csum not valid ++ * doff holds transport protocol data offset ++ * csum holds its checksum ++ * csum_ok says if csum is valid + */ +- unsigned doff = 0; ++ int doff = 0; + int csum = 0; ++ int csum_ok = 0; + + /* + * We can only masquerade protocols with ports... and hack some ICMPs + */ + + h.raw = (char*) iph + iph->ihl * 4; ++ size = ntohs(iph->tot_len) - (iph->ihl * 4); + ++ doff = proto_doff(iph->protocol, h.raw, size); ++ if (doff < 0) { ++ IP_MASQ_DEBUG(0, "O-pkt invalid packet data size\n"); ++ return -1; ++ } + switch (iph->protocol) { + case IPPROTO_ICMP: + return(ip_fw_masq_icmp(skb_p, maddr)); +@@ -1002,7 +1037,6 @@ + break; + case IPPROTO_TCP: + /* Make sure packet is in the masq range */ +- size = ntohs(iph->tot_len) - (iph->ihl * 4); + IP_MASQ_DEBUG(3, "O-pkt: %s size=%d\n", + masq_proto_name(iph->protocol), + size); +@@ -1011,7 +1045,7 @@ + switch (skb->ip_summed) + { + case CHECKSUM_NONE: +- doff = proto_doff(iph->protocol, h.raw); ++ csum_ok++; + csum = csum_partial(h.raw + doff, size - doff, 0); + IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n", + masq_proto_name(iph->protocol), +@@ -1133,7 +1167,7 @@ + */ + + if (ms->app) +- doff = 0; ++ csum_ok = 0; + + /* + * Attempt ip_masq_app call. +@@ -1148,6 +1182,7 @@ + iph = skb->nh.iph; + h.raw = (char*) iph + iph->ihl *4; + size = skb->len - (h.raw - skb->nh.raw); ++ /* doff should have not changed */ + } + + /* +@@ -1158,8 +1193,7 @@ + * Transport's payload partial csum + */ + +- if (!doff) { +- doff = proto_doff(iph->protocol, h.raw); ++ if (!csum_ok) { + csum = csum_partial(h.raw + doff, size - doff, 0); + } + skb->csum = csum; +@@ -1710,8 +1744,9 @@ + union ip_masq_tphdr h; + struct ip_masq *ms; + unsigned short size; +- unsigned doff = 0; ++ int doff = 0; + int csum = 0; ++ int csum_ok = 0; + __u32 maddr; + + /* +@@ -1727,8 +1762,19 @@ + return 0; + } + +- maddr = iph->daddr; + h.raw = (char*) iph + iph->ihl * 4; ++ /* ++ * IP payload size ++ */ ++ size = ntohs(iph->tot_len) - (iph->ihl * 4); ++ ++ doff = proto_doff(iph->protocol, h.raw, size); ++ if (doff < 0) { ++ IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n"); ++ return -1; ++ } ++ ++ maddr = iph->daddr; + + switch (iph->protocol) { + case IPPROTO_ICMP: +@@ -1749,7 +1795,6 @@ + return 0; + + /* Check that the checksum is OK */ +- size = ntohs(iph->tot_len) - (iph->ihl * 4); + if ((iph->protocol == IPPROTO_UDP) && (h.uh->check == 0)) + /* No UDP checksum */ + break; +@@ -1757,8 +1802,8 @@ + switch (skb->ip_summed) + { + case CHECKSUM_NONE: +- doff = proto_doff(iph->protocol, h.raw); + csum = csum_partial(h.raw + doff, size - doff, 0); ++ csum_ok++; + skb->csum = csum_partial(h.raw , doff, csum); + + case CHECKSUM_HW: +@@ -1846,7 +1891,7 @@ + */ + + if (ms->app) +- doff = 0; ++ csum_ok = 0; + + /* + * Attempt ip_masq_app call. +@@ -1873,8 +1918,7 @@ + * Transport's payload partial csum + */ + +- if (!doff) { +- doff = proto_doff(iph->protocol, h.raw); ++ if (!csum_ok) { + csum = csum_partial(h.raw + doff, size - doff, 0); + } + skb->csum = csum; + diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index fc81c94c8010..ace995c843c9 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -483,7 +483,7 @@ static int shaper_ioctl(struct device *dev, struct ifreq *ifr, int cmd) case SHAPER_GET_DEV: if(sh->dev==NULL) return -ENODEV; - memcpy(ss->ss_name, sh->dev->name, strlen(sh->dev->name)+1); + strcpy(ss->ss_name, sh->dev->name); return 0; case SHAPER_SET_SPEED: shaper_setspeed(sh,ss->ss_speed); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6eabf8eba456..bb79cc472c30 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -262,6 +262,8 @@ struct pci_dev_info dev_info[] = { DEVICE( WINBOND, WINBOND_82C105, "SL82C105"), DEVICE( WINBOND, WINBOND_83C553, "W83C553"), DEVICE( DATABOOK, DATABOOK_87144, "DB87144"), + DEVICE( PLX, PLX_SPCOM200, "SPCom 200 PCI serial I/O"), + DEVICE( PLX, PLX_9050, "PLX9050 PCI <-> IOBus Bridge"), DEVICE( PLX, PLX_9080, "PCI9080 I2O"), DEVICE( MADGE, MADGE_MK2, "Smart 16/4 BM Mk2 Ringnode"), DEVICE( 3COM, 3COM_3C339, "3C339 TokenRing"), diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index 7d40dae74596..4edef1bdc225 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -349,7 +349,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = { 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.2" +#define AIC7XXX_C_VERSION "5.1.3" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -9186,6 +9186,27 @@ aic7xxx_detect(Scsi_Host_Template *template) DSCOMMAND0); aic7xxx_load_seeprom(temp_p, &sxfrctl1); break; + case AHC_AIC7880: + /* + * Only set the DSCOMMAND0 register if this is a Rev B. + * chipset. For those, we also enable Ultra mode by + * force due to brain-damage on the part of some BIOSes + * We overload the devconfig variable here since we can. + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) + pci_read_config_dword(pdev, DEVCONFIG, &devconfig); +#else + pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, + &devconfig); +#endif + if ((devconfig & 0xff) >= 1) + { + aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | + CACHETHEN | MPARCKEN) & ~DPARCKEN, + DSCOMMAND0); + } + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + break; } diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 08e8855ea324..2c6f63772b82 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -50,6 +50,7 @@ int scsicam_bios_param (Disk *disk, /* SCSI disk */ struct buffer_head *bh; int ret_code; int size = disk->capacity; + unsigned long temp_cyl; if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024))) return -1; @@ -72,6 +73,11 @@ int scsicam_bios_param (Disk *disk, /* SCSI disk */ if (ret_code || ip[0] > 255 || ip[1] > 63) { ip[0] = 64; ip[1] = 32; + temp_cyl = size / (ip[0] * ip[1]); + if (temp_cyl > 65534) { + ip[0] = 255; + ip[1] = 63; + } ip[2] = size / (ip[0] * ip[1]); } diff --git a/fs/fat/file.c b/fs/fat/file.c index 3d3942050cc9..516781b3c880 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -324,8 +324,8 @@ int fat_file_write(struct inode *inode,struct file *filp,const char *buf,int cou #else if (count <= 0) return 0; #endif - if (filp->f_pos + count > 0x7FFFFFFFLL) { - count = 0x7FFFFFFFLL - filp->f_pos; + if (filp->f_pos + count > 0x7FFFFFFFL) { + count = 0x7FFFFFFFL - filp->f_pos; if (!count) return -EFBIG; } diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h index ea31d746d340..feb504a501e9 100644 --- a/include/asm-i386/irq.h +++ b/include/asm-i386/irq.h @@ -108,6 +108,17 @@ extern void enable_irq(unsigned int); "1:\tjmp 1f\n" \ "1:\toutb %al,$0x20\n\t" +/* do not modify the ISR nor the cache_A1 variable */ +#define MSGACK_SECOND(mask,nr) \ + "inb $0xA1,%al\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\tmovb $0x20,%al\n\t" \ + "outb %al,$0xA0\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\toutb %al,$0x20\n\t" + #define UNBLK_FIRST(mask) \ "inb $0x21,%al\n\t" \ "jmp 1f\n" \ @@ -307,34 +318,14 @@ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $-"#nr"-2\n\t" \ - SAVE_ALL \ - ENTER_KERNEL \ - ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ - "sti\n\t" \ - "movl %esp,%ebx\n\t" \ - "pushl %ebx\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ - "addl $8,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ - GET_PROCESSOR_ID \ - "btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ - "jmp ret_from_sys_call\n" \ -"\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ - ACK_##chip(mask,(nr&7)) \ + MSGACK_##chip(mask,(nr&7)) \ SMP_PROF_IPI_CNT \ "pushl $" #nr "\n\t" \ "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ "addl $4,%esp\n\t" \ "cli\n\t" \ - UNBLK_##chip(mask) \ RESTORE_MOST \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ diff --git a/include/linux/pci.h b/include/linux/pci.h index d9148fb47629..eb1472d416cd 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -546,8 +546,11 @@ #define PCI_DEVICE_ID_DATABOOK_87144 0xb106 #define PCI_VENDOR_ID_PLX 0x10b5 +#define PCI_DEVICE_ID_PLX_9050 0x9050 #define PCI_DEVICE_ID_PLX_9080 0x9080 +#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103 + #define PCI_VENDOR_ID_MADGE 0x10b6 #define PCI_DEVICE_ID_MADGE_MK2 0x0002 diff --git a/net/ipv4/ip_masq.c b/net/ipv4/ip_masq.c index 6c485e45842e..114397579376 100644 --- a/net/ipv4/ip_masq.c +++ b/net/ipv4/ip_masq.c @@ -1515,32 +1515,35 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) else { struct tcphdr *th; - skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), + if(len>=sizeof(struct tcphdr)) + { + skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), len - sizeof(struct tcphdr), 0); - tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb); + tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb); - /* Check if TCP FIN or RST */ - th = (struct tcphdr *)portptr; - if (th->fin) - { - ms->flags |= IP_MASQ_F_SAW_FIN_IN; - } - if (th->rst) - { - ms->flags |= IP_MASQ_F_SAW_RST; - } + /* Check if TCP FIN or RST */ + th = (struct tcphdr *)portptr; + if (th->fin) + { + ms->flags |= IP_MASQ_F_SAW_FIN_IN; + } + if (th->rst) + { + ms->flags |= IP_MASQ_F_SAW_RST; + } - /* Now set the timeouts */ - if (ms->flags & IP_MASQ_F_SAW_RST) - { - timeout = 1; - } - else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) - { - timeout = ip_masq_expire->tcp_fin_timeout; + /* Now set the timeouts */ + if (ms->flags & IP_MASQ_F_SAW_RST) + { + timeout = 1; + } + else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) + { + timeout = ip_masq_expire->tcp_fin_timeout; + } + else timeout = ip_masq_expire->tcp_timeout; } - else timeout = ip_masq_expire->tcp_timeout; - } + } ip_masq_set_expire(ms, timeout); ip_send_check(iph); #ifdef DEBUG_CONFIG_IP_MASQUERADE -- 2.39.5