diff -rc linux/arch/i386/kernel/entry.S linux-2.0.30.strip.iw/arch/i386/kernel/entry.S *** linux/arch/i386/kernel/entry.S Wed Dec 11 06:41:01 1996 --- linux-2.0.30.strip.iw/arch/i386/kernel/entry.S Sun Jun 29 23:50:43 1997 *************** *** 194,199 **** --- 194,200 ---- #define RESTORE_ALL \ + movl $-10,SYMBOL_NAME(serial_oe_last_interrupt); \ cmpw $(KERNEL_CS),CS(%esp); \ je 1f; \ GET_PROCESSOR_OFFSET(%edx) \ *************** *** 218,223 **** --- 219,225 ---- #else #define RESTORE_ALL \ + movl $-11,SYMBOL_NAME(serial_oe_last_interrupt); \ cmpw $(KERNEL_CS),CS(%esp); \ je 1f; \ movl SYMBOL_NAME(current_set),%eax; \ *************** *** 324,336 **** jne 2f 9: movl SYMBOL_NAME(bh_mask),%eax andl SYMBOL_NAME(bh_active),%eax jne handle_bottom_half movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are testl $(VM_MASK),%eax # different then jne 1f cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ? je 2f ! 1: sti orl $(IF_MASK),%eax # these just try to make sure andl $~NT_MASK,%eax # the program doesn't do anything movl %eax,EFLAGS(%esp) # stupid --- 326,340 ---- jne 2f 9: movl SYMBOL_NAME(bh_mask),%eax andl SYMBOL_NAME(bh_active),%eax + movl $-1,SYMBOL_NAME(serial_oe_last_interrupt) jne handle_bottom_half movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are testl $(VM_MASK),%eax # different then jne 1f cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ? je 2f ! 1: movl $-2,SYMBOL_NAME(serial_oe_last_interrupt) ! sti orl $(IF_MASK),%eax # these just try to make sure andl $~NT_MASK,%eax # the program doesn't do anything movl %eax,EFLAGS(%esp) # stupid Only in linux-2.0.30.strip.iw/arch/i386/kernel: entry.S.orig diff -rc linux/arch/i386/kernel/irq.c linux-2.0.30.strip.iw/arch/i386/kernel/irq.c *** linux/arch/i386/kernel/irq.c Mon Mar 17 14:58:59 1997 --- linux-2.0.30.strip.iw/arch/i386/kernel/irq.c Sun Jun 29 23:50:43 1997 *************** *** 32,37 **** --- 32,43 ---- #include #include + /* Global variables for the INTERRUPT_WATCHDOG code */ + volatile int serial_oe_last_line; + volatile char *serial_oe_last_file; + volatile char *serial_oe_last_base; + volatile int serial_oe_last_interrupt; + #define CR0_NE 32 static unsigned char cache_21 = 0xff; *************** *** 160,165 **** --- 166,182 ---- fast_IRQ14_interrupt, fast_IRQ15_interrupt }; + static void (*adaptive_interrupt[16])(void) = { + adaptive_IRQ0_interrupt, adaptive_IRQ1_interrupt, + adaptive_IRQ2_interrupt, adaptive_IRQ3_interrupt, + adaptive_IRQ4_interrupt, adaptive_IRQ5_interrupt, + adaptive_IRQ6_interrupt, adaptive_IRQ7_interrupt, + adaptive_IRQ8_interrupt, adaptive_IRQ9_interrupt, + adaptive_IRQ10_interrupt, adaptive_IRQ11_interrupt, + adaptive_IRQ12_interrupt, adaptive_IRQ13_interrupt, + adaptive_IRQ14_interrupt, adaptive_IRQ15_interrupt + }; + static void (*bad_interrupt[16])(void) = { bad_IRQ0_interrupt, bad_IRQ1_interrupt, bad_IRQ2_interrupt, bad_IRQ3_interrupt, *************** *** 234,240 **** continue; len += sprintf(buf+len, "%2d: %10u %c %s", i, kstat.interrupts[i], ! (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { len += sprintf(buf+len, ",%s %s", --- 251,258 ---- continue; len += sprintf(buf+len, "%2d: %10u %c %s", i, kstat.interrupts[i], ! (action->flags & SA_INTERRUPT) ? '+' : ! (action->flags & SA_ADAPTIVE ) ? '*' : ' ', action->name); for (action=action->next; action; action = action->next) { len += sprintf(buf+len, ",%s %s", *************** *** 393,398 **** --- 411,451 ---- add_interrupt_randomness(irq); } + /* + * do_adaptive_IRQ handles IRQ's that might occasionally want the fancy interrupt + * return stuff, but probably don't most of the time. The handler is also + * running with interrupts disabled unless it explicitly enables them later. + * This is declared to return a "long" to make certain that the result + * is returned as a 32-bit value in EAX, which the assembly glue in + * "include/asm/irq.h" will test with a "testl %eax,%eax" instruction. + */ + asmlinkage long do_adaptive_IRQ(int irq) + { + long retcode = FAST_RETURN; + struct irqaction * action = *(irq + irq_action); + int do_random = 0; + + #ifdef __SMP__ + /* IRQ 13 is allowed - that's a flush tlb */ + if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13) + panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id()); + #endif + + kstat.interrupts[irq]++; + #ifdef __SMP_PROF__ + int_count[smp_processor_id()][irq]++; + #endif + while (action) { + AdaptiveInterruptHandler *handler = (AdaptiveInterruptHandler*)(action->handler); + do_random |= action->flags; + retcode |= handler(irq, action->dev_id, NULL); + action = action->next; + } + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + return(retcode); + } + int setup_x86_irq(int irq, struct irqaction * new) { int shared = 0; *************** *** 406,412 **** return -EBUSY; /* Can't share interrupts unless both are same type */ ! if ((old->flags ^ new->flags) & SA_INTERRUPT) return -EBUSY; /* add new interrupt at end of irq queue */ --- 459,465 ---- return -EBUSY; /* Can't share interrupts unless both are same type */ ! if ((old->flags ^ new->flags) & (SA_INTERRUPT | SA_ADAPTIVE)) return -EBUSY; /* add new interrupt at end of irq queue */ *************** *** 427,432 **** --- 480,487 ---- if (!shared) { if (new->flags & SA_INTERRUPT) set_intr_gate(0x20+irq,fast_interrupt[irq]); + else if (new->flags & SA_ADAPTIVE) + set_intr_gate(0x20+irq,adaptive_interrupt[irq]); else set_intr_gate(0x20+irq,interrupt[irq]); unmask_irq(irq); Only in linux-2.0.30.strip.iw/arch/i386/kernel: irq.c.orig diff -rc linux/drivers/char/apm_bios.c linux-2.0.30.strip.iw/drivers/char/apm_bios.c *** linux/drivers/char/apm_bios.c Tue May 14 23:06:55 1996 --- linux-2.0.30.strip.iw/drivers/char/apm_bios.c Sun Jun 29 23:50:43 1997 *************** *** 617,623 **** --- 617,630 ---- return; save_flags(flags); + #define DO_SOMETHING_SILLY 0 + #if DO_SOMETHING_SILLY + /* + * This is bogus. get_cmos_time() takes up to one second to complete. + * You can't disable interrupts for a second + */ cli(); + #endif CURRENT_TIME = get_cmos_time() + clock_cmos_diff; restore_flags(flags); } Only in linux-2.0.30.strip.iw/drivers/char: apm_bios.c.orig diff -rc linux/drivers/char/serial.c linux-2.0.30.strip.iw/drivers/char/serial.c *** linux/drivers/char/serial.c Tue Apr 8 08:47:45 1997 --- linux-2.0.30.strip.iw/drivers/char/serial.c Sun Jun 29 23:50:44 1997 *************** *** 391,410 **** mark_bh(SERIAL_BH); } ! static _INLINE_ void receive_chars(struct async_struct *info, int *status) { struct tty_struct *tty = info->tty; unsigned char ch; int ignored = 0; do { ch = serial_inp(info, UART_RX); if (*status & info->ignore_status_mask) { if (++ignored > 100) break; goto ignore_char; } if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; tty->flip.count++; --- 391,438 ---- mark_bh(SERIAL_BH); } ! /* ! * dequeue_task_irq_off pulls a task off a task queue that it's already on ! * so it can be moved to another (more timely) task queue ! * Note 15th Oct 1995: ! * D'oh! ! * It appears that t_queue lists are not NULL terminated. ! * They are terminated by a special element that points to itself. ! * If you walk down the list expecting to get to a NULL ! * pointer, you'll end up in an infinite loop. ! */ ! static void dequeue_task_irq_off(struct tq_struct *the_element, struct tq_struct **tq) ! { ! while (*tq && *tq != (*tq)->next) ! { ! if (*tq == the_element) ! { ! *tq = (*tq)->next; ! the_element->sync = 0; ! return; ! } ! tq = &(*tq)->next; ! } ! } ! ! static _INLINE_ irq_return receive_chars(struct async_struct *info, int *status) { struct tty_struct *tty = info->tty; unsigned char ch; int ignored = 0; + int overrun = 0, charsread = 0; + irq_return retcode = FAST_RETURN; do { ch = serial_inp(info, UART_RX); + charsread++; if (*status & info->ignore_status_mask) { if (++ignored > 100) break; goto ignore_char; } + if (*status & UART_LSR_OE) overrun++; if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; tty->flip.count++; *************** *** 424,436 **** else *tty->flip.flag_buf_ptr++ = 0; *tty->flip.char_buf_ptr++ = ch; ignore_char: *status = serial_inp(info, UART_LSR) & info->read_status_mask; } while (*status & UART_LSR_DR); ! queue_task_irq_off(&tty->flip.tqueue, &tq_timer); #ifdef SERIAL_DEBUG_INTR printk("DR..."); #endif } static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) --- 452,543 ---- else *tty->flip.flag_buf_ptr++ = 0; *tty->flip.char_buf_ptr++ = ch; + + /* + * Stuart Cheshire's fast response hack: + * If we're running SLIP, STRIP, or PPP, then as soon as we + * see an end-of-packet character we trigger a full system call + * return from the interrupt handler instead of a low-overhead + * fast return, so that the packet is handled immediately, + * instead of waiting waiting for the next timer tick, which + * could take up to 10ms. + * + * e.g. If the one-way transmission time for a small ping + * packet over your ISDN modem is 12ms, then the round-trip + * ping time *should* be 24ms. Without this fast response hack + * the actual round-trip ping time would currently be 40ms + * -- almost twice as slow -- because of all the time wasted + * inside the kernel waiting for the next timer tick. + * + * If this were officially supported by the Linux kernel, + * then instead of having the end-of-packet characters + * hard-coded into the serial driver like this, there'd be + * an official API to specify the marker character that the + * serial driver should be looking for. e.g. for terminal + * dial-in, triggering a fast response every time a carriage + * return is seen would be the appropriate thing to do. + */ + if ((ch == 0x0D && tty->ldisc.num == N_STRIP) || + (ch == 0xC0 && tty->ldisc.num == N_SLIP) || + (ch == 0x7E && tty->ldisc.num == N_PPP)) retcode = SYSCALL_RETURN; ignore_char: *status = serial_inp(info, UART_LSR) & info->read_status_mask; } while (*status & UART_LSR_DR); ! ! /* ! * If there was no 'attention' character in the received data, the ! * flip.tqueue is put on the timer tq to deliver the data normally. ! * If there was an 'attention' character then the flip.tqueue is put ! * on the immediate tq to expedite the process (it may be up to 10ms ! * before the next timer tick, and we don't want to wait that long). ! */ ! if (retcode == FAST_RETURN) queue_task_irq_off(&tty->flip.tqueue, &tq_timer); ! else ! { ! #if 0 ! struct timeval tv; ! do_gettimeofday(&tv); ! printk("**** receive_chars: tq_immediate at %02d.%06d\n", ! tv.tv_sec % 100, tv.tv_usec); ! #endif ! /* ! * If the flip.tqueue is already on the timer tq, then ! * must remove it first before we put in on the immediate tq ! * It's a good thing interrupts are disabled here :-) ! */ ! if (tty->flip.tqueue.sync) dequeue_task_irq_off(&tty->flip.tqueue, &tq_timer); ! queue_task_irq_off(&tty->flip.tqueue, &tq_immediate); ! mark_bh(IMMEDIATE_BH); ! } ! #ifdef SERIAL_DEBUG_INTR printk("DR..."); #endif + + #if INTERRUPT_WATCHDOG + /* + * Normally receive_chars should read up to 8 characters at a time. + * (The serial chip interrupts when there are 8 characters in the FIFO.) + * If it reads more than 10, that indicates that the computer is being very slow + * servicing interrupts, and we may want to investigate what is going wrong. + * If the computer is so slow that a hardware overrun happens, that is very bad. + */ + if (overrun) + printk(KERN_NOTICE "Serial overrun:%5d %-11s %-11s %d\n", + serial_oe_last_line, + serial_oe_last_file, + serial_oe_last_base, + serial_oe_last_interrupt); + else if (charsread > 10) + printk(KERN_NOTICE "Serial read%3d:%5d %-11s %-11s %d\n", + charsread, + serial_oe_last_line, + serial_oe_last_file, + serial_oe_last_base, + serial_oe_last_interrupt); + #endif + + return(retcode); } static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) *************** *** 537,543 **** /* * This is the serial driver's generic interrupt routine */ ! static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { int status; struct async_struct * info; --- 644,650 ---- /* * This is the serial driver's generic interrupt routine */ ! static irq_return rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { int status; struct async_struct * info; *************** *** 545,550 **** --- 652,658 ---- struct async_struct *end_mark = 0; int first_multi = 0; struct rs_multiport_struct *multi; + irq_return retcode = FAST_RETURN; #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt(%d)...", irq); *************** *** 552,558 **** info = IRQ_ports[irq]; if (!info) ! return; multi = &rs_multiport[irq]; if (multi->port_monitor) --- 660,666 ---- info = IRQ_ports[irq]; if (!info) ! return(FAST_RETURN); multi = &rs_multiport[irq]; if (multi->port_monitor) *************** *** 574,580 **** printk("status = %x...", status); #endif if (status & UART_LSR_DR) ! receive_chars(info, &status); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); --- 682,688 ---- printk("status = %x...", status); #endif if (status & UART_LSR_DR) ! retcode |= receive_chars(info, &status); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); *************** *** 598,615 **** #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif } /* * This is the serial driver's interrupt routine for a single port */ ! static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { int status; int pass_counter = 0; int first_multi = 0; struct async_struct * info; struct rs_multiport_struct *multi; #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_single(%d)...", irq); --- 706,725 ---- #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif + return(retcode); } /* * This is the serial driver's interrupt routine for a single port */ ! static irq_return rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { int status; int pass_counter = 0; int first_multi = 0; struct async_struct * info; struct rs_multiport_struct *multi; + irq_return retcode = FAST_RETURN; #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_single(%d)...", irq); *************** *** 617,623 **** info = IRQ_ports[irq]; if (!info || !info->tty) ! return; multi = &rs_multiport[irq]; if (multi->port_monitor) --- 727,733 ---- info = IRQ_ports[irq]; if (!info || !info->tty) ! return(FAST_RETURN); multi = &rs_multiport[irq]; if (multi->port_monitor) *************** *** 629,635 **** printk("status = %x...", status); #endif if (status & UART_LSR_DR) ! receive_chars(info, &status); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); --- 739,745 ---- printk("status = %x...", status); #endif if (status & UART_LSR_DR) ! retcode |= receive_chars(info, &status); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); *************** *** 647,664 **** #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif } /* * This is the serial driver's for multiport boards */ ! static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) { int status; struct async_struct * info; int pass_counter = 0; int first_multi= 0; struct rs_multiport_struct *multi; #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_multi(%d)...", irq); --- 757,776 ---- #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif + return(retcode); } /* * This is the serial driver's for multiport boards */ ! static irq_return rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) { int status; struct async_struct * info; int pass_counter = 0; int first_multi= 0; struct rs_multiport_struct *multi; + irq_return retcode = FAST_RETURN; #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_multi(%d)...", irq); *************** *** 666,677 **** info = IRQ_ports[irq]; if (!info) ! return; multi = &rs_multiport[irq]; if (!multi->port1) { /* Should never happen */ printk("rs_interrupt_multi: NULL port1!\n"); ! return; } if (multi->port_monitor) first_multi = inb(multi->port_monitor); --- 778,789 ---- info = IRQ_ports[irq]; if (!info) ! return(FAST_RETURN); multi = &rs_multiport[irq]; if (!multi->port1) { /* Should never happen */ printk("rs_interrupt_multi: NULL port1!\n"); ! return(FAST_RETURN); } if (multi->port_monitor) first_multi = inb(multi->port_monitor); *************** *** 688,694 **** printk("status = %x...", status); #endif if (status & UART_LSR_DR) ! receive_chars(info, &status); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); --- 800,806 ---- printk("status = %x...", status); #endif if (status & UART_LSR_DR) ! retcode |= receive_chars(info, &status); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); *************** *** 728,733 **** --- 840,846 ---- #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif + return(retcode); } *************** *** 909,915 **** unsigned short ICP; unsigned long flags; int retval; ! void (*handler)(int, void *, struct pt_regs *); unsigned long page; page = get_free_page(GFP_KERNEL); --- 1022,1028 ---- unsigned short ICP; unsigned long flags; int retval; ! AdaptiveInterruptHandler *handler; unsigned long page; page = get_free_page(GFP_KERNEL); *************** *** 985,991 **** } else handler = rs_interrupt_single; ! retval = request_irq(info->irq, handler, IRQ_T(info), "serial", NULL); if (retval) { restore_flags(flags); --- 1098,1104 ---- } else handler = rs_interrupt_single; ! retval = request_adaptive_irq(info->irq, handler, IRQ_T(info), "serial", NULL); if (retval) { restore_flags(flags); *************** *** 1120,1126 **** !IRQ_ports[info->irq]->next_port)) { if (IRQ_ports[info->irq]) { free_irq(info->irq, NULL); ! retval = request_irq(info->irq, rs_interrupt_single, IRQ_T(info), "serial", NULL); if (retval) --- 1233,1239 ---- !IRQ_ports[info->irq]->next_port)) { if (IRQ_ports[info->irq]) { free_irq(info->irq, NULL); ! retval = request_adaptive_irq(info->irq, rs_interrupt_single, IRQ_T(info), "serial", NULL); if (retval) *************** *** 1291,1296 **** --- 1404,1427 ---- if (I_IGNBRK(info->tty)) { info->ignore_status_mask |= UART_LSR_BI; info->read_status_mask |= UART_LSR_BI; + #if 0 + /* + This is wrong. It does not ignore overruns. It ignores whatever *characters* + coincidentally happen to be read when the status register is also indicating + that an overrun has occurred. + + e.g. The serial chip has a 16 character FIFO, but occasionally the + kernel might disable interrupts for too long and cause an overrun: + + 20 characters arrive: ABCDEFGHIJKLMNOPQRST + The FIFO can only hold 16; four get lost: ABCDEFGHIJKLMNOP---- + The serial chip's overrun error bit gets set. + Because of this, the code here would ignore the *first* + character, and what gets delivered would be this: BCDEFGHIJKLMNOP + + So, an overrun not only loses some characters, but also causes another + unrelated character to get lost as well. This is obviously wrong. + */ /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). *************** *** 1301,1306 **** --- 1432,1438 ---- info->read_status_mask |= UART_LSR_OE | \ UART_LSR_PE | UART_LSR_FE; } + #endif } cli(); serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ *************** *** 1829,1835 **** struct rs_multiport_struct *multi; int was_multi, now_multi; int retval; ! void (*handler)(int, void *, struct pt_regs *); if (!suser()) return -EPERM; --- 1961,1967 ---- struct rs_multiport_struct *multi; int was_multi, now_multi; int retval; ! AdaptiveInterruptHandler *handler; if (!suser()) return -EPERM; *************** *** 1889,1895 **** else handler = rs_interrupt; ! retval = request_irq(info->irq, handler, IRQ_T(info), "serial", NULL); if (retval) { printk("Couldn't reallocate serial interrupt " --- 2021,2027 ---- else handler = rs_interrupt; ! retval = request_adaptive_irq(info->irq, handler, IRQ_T(info), "serial", NULL); if (retval) { printk("Couldn't reallocate serial interrupt " Only in linux-2.0.30.strip.iw/drivers/char: serial.c.orig diff -rc linux/drivers/net/net_init.c linux-2.0.30.strip.iw/drivers/net/net_init.c *** linux/drivers/net/net_init.c Wed Nov 6 04:39:42 1996 --- linux-2.0.30.strip.iw/drivers/net/net_init.c Sun Jun 29 23:52:00 1997 *************** *** 318,324 **** for (i = 0; i < MAX_ETH_CARDS; ++i) if (ethdev_index[i] == NULL) { sprintf(dev->name, "eth%d", i); ! printk("loading device '%s'...\n", dev->name); ethdev_index[i] = dev; break; } --- 318,324 ---- for (i = 0; i < MAX_ETH_CARDS; ++i) if (ethdev_index[i] == NULL) { sprintf(dev->name, "eth%d", i); ! printk(KERN_INFO "loading device '%s'...\n", dev->name); ethdev_index[i] = dev; break; } Only in linux-2.0.30.strip.iw/drivers/net: net_init.c.orig diff -rc linux/drivers/net/new_tunnel.c linux-2.0.30.strip.iw/drivers/net/new_tunnel.c *** linux/drivers/net/new_tunnel.c Tue Apr 8 08:47:46 1997 --- linux-2.0.30.strip.iw/drivers/net/new_tunnel.c Sun Jun 29 23:54:14 1997 *************** *** 161,167 **** * routing tables */ iph = (struct iphdr *) skb->data; ! if ((rt = ip_rt_route(iph->daddr, 0)) == NULL) { /* No route to host */ /* Where did the packet come from? */ --- 161,167 ---- * routing tables */ iph = (struct iphdr *) skb->data; ! if ((rt = ip_rt_route(iph->daddr, 0, skb->sk?skb->sk->bound_device:NULL)) == NULL) { /* No route to host */ /* Where did the packet come from? */ *************** *** 194,200 **** } ip_rt_put(rt); ! if ((rt = ip_rt_route(target, 0)) == NULL) { /* No route to host */ /* Where did the packet come from? */ --- 194,200 ---- } ip_rt_put(rt); ! if ((rt = ip_rt_route(target, 0, skb->sk?skb->sk->bound_device:NULL)) == NULL) { /* No route to host */ /* Where did the packet come from? */ Only in linux-2.0.30.strip.iw/drivers/net: new_tunnel.c.orig diff -rc linux/drivers/net/strip.c linux-2.0.30.strip.iw/drivers/net/strip.c *** linux/drivers/net/strip.c Sat Aug 17 11:19:26 1996 --- linux-2.0.30.strip.iw/drivers/net/strip.c Sun Jun 29 23:52:45 1997 *************** *** 14,66 **** * for kernel-based devices like TTY. It interfaces between a * raw TTY, and the kernel's INET protocol layers (via DDI). * ! * Version: @(#)strip.c 0.9.8 June 1996 * * Author: Stuart Cheshire * ! * Fixes: v0.9 12th Feb 1996. * New byte stuffing (2+6 run-length encoding) * New watchdog timer task * New Protocol key (SIP0) * ! * v0.9.1 3rd March 1996 * Changed to dynamic device allocation -- no more compile * time (or boot time) limit on the number of STRIP devices. * ! * v0.9.2 13th March 1996 * Uses arp cache lookups (but doesn't send arp packets yet) * ! * v0.9.3 17th April 1996 * Fixed bug where STR_ERROR flag was getting set unneccessarily * ! * v0.9.4 27th April 1996 * First attempt at using "&COMMAND" Starmode AT commands * ! * v0.9.5 29th May 1996 * First attempt at sending (unicast) ARP packets * ! * v0.9.6 5th June 1996 ! * Elliot put "message level" tags in every "printk" statement * ! * v0.9.7 13th June 1996 ! * Added support for the /proc fs (laik) * ! * v0.9.8 July 1996 ! * Added packet logging (Mema) ! */ ! ! /* ! * Undefine this symbol if you don't have PROC_NET_STRIP_STATUS ! * defined in include/linux/proc_fs.h */ ! #define DO_PROC_NET_STRIP_STATUS 1 ! ! /* ! * Define this symbol if you want to enable STRIP packet tracing. ! */ ! #define DO_PROC_NET_STRIP_TRACE 0 /************************************************************************/ --- 14,75 ---- * for kernel-based devices like TTY. It interfaces between a * raw TTY, and the kernel's INET protocol layers (via DDI). * ! * Version: @(#)strip.c 1.2 February 1997 * * Author: Stuart Cheshire * ! * Fixes: v0.9 12th Feb 1996 (SC) * New byte stuffing (2+6 run-length encoding) * New watchdog timer task * New Protocol key (SIP0) * ! * v0.9.1 3rd March 1996 (SC) * Changed to dynamic device allocation -- no more compile * time (or boot time) limit on the number of STRIP devices. * ! * v0.9.2 13th March 1996 (SC) * Uses arp cache lookups (but doesn't send arp packets yet) * ! * v0.9.3 17th April 1996 (SC) * Fixed bug where STR_ERROR flag was getting set unneccessarily + * (causing otherwise good packets to be unneccessarily dropped) * ! * v0.9.4 27th April 1996 (SC) * First attempt at using "&COMMAND" Starmode AT commands * ! * v0.9.5 29th May 1996 (SC) * First attempt at sending (unicast) ARP packets * ! * v0.9.6 5th June 1996 (Elliot) ! * Put "message level" tags in every "printk" statement * ! * v0.9.7 13th June 1996 (laik) ! * Added support for the /proc fs * ! * v0.9.8 July 1996 (Mema) ! * Added packet logging ! * ! * v1.0 November 1996 (SC) ! * Fixed (severe) memory leaks in the /proc fs code ! * Fixed race conditions in the logging code ! * ! * v1.1 January 1997 (SC) ! * Deleted packet logging (use tcpdump instead) ! * Added support for Metricom Firmware v204 features ! * (like message checksums) ! * ! * v1.2 January 1997 (SC) ! * Put portables list back in */ ! #ifdef MODULE ! static const char StripVersion[] = "1.2-STUART.CHESHIRE-MODULAR"; ! #else ! static const char StripVersion[] = "1.2-STUART.CHESHIRE"; ! #endif ! #define TICKLE_TIMERS 0 ! #define EXT_COUNTERS 1 /************************************************************************/ *************** *** 146,158 **** __u8 c[24]; } MetricomAddressString; /* ! * Note: A Metricom packet looks like this: *
* ! * eg. *0000-1234*SIP0 ! * A STRIP_Header is never really sent over the radio, but making a dummy header ! * for internal use within the kernel that looks like an Ethernet header makes ! * certain other software happier. For example, tcpdump already understands ! * Ethernet headers. */ typedef struct --- 155,173 ---- __u8 c[24]; } MetricomAddressString; + /* Encapsulation can expand packet of size x to 65/64x + 1 + * Sent packet looks like "*
*" + * 1 1 1-18 1 4 ? 1 + * eg. *0000-1234*SIP0 + * We allow 31 bytes for the stars, the key, the address and the s + */ + #define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) + /* ! * A STRIP_Header is never really sent over the radio, but making a dummy ! * header for internal use within the kernel that looks like an Ethernet ! * header makes certain other software happier. For example, tcpdump ! * already understands Ethernet headers. */ typedef struct *************** *** 162,244 **** unsigned short protocol; /* The protocol type, using Ethernet codes */ } STRIP_Header; - typedef struct GeographicLocation - { - char s[18]; - } GeographicLocation; - - typedef enum { - NodeValid = 0x1, - NodeHasWAN = 0x2, - NodeIsRouter = 0x4 - } NodeType; - - typedef struct MetricomNode - { - NodeType type; /* Some flags about the type of node */ - GeographicLocation gl; /* The location of the node. */ - MetricomAddress addr; /* The metricom address of this node */ - int poll_latency; /* The latency to poll that node ? */ - int rssi; /* The Receiver Signal Strength Indicator */ - struct MetricomNode *next; /* The next node */ - } MetricomNode; - - enum { FALSE = 0, TRUE = 1 }; - - /* - * Holds the packet signature for an IP packet. - */ typedef struct { ! IPaddr src; ! /* Data is stored in the following field in network byte order. */ ! __u16 id; ! } IPSignature; ! /* ! * Holds the packet signature for an ARP packet. ! */ typedef struct { ! IPaddr src; ! /* Data is stored in the following field in network byte order. */ ! __u16 op; ! } ARPSignature; ! ! /* ! * Holds the signature of a packet. ! */ ! typedef union ! { ! IPSignature ip_sig; ! ARPSignature arp_sig; ! __u8 print_sig[6]; ! } PacketSignature; ! ! typedef enum { ! EntrySend = 0, ! EntryReceive = 1 ! } LogEntry; ! ! /* Structure for Packet Logging */ ! typedef struct stripLog ! { ! LogEntry entry_type; ! u_long seqNum; ! int packet_type; ! PacketSignature sig; ! MetricomAddress src; ! MetricomAddress dest; ! struct timeval timeStamp; ! u_long rawSize; ! u_long stripSize; ! u_long slipSize; ! u_long valid; ! } StripLog; ! ! #define ENTRY_TYPE_TO_STRING(X) ((X) ? "r" : "s") ! #define BOOLEAN_TO_STRING(X) ((X) ? "true" : "false") /* * Holds the radio's firmware version. --- 177,196 ---- unsigned short protocol; /* The protocol type, using Ethernet codes */ } STRIP_Header; typedef struct { ! char c[60]; ! } MetricomNode; ! #define NODE_TABLE_SIZE 32 typedef struct { ! struct timeval timestamp; ! int num_nodes; ! MetricomNode node[NODE_TABLE_SIZE]; ! } MetricomNodeTable; ! enum { FALSE = 0, TRUE = 1 }; /* * Holds the radio's firmware version. *************** *** 246,252 **** typedef struct { char c[50]; ! } MetricomFirmwareVersion; /* * Holds the radio's serial number. --- 198,204 ---- typedef struct { char c[50]; ! } FirmwareVersion; /* * Holds the radio's serial number. *************** *** 254,260 **** typedef struct { char c[18]; ! } MetricomSerialNumber; /* * Holds the radio's battery voltage. --- 206,212 ---- typedef struct { char c[18]; ! } SerialNumber; /* * Holds the radio's battery voltage. *************** *** 262,268 **** typedef struct { char c[11]; ! } MetricomBatteryVoltage; struct strip { --- 214,232 ---- typedef struct { char c[11]; ! } BatteryVoltage; ! ! typedef struct ! { ! char c[8]; ! } char8; ! ! enum ! { ! NoStructure = 0, /* Really old firmware */ ! StructuredMessages = 1, /* Parsable AT response msgs */ ! ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ ! } FirmwareLevel; struct strip { *************** *** 292,297 **** --- 256,280 ---- unsigned long tx_dropped; /* When MTU change */ unsigned long rx_over_errors; /* Frame bigger then STRIP buf. */ + unsigned long pps_timer; /* Timer to determine pps */ + unsigned long rx_pps_count; /* Counter to determine pps */ + unsigned long tx_pps_count; /* Counter to determine pps */ + unsigned long sx_pps_count; /* Counter to determine pps */ + unsigned long rx_average_pps; /* rx packets per second * 8 */ + unsigned long tx_average_pps; /* tx packets per second * 8 */ + unsigned long sx_average_pps; /* sent packets per second * 8 */ + + #ifdef EXT_COUNTERS + unsigned long rx_bytes; /* total received bytes */ + unsigned long tx_bytes; /* total received bytes */ + unsigned long rx_rbytes; /* bytes thru radio i/f */ + unsigned long tx_rbytes; /* bytes thru radio i/f */ + unsigned long rx_sbytes; /* tot bytes thru serial i/f */ + unsigned long tx_sbytes; /* tot bytes thru serial i/f */ + unsigned long rx_ebytes; /* tot stat/err bytes */ + unsigned long tx_ebytes; /* tot stat/err bytes */ + #endif + /* * Internal variables. */ *************** *** 300,351 **** struct strip **referrer; /* The pointer that points to us*/ int discard; /* Set if serial error */ int working; /* Is radio working correctly? */ ! int structured_messages; /* Parsable AT response msgs? */ int mtu; /* Our mtu (to spot changes!) */ long watchdog_doprobe; /* Next time to test the radio */ long watchdog_doreset; /* Time to do next reset */ long gratuitous_arp; /* Time to send next ARP refresh*/ long arp_interval; /* Next ARP interval */ struct timer_list idle_timer; /* For periodic wakeup calls */ ! MetricomNode *neighbor_list; /* The list of neighbor nodes */ ! int neighbor_list_locked; /* Indicates the list is locked */ ! MetricomFirmwareVersion firmware_version; /* The radio's firmware version */ ! MetricomSerialNumber serial_number; /* The radio's serial number */ ! MetricomBatteryVoltage battery_voltage; /* The radio's battery voltage */ /* * Other useful structures. */ struct tty_struct *tty; /* ptr to TTY structure */ ! char if_name[8]; /* Dynamically generated name */ struct device dev; /* Our device structure */ /* ! * Packet Logging Structures. */ ! u_long num_sent; ! u_long num_received; ! ! int next_entry; /* The index of the oldest packet; */ ! /* Also the next to be logged. */ ! StripLog packetLog[610]; }; /************************************************************************/ /* Constants */ ! #ifdef MODULE ! static const char StripVersion[] = "0.9.8-STUART.CHESHIRE-MODULAR"; ! #else ! static const char StripVersion[] = "0.9.8-STUART.CHESHIRE"; ! #endif ! ! static const char TickleString1[] = "***&COMMAND*ATS305?\r"; ! static const char TickleString2[] = "***&COMMAND*ATS305?\r\r" ! "*&COMMAND*ATS300?\r\r*&COMMAND*ATS325?\r\r*&COMMAND*AT~I2 nn\r\r"; static const char hextable[16] = "0123456789ABCDEF"; --- 283,424 ---- struct strip **referrer; /* The pointer that points to us*/ int discard; /* Set if serial error */ int working; /* Is radio working correctly? */ ! int firmware_level; /* Message structuring level */ ! int next_command; /* Next periodic command */ int mtu; /* Our mtu (to spot changes!) */ long watchdog_doprobe; /* Next time to test the radio */ long watchdog_doreset; /* Time to do next reset */ long gratuitous_arp; /* Time to send next ARP refresh*/ long arp_interval; /* Next ARP interval */ struct timer_list idle_timer; /* For periodic wakeup calls */ ! MetricomAddress true_dev_addr; /* True address of radio */ ! int manual_dev_addr; /* Hack: See note below */ ! ! FirmwareVersion firmware_version; /* The radio's firmware version */ ! SerialNumber serial_number; /* The radio's serial number */ ! BatteryVoltage battery_voltage; /* The radio's battery voltage */ /* * Other useful structures. */ struct tty_struct *tty; /* ptr to TTY structure */ ! char8 if_name; /* Dynamically generated name */ struct device dev; /* Our device structure */ /* ! * Neighbour radio records */ ! MetricomNodeTable portables; ! MetricomNodeTable poletops; }; + /* + * Note: manual_dev_addr hack + * + * It is not possible to change the hardware address of a Metricom radio, + * or to send packets with a user-specified hardware source address, thus + * trying to manually set a hardware source address is a questionable + * thing to do. However, if the user *does* manually set the hardware + * source address of a STRIP interface, then the kernel will believe it, + * and use it in certain places. For example, the hardware address listed + * by ifconfig will be the manual address, not the true one. + * (Both addresses are listed in /proc/net/strip.) + * Also, ARP packets will be sent out giving the user-specified address as + * the source address, not the real address. This is dangerous, because + * it means you won't receive any replies -- the ARP replies will go to + * the specified address, which will be some other radio. The case where + * this is useful is when that other radio is also connected to the same + * machine. This allows you to connect a pair of radios to one machine, + * and to use one exclusively for inbound traffic, and the other + * exclusively for outbound traffic. Pretty neat, huh? + * + * Here's the full procedure to set this up: + * + * 1. "slattach" two interfaces, e.g. st0 for outgoing packets, + * and st1 for incoming packets + * + * 2. "ifconfig" st0 (outbound radio) to have the hardware address + * which is the real hardware address of st1 (inbound radio). + * Now when it sends out packets, it will masquerade as st1, and + * replies will be sent to that radio, which is exactly what we want. + * + * 3. Set the route table entry ("route add default ..." or + * "route add -net ...", as appropriate) to send packets via the st0 + * interface (outbound radio). Do not add any route which sends packets + * out via the st1 interface -- that radio is for inbound traffic only. + * + * 4. "ifconfig" st1 (inbound radio) to have hardware address zero. + * This tells the STRIP driver to "shut down" that interface and not + * send any packets through it. In particular, it stops sending the + * periodic gratuitous ARP packets that a STRIP interface normally sends. + * Also, when packets arrive on that interface, it will search the + * interface list to see if there is another interface who's manual + * hardware address matches its own real address (i.e. st0 in this + * example) and if so it will transfer ownership of the skbuff to + * that interface, so that it looks to the kernel as if the packet + * arrived on that interface. This is necessary because when the + * kernel sends an ARP packet on st0, it expects to get a reply on + * st0, and if it sees the reply come from st1 then it will ignore + * it (to be accurate, it puts the entry in the ARP table, but + * labelled in such a way that st0 can't use it). + * + * Thanks to Petros Maniatis for coming up with the idea of splitting + * inbound and outbound traffic between two interfaces, which turned + * out to be really easy to implement, even if it is a bit of a hack. + * + * Having set a manual address on an interface, you can restore it + * to automatic operation (where the address is automatically kept + * consistent with the real address of the radio) by setting a manual + * address of all ones, e.g. "ifconfig st0 hw strip FFFFFFFFFFFF" + * This 'turns off' manual override mode for the device address. + * + * Note: The IEEE 802 headers reported in tcpdump will show the *real* + * radio addresses the packets were sent and received from, so that you + * can see what is really going on with packets, and which interfaces + * they are really going through. + */ + /************************************************************************/ /* Constants */ ! /* ! * CommandString1 works on all radios ! * Other CommandStrings are only used with firmware that provides structured responses. ! * ! * ats319=1 Enables Info message for node additions and deletions ! * ats319=2 Enables Info message for a new best node ! * ats319=4 Enables checksums ! * ats319=8 Enables ACK messages ! */ ! ! static const int MaxCommandStringLength = 32; ! static const int CompatibilityCommand = 1; ! ! static const char CommandString0[] = "*&COMMAND*ATS319=7"; /* Turn on checksums & info messages */ ! static const char CommandString1[] = "*&COMMAND*ATS305?"; /* Query radio name */ ! static const char CommandString2[] = "*&COMMAND*ATS325?"; /* Query battery voltage */ ! static const char CommandString3[] = "*&COMMAND*ATS300?"; /* Query version information */ ! static const char CommandString4[] = "*&COMMAND*ATS311?"; /* Query poletop list */ ! static const char CommandString5[] = "*&COMMAND*AT~LA"; /* Query portables list */ ! typedef struct { const char *string; long length; } StringDescriptor; ! ! static const StringDescriptor CommandString[] = ! { ! { CommandString0, sizeof(CommandString0)-1 }, ! { CommandString1, sizeof(CommandString1)-1 }, ! { CommandString2, sizeof(CommandString2)-1 }, ! { CommandString3, sizeof(CommandString3)-1 }, ! { CommandString4, sizeof(CommandString4)-1 }, ! { CommandString5, sizeof(CommandString5)-1 } ! }; ! ! #define GOT_ALL_RADIO_INFO(S) \ ! ((S)->firmware_version.c[0] && \ ! (S)->battery_voltage.c[0] && \ ! memcmp(&(S)->true_dev_addr, zero_address.c, sizeof(zero_address))) static const char hextable[16] = "0123456789ABCDEF"; *************** *** 354,379 **** static const MetricomKey SIP0Key = { { "SIP0" } }; static const MetricomKey ARP0Key = { { "ARP0" } }; - static const MetricomKey ERR_Key = { { "ERR_" } }; static const MetricomKey ATR_Key = { { "ATR " } }; static const long MaxARPInterval = 60 * HZ; /* One minute */ /* ! * Maximum Starmode packet length (including starmode address) is 1183 bytes. ! * Allowing 32 bytes for header, and 65/64 expansion for STRIP encoding, ! * that translates to a maximum payload MTU of 1132. ! */ ! static const unsigned short MAX_STRIP_MTU = 1132; ! static const unsigned short DEFAULT_STRIP_MTU = 1024; static const int STRIP_MAGIC = 0x5303; static const long LongTime = 0x7FFFFFFF; - static const int STRIP_NODE_LEN = 64; - static const char STRIP_PORTABLE_CHAR = 'P'; - static const char STRIP_ROUTER_CHAR = 'r'; - static const int STRIP_PROC_BUFFER_SIZE = 4096; - static const int STRIP_LOG_INT_SIZE = 10; /************************************************************************/ /* Global variables */ --- 427,453 ---- static const MetricomKey SIP0Key = { { "SIP0" } }; static const MetricomKey ARP0Key = { { "ARP0" } }; static const MetricomKey ATR_Key = { { "ATR " } }; + static const MetricomKey ACK_Key = { { "ACK_" } }; + static const MetricomKey INF_Key = { { "INF_" } }; + static const MetricomKey ERR_Key = { { "ERR_" } }; static const long MaxARPInterval = 60 * HZ; /* One minute */ /* ! * Maximum Starmode packet length is 1183 bytes. Allowing 4 bytes for ! * protocol key, 4 bytes for checksum, one byte for CR, and 65/64 expansion ! * for STRIP encoding, that translates to a maximum payload MTU of 1155. ! * Note: A standard NFS 1K data packet is a total of 0x480 (1152) bytes ! * long, including IP header, UDP header, and NFS header. Setting the STRIP ! * MTU to 1152 allows us to send default sized NFS packets without fragmentation. ! */ ! static const unsigned short MAX_SEND_MTU = 1152; ! static const unsigned short MAX_RECV_MTU = 1500; /* Hoping for Ethernet sized packets in the future! */ ! static const unsigned short DEFAULT_STRIP_MTU = 1152; static const int STRIP_MAGIC = 0x5303; static const long LongTime = 0x7FFFFFFF; /************************************************************************/ /* Global variables */ *************** *** 384,393 **** --- 458,475 ---- /************************************************************************/ /* Macros */ + /* Returns TRUE if text T begins with prefix P */ + #define has_prefix(T,P) (!strncmp((T), (P), sizeof(P)-1)) + + /* Returns TRUE if text T of length L is equal to string S */ + #define text_equal(T,L,S) (((L) == sizeof(S)-1) && !strncmp((T), (S), sizeof(S)-1)) + #define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' : \ (X)>='a' && (X)<='f' ? (X)-'a'+10 : \ (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 ) + #define READHEX16(X) ((__u16)(READHEX(X))) + #define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0) #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) *************** *** 395,411 **** #define ELEMENTS_OF(X) (sizeof(X) / sizeof((X)[0])) #define ARRAY_END(X) (&((X)[ELEMENTS_OF(X)])) - /* Encapsulation can expand packet of size x to 65/64x + 1 */ - /* Sent packet looks like "*
*" */ - /* 1 1-18 1 4 ? 1 */ - /* We allow 31 bytes for the stars, the key, the address and the */ - #define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) - - #define IS_RADIO_ADDRESS(p) ( \ - isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ - (p)[4] == '-' && \ - isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) - #define JIFFIE_TO_SEC(X) ((X) / HZ) --- 477,482 ---- *************** *** 605,611 **** } /* else, we only have one so far, so switch to Stuff_Diff code */ code = Stuff_Diff; ! /* and fall through to Stuff_Diff case below */ /* Stuff_Diff: We have at least two *different* bytes encoded */ case Stuff_Diff: --- 676,690 ---- } /* else, we only have one so far, so switch to Stuff_Diff code */ code = Stuff_Diff; ! /* and fall through to Stuff_Diff case below ! * Note cunning cleverness here: case Stuff_Diff compares ! * the current character with the previous two to see if it ! * has a run of three the same. Won't this be an error if ! * there aren't two previous characters stored to compare with? ! * No. Because we know the current character is *not* the same ! * as the previous one, the first test below will necessarily ! * fail and the send half of the "if" won't be executed. ! */ /* Stuff_Diff: We have at least two *different* bytes encoded */ case Stuff_Diff: *************** *** 639,648 **** src++; /* Consume the byte */ break; } ! if (count == Stuff_MaxCount) ! { ! StuffData_FinishBlock(code + count); ! } } if (code == Stuff_NoCode) { --- 718,727 ---- src++; /* Consume the byte */ break; } ! if (count == Stuff_MaxCount) ! { ! StuffData_FinishBlock(code + count); ! } } if (code == Stuff_NoCode) { *************** *** 758,771 **** * Convert a string to a Metricom Address. */ ! static void string_to_radio_address(MetricomAddress *addr, __u8 *p) { addr->c[0] = 0; addr->c[1] = 0; addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); } /* --- 837,857 ---- * Convert a string to a Metricom Address. */ ! #define IS_RADIO_ADDRESS(p) ( \ ! isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ ! (p)[4] == '-' && \ ! isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) ! ! static int string_to_radio_address(MetricomAddress *addr, __u8 *p) { + if (!IS_RADIO_ADDRESS(p)) return(1); addr->c[0] = 0; addr->c[1] = 0; addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); + return(0); } /* *************** *** 780,798 **** /* * Note: Must make sure sx_size is big enough to receive a stuffed ! * MAX_STRIP_MTU packet. Additionally, we also want to ensure that it's * big enough to receive a large radio neighbour list (currently 4K). */ static int allocate_buffers(struct strip *strip_info) { struct device *dev = &strip_info->dev; ! int stuffedlen = STRIP_ENCAP_SIZE(dev->mtu); ! int sx_size = MAX(stuffedlen, 4096); ! int tx_size = stuffedlen + sizeof(TickleString2); ! __u8 *r = kmalloc(MAX_STRIP_MTU, GFP_ATOMIC); ! __u8 *s = kmalloc(sx_size, GFP_ATOMIC); ! __u8 *t = kmalloc(tx_size, GFP_ATOMIC); if (r && s && t) { strip_info->rx_buff = r; --- 866,883 ---- /* * Note: Must make sure sx_size is big enough to receive a stuffed ! * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's * big enough to receive a large radio neighbour list (currently 4K). */ static int allocate_buffers(struct strip *strip_info) { struct device *dev = &strip_info->dev; ! int sx_size = MAX(STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096); ! int tx_size = STRIP_ENCAP_SIZE(dev->mtu) + MaxCommandStringLength; ! __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC); ! __u8 *s = kmalloc(sx_size, GFP_ATOMIC); ! __u8 *t = kmalloc(tx_size, GFP_ATOMIC); if (r && s && t) { strip_info->rx_buff = r; *************** *** 824,833 **** unsigned char *otbuff = strip_info->tx_buff; InterruptStatus intstat; ! if (dev->mtu > MAX_STRIP_MTU) { printk(KERN_ERR "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", ! strip_info->dev.name, MAX_STRIP_MTU); dev->mtu = old_mtu; return; } --- 909,918 ---- unsigned char *otbuff = strip_info->tx_buff; InterruptStatus intstat; ! if (dev->mtu > MAX_SEND_MTU) { printk(KERN_ERR "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", ! strip_info->dev.name, MAX_SEND_MTU); dev->mtu = old_mtu; return; } *************** *** 856,864 **** memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count); else { ! strip_info->sx_count = 0; strip_info->rx_over_errors++; - strip_info->discard = 1; } } --- 941,948 ---- memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count); else { ! strip_info->discard = strip_info->sx_count; strip_info->rx_over_errors++; } } *************** *** 889,895 **** /* * Set the time to go off in one second. */ ! strip_info->idle_timer.expires = jiffies + HZ; add_timer(&strip_info->idle_timer); if (!clear_bit(0, (void *)&strip_info->dev.tbusy)) printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", --- 973,979 ---- /* * Set the time to go off in one second. */ ! strip_info->idle_timer.expires = jiffies + 1*HZ; add_timer(&strip_info->idle_timer); if (!clear_bit(0, (void *)&strip_info->dev.tbusy)) printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", *************** *** 900,907 **** /************************************************************************/ /* Callback routines for exporting information through /proc */ - #if DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE - /* * This function updates the total amount of data printed so far. It then * determines if the amount of data printed into a buffer has reached the --- 984,989 ---- *************** *** 912,940 **** */ static int shift_buffer(char *buffer, int requested_offset, int requested_len, ! int *total, int *slop, char **buf) { int printed; /* printk(KERN_DEBUG "shift: buffer: %d o: %d l: %d t: %d buf: %d\n", ! (int) buffer, requested_offset, requested_len, *total, ! (int) *buf); */ printed = *buf - buffer; if (*total + printed <= requested_offset) { ! *total += printed; ! *buf = buffer; } else { ! if (*total < requested_offset) { ! *slop = requested_offset - *total; ! } ! *total = requested_offset + printed - *slop; } if (*total > requested_offset + requested_len) { ! return 1; } else { ! return 0; } } --- 994,1022 ---- */ static int shift_buffer(char *buffer, int requested_offset, int requested_len, ! int *total, int *slop, char **buf) { int printed; /* printk(KERN_DEBUG "shift: buffer: %d o: %d l: %d t: %d buf: %d\n", ! (int) buffer, requested_offset, requested_len, *total, ! (int) *buf); */ printed = *buf - buffer; if (*total + printed <= requested_offset) { ! *total += printed; ! *buf = buffer; } else { ! if (*total < requested_offset) { ! *slop = requested_offset - *total; ! } ! *total = requested_offset + printed - *slop; } if (*total > requested_offset + requested_len) { ! return 1; } else { ! return 0; } } *************** *** 945,956 **** */ static int calc_start_len(char *buffer, char **start, int requested_offset, ! int requested_len, int total, char *buf) { int return_len, buffer_len; buffer_len = buf - buffer; ! if (buffer_len >= STRIP_PROC_BUFFER_SIZE - 1) { printk(KERN_ERR "STRIP: exceeded /proc buffer size\n"); } --- 1027,1038 ---- */ static int calc_start_len(char *buffer, char **start, int requested_offset, ! int requested_len, int total, char *buf) { int return_len, buffer_len; buffer_len = buf - buffer; ! if (buffer_len >= 4095) { printk(KERN_ERR "STRIP: exceeded /proc buffer size\n"); } *************** *** 960,979 **** */ return_len = total - requested_offset; if (return_len < 0) { ! return_len = 0; } *start = buf - return_len; if (return_len > requested_len) { ! return_len = requested_len; } /* printk(KERN_DEBUG "return_len: %d\n", return_len); */ return return_len; } - #endif DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE - - #if DO_PROC_NET_STRIP_STATUS - /* * If the time is in the near future, time_delta prints the number of * seconds to go into the buffer and returns the address of the buffer. --- 1042,1057 ---- */ return_len = total - requested_offset; if (return_len < 0) { ! return_len = 0; } *start = buf - return_len; if (return_len > requested_len) { ! return_len = requested_len; } /* printk(KERN_DEBUG "return_len: %d\n", return_len); */ return return_len; } /* * If the time is in the near future, time_delta prints the number of * seconds to go into the buffer and returns the address of the buffer. *************** *** 991,1527 **** return(buffer); } ! /* ! * This function prints radio status information into the specified ! * buffer. ! */ ! static int ! sprintf_status_info(char *buffer, struct strip *strip_info) ! { ! char temp_buffer[32]; ! MetricomAddressString addr_string; ! char *buf; ! ! buf = buffer; ! buf += sprintf(buf, "Interface name\t\t%s\n", strip_info->if_name); ! buf += sprintf(buf, " Radio working:\t\t%s\n", ! strip_info->working && ! (long)jiffies - strip_info->watchdog_doreset < 0 ? "Yes" : "No"); ! (void) radio_address_to_string((MetricomAddress *) ! &strip_info->dev.dev_addr, ! &addr_string); ! buf += sprintf(buf, " Device address:\t%s\n", addr_string.c); ! buf += sprintf(buf, " Firmware version:\t%s\n", ! !strip_info->working ? "Unknown" : ! !strip_info->structured_messages ? "Should be upgraded" : ! strip_info->firmware_version.c); ! buf += sprintf(buf, " Serial number:\t\t%s\n", strip_info->serial_number.c); ! buf += sprintf(buf, " Battery voltage:\t%s\n", strip_info->battery_voltage.c); ! buf += sprintf(buf, " Transmit queue (bytes):%d\n", strip_info->tx_left); ! buf += sprintf(buf, " Next watchdog probe:\t%s\n", ! time_delta(temp_buffer, strip_info->watchdog_doprobe)); ! buf += sprintf(buf, " Next watchdog reset:\t%s\n", ! time_delta(temp_buffer, strip_info->watchdog_doreset)); ! buf += sprintf(buf, " Next gratuitous ARP:\t%s\n", ! time_delta(temp_buffer, strip_info->gratuitous_arp)); ! buf += sprintf(buf, " Next ARP interval:\t%ld seconds\n", ! JIFFIE_TO_SEC(strip_info->arp_interval)); ! return buf - buffer; ! } ! ! static int ! sprintf_portables(char *buffer, struct strip *strip_info) ! { ! ! MetricomAddressString addr_string; ! MetricomNode *node; ! char *buf; ! ! buf = buffer; ! buf += sprintf(buf, " portables: name\t\tpoll_latency\tsignal strength\n"); ! for (node = strip_info->neighbor_list; node != NULL; ! node = node->next) { ! if (!(node->type & NodeValid)) { ! break; ! } ! if (node->type & NodeHasWAN) { ! continue; ! } ! (void) radio_address_to_string(&node->addr, &addr_string); ! buf += sprintf(buf, " %s\t\t\t\t%d\t\t%d\n", ! addr_string.c, node->poll_latency, node->rssi); ! } ! return buf - buffer; ! } ! ! static int ! sprintf_poletops(char *buffer, struct strip *strip_info) { ! MetricomNode *node; ! char *buf; ! ! buf = buffer; ! buf += sprintf(buf, " poletops: GPS\t\t\tpoll_latency\tsignal strength\n"); ! for (node = strip_info->neighbor_list; ! node != NULL; node = node->next) { ! if (!(node->type & NodeValid)) { ! break; ! } ! if (!(node->type & NodeHasWAN)) { ! continue; ! } ! buf += sprintf(buf, " %s\t\t\t%d\t\t%d\n", ! node->gl.s, node->poll_latency, node->rssi); ! } ! return buf - buffer; } /* ! * This function is exports status information from the STRIP driver through ! * the /proc file system. /proc filesystem should be fixed: ! * 1) slow (sprintfs here, a memory copy in the proc that calls this one) ! * 2) length of buffer not passed ! * 3) dummy isn't client data set when the callback was registered ! * 4) poorly documented (this function is called until the requested amount ! * of data is returned, buffer is only 4K long, dummy is the permissions ! * of the file (?), the proc_dir_entry passed to proc_net_register must ! * be kmalloc-ed) ! */ ! ! static int ! strip_get_status_info(char *buffer, char **start, off_t requested_offset, ! int requested_len, int dummy) ! { ! char *buf; ! int total = 0, slop = 0, len_exceeded; ! InterruptStatus i_status; ! struct strip *strip_info; ! ! buf = buffer; ! buf += sprintf(buf, "strip_version: %s\n", StripVersion); ! ! i_status = DisableInterrupts(); ! strip_info = struct_strip_list; ! RestoreInterrupts(i_status); ! ! while (strip_info != NULL) { ! i_status = DisableInterrupts(); ! buf += sprintf_status_info(buf, strip_info); ! RestoreInterrupts(i_status); ! len_exceeded = shift_buffer(buffer, requested_offset, requested_len, ! &total, &slop, &buf); ! if (len_exceeded) { ! goto done; ! } ! strip_info->neighbor_list_locked = TRUE; ! buf += sprintf_portables(buf, strip_info); ! strip_info->neighbor_list_locked = FALSE; ! len_exceeded = shift_buffer(buffer, requested_offset, requested_len, ! &total, &slop, &buf); ! if (len_exceeded) { ! goto done; ! } ! strip_info->neighbor_list_locked = TRUE; ! buf += sprintf_poletops(buf, strip_info); ! strip_info->neighbor_list_locked = FALSE; ! len_exceeded = shift_buffer(buffer, requested_offset, requested_len, ! &total, &slop, &buf); ! if (len_exceeded) { ! goto done; ! } ! strip_info = strip_info->next; ! } ! done: ! return calc_start_len(buffer, start, requested_offset, requested_len, ! total, buf); ! } ! ! #endif DO_PROC_NET_STRIP_STATUS ! ! #if DO_PROC_NET_STRIP_TRACE ! ! /* ! * Convert an Ethernet protocol to a string ! * Returns the number of characters printed. */ - - static int protocol_to_string(int protocol, __u8 *p) - { - int printed; - - switch (protocol) { - case ETH_P_IP: - printed = sprintf(p, "IP"); - break; - case ETH_P_ARP: - printed = sprintf(p, "ARP"); - break; - default: - printed = sprintf(p, "%d", protocol); - } - return printed; - } - static int ! sprintf_log_entry(char *buffer, struct strip *strip_info, int packet_index) { ! StripLog *entry; MetricomAddressString addr_string; - __u8 sig_buf[24], *s; - char *buf, proto_buf[10]; - - entry = &strip_info->packetLog[packet_index]; - if (!entry->valid) { - return 0; - } - buf = buffer; - buf += sprintf(buf, "%-4s %s %7lu ", strip_info->if_name, - ENTRY_TYPE_TO_STRING(entry->entry_type), entry->seqNum); - (void) protocol_to_string(entry->packet_type, proto_buf); - buf += sprintf(buf, "%-4s", proto_buf); - s = entry->sig.print_sig; - sprintf(sig_buf, "%d.%d.%d.%d.%d.%d", s[0], s[1], s[2], s[3], s[4], s[5]); - buf += sprintf(buf, "%-24s", sig_buf); - (void) radio_address_to_string((MetricomAddress *) &entry->src, - &addr_string); - buf += sprintf(buf, "%-10s", addr_string.c); - (void) radio_address_to_string((MetricomAddress *) &entry->dest, - &addr_string); - buf += sprintf(buf, "%-10s", addr_string.c); - buf += sprintf(buf, "%8d %6d %5lu %6lu %5lu\n", entry->timeStamp.tv_sec, - entry->timeStamp.tv_usec, entry->rawSize, - entry->stripSize, entry->slipSize); - return buf - buffer; - } ! /* ! * This function exports trace information from the STRIP driver through the ! * /proc file system. ! */ ! ! static int ! strip_get_trace_info(char *buffer, char **start, off_t requested_offset, ! int requested_len, int dummy) ! { ! char *buf; ! int len_exceeded, total = 0, slop = 0, packet_index, oldest; ! InterruptStatus i_status; ! struct strip *strip_info; ! ! buf = buffer; ! buf += sprintf(buf, "if s/r seqnum t signature "); ! buf += sprintf(buf, ! "src dest sec usec raw strip slip\n"); ! ! i_status = DisableInterrupts(); ! strip_info = struct_strip_list; ! oldest = strip_info->next_entry; ! RestoreInterrupts(i_status); ! /* ! * If we disable interrupts for this entire loop, ! * characters from the serial port could be lost, ! * so we only disable interrupts when accessing ! * a log entry. If more than STRIP_LOG_INT_SIZE ! * packets are logged before the first entry is ! * printed, then some of the entries could be ! * printed out of order. ! */ ! while (strip_info != NULL) { ! for (packet_index = oldest + STRIP_LOG_INT_SIZE; ! packet_index != oldest; ! packet_index = (packet_index + 1) % ! ELEMENTS_OF(strip_info->packetLog)) { ! i_status = DisableInterrupts(); ! buf += sprintf_log_entry(buf, strip_info, packet_index); ! RestoreInterrupts(i_status); ! len_exceeded = shift_buffer(buffer, requested_offset, ! requested_len, &total, &slop, &buf); ! if (len_exceeded) { ! goto done; ! } ! } ! strip_info = strip_info->next; ! } ! done: ! return calc_start_len(buffer, start, requested_offset, requested_len, ! total, buf); ! } ! static int slip_len(unsigned char *data, int len) ! { ! static const unsigned char SLIP_END=0300; /* indicates end of SLIP frame */ ! static const unsigned char SLIP_ESC=0333; /* indicates SLIP byte stuffing */ ! int count = len; ! while (--len >= 0) { ! if (*data == SLIP_END || *data == SLIP_ESC) count++; ! data++; } - return(count); - } - - /* Copied from kernel/sched.c */ - static void jiffiestotimeval(unsigned long jiffies, struct timeval *value) - { - value->tv_usec = (jiffies % HZ) * (1000000.0 / HZ); - value->tv_sec = jiffies / HZ; - return; - } - - /* - * This function logs a packet. - * A pointer to the packet itself is passed so that some of the data can be - * used to compute a signature. The pointer should point the the - * part of the packet following the STRIP_header. - */ - - static void packet_log(struct strip *strip_info, __u8 *packet, - LogEntry entry_type, STRIP_Header *hdr, - int raw_size, int strip_size, int slip_size) - { - StripLog *entry; - struct iphdr *iphdr; - struct arphdr *arphdr; ! entry = &strip_info->packetLog[strip_info->next_entry]; ! if (entry_type == EntrySend) { ! entry->seqNum = strip_info->num_sent++; ! } ! else { ! entry->seqNum = strip_info->num_received++; ! } ! entry->entry_type = entry_type; ! entry->packet_type = ntohs(hdr->protocol); ! switch (entry->packet_type) { ! case ETH_P_IP: ! /* ! * The signature for IP is the sender's ip address and ! * the identification field. ! */ ! iphdr = (struct iphdr *) packet; ! entry->sig.ip_sig.id = iphdr->id; ! entry->sig.ip_sig.src.l = iphdr->saddr; ! break; ! case ETH_P_ARP: ! /* ! * The signature for ARP is the sender's ip address and ! * the operation. ! */ ! arphdr = (struct arphdr *) packet; ! entry->sig.arp_sig.op = arphdr->ar_op; ! memcpy(&entry->sig.arp_sig.src.l, packet + 8 + arphdr->ar_hln, ! sizeof(entry->sig.arp_sig.src.l)); ! entry->sig.arp_sig.src.l = entry->sig.arp_sig.src.l; ! break; ! default: ! printk(KERN_DEBUG "STRIP: packet_log: unknown packet type: %d\n", ! entry->packet_type); ! break; ! } ! memcpy(&entry->src, &hdr->src_addr, sizeof(MetricomAddress)); ! memcpy(&entry->dest, &hdr->dst_addr, sizeof(MetricomAddress)); ! ! jiffiestotimeval(jiffies, &(entry->timeStamp)); ! entry->rawSize = raw_size; ! entry->stripSize = strip_size; ! entry->slipSize = slip_size; ! entry->valid = 1; ! strip_info->next_entry = (strip_info->next_entry + 1) % ! ELEMENTS_OF(strip_info->packetLog); } - #endif DO_PROC_NET_STRIP_TRACE - /* ! * This function parses the response to the ATS300? command, ! * extracting the radio version and serial number. */ - static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end) - { - __u8 *p, *value_begin, *value_end; - int len; - - /* Determine the beginning of the second line of the payload */ - p = ptr; - while (p < end && *p != 10) p++; - if (p >= end) return; - p++; - value_begin = p; - - /* Determine the end of line */ - while (p < end && *p != 10) p++; - if (p >= end) return; - value_end = p; - p++; - - len = value_end - value_begin; - len = MIN(len, sizeof(MetricomFirmwareVersion) - 1); - sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); - - /* Look for the first colon */ - while (p < end && *p != ':') p++; - if (p >= end) return; - /* Skip over the space */ - p += 2; - len = sizeof(MetricomSerialNumber) - 1; - if (p + len <= end) { - sprintf(strip_info->serial_number.c, "%.*s", len, p); - } - else { - printk(KERN_ERR "STRIP: radio serial number shorter (%d) than expected (%d)\n", - end - p, len); - } - } ! /* ! * This function parses the response to the ATS325? command, ! * extracting the radio battery voltage. ! */ ! static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end) { ! int len; ! len = sizeof(MetricomBatteryVoltage) - 1; ! if (ptr + len <= end) { ! sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); ! } ! else { ! printk(KERN_ERR "STRIP: radio voltage string shorter (%d) than expected (%d)\n", ! end - ptr, len); ! } } ! /* ! * This function parses the response to the AT~I2 command, ! * which gives the names of the radio's nearest neighbors. ! * It relies on the format of the response. ! */ ! static void get_radio_neighbors(struct strip *strip_info, __u8 *ptr, __u8 *end) { ! __u8 *p, *line_begin; ! int num_nodes_reported, num_nodes_counted; ! MetricomNode *node, *last; ! ! /* Check if someone is reading the list */ ! if (strip_info->neighbor_list_locked) { ! return; ! } ! ! /* Determine the number of Nodes */ ! p = ptr; ! num_nodes_reported = simple_strtoul(p, NULL, 10); ! /* printk(KERN_DEBUG "num_nodes: %d\n", num_nodes_reported); */ ! ! /* Determine the beginning of the next line */ ! while (p < end && *p != 10) p++; ! if (p >= end) return; ! p++; ! ! /* ! * The node list should never be empty because we allocate one empty ! * node when the strip_info is allocated. The nodes which were allocated ! * when the number of neighbors was high but are no longer needed because ! * there aren't as many neighbors any more are marked invalid. Invalid nodes ! * are kept at the end of the list. ! */ ! node = strip_info->neighbor_list; ! last = node; ! if (node == NULL) { ! DumpData("Neighbor list is NULL:", strip_info, p, end); ! return; ! } ! line_begin = p; ! num_nodes_counted = 0; ! while (line_begin < end) { ! /* Check to see if the format is what we expect. */ ! if ((line_begin + STRIP_NODE_LEN) > end) { ! printk(KERN_ERR "STRIP: radio neighbor node string shorter (%d) than expected (%d)\n", ! end - line_begin, STRIP_NODE_LEN); ! break; ! } ! ! /* Get a node */ ! if (node == NULL) { ! node = kmalloc(sizeof(MetricomNode), GFP_ATOMIC); ! node->next = NULL; ! } ! node->type = NodeValid; ! ! /* Fill the node in */ ! ! /* Determine if it has a GPS location and fill it in if it does. */ ! p = line_begin; ! /* printk(KERN_DEBUG "node: %64s\n", p); */ ! if (p[0] != STRIP_PORTABLE_CHAR) { ! node->type |= NodeHasWAN; ! sprintf(node->gl.s, "%.*s", (int) sizeof(GeographicLocation) - 1, p); ! } ! ! /* Determine if it is a router */ ! p = line_begin + 18; ! if (p[0] == STRIP_ROUTER_CHAR) { ! node->type |= NodeIsRouter; ! } ! ! /* Could be a radio address or some weird poletop address. */ ! p = line_begin + 20; ! /* printk(KERN_DEBUG "before addr: %6s\n", p); */ ! string_to_radio_address(&node->addr, p); ! /* radio_address_to_string(&node->addr, addr_string); ! printk(KERN_DEBUG "after addr: %s\n", addr_string); */ ! ! if (IS_RADIO_ADDRESS(p)) { ! string_to_radio_address(&node->addr, p); ! } ! else { ! memset(&node->addr, 0, sizeof(MetricomAddress)); ! } ! ! /* Get the poll latency. %$#!@ simple_strtoul can't skip white space */ ! p = line_begin + 41; ! while (isspace(*p) && (p < end)) { ! p++; ! } ! node->poll_latency = simple_strtoul(p, NULL, 10); ! ! /* Get the signal strength. simple_strtoul doesn't do minus signs */ ! p = line_begin + 60; ! node->rssi = -simple_strtoul(p, NULL, 10); ! ! if (last != node) { ! last->next = node; ! last = node; ! } ! node = node->next; ! line_begin += STRIP_NODE_LEN; ! num_nodes_counted++; ! } ! ! /* invalidate all remaining nodes */ ! for (;node != NULL; node = node->next) { ! node->type &= ~NodeValid; ! } ! ! /* ! * If the number of nodes reported is different ! * from the number counted, might need to up the number ! * requested. ! */ ! if (num_nodes_reported != num_nodes_counted) { ! printk(KERN_DEBUG "nodes reported: %d \tnodes counted: %d\n", ! num_nodes_reported, num_nodes_counted); ! } ! } /************************************************************************/ /* Sending routines */ static void ResetRadio(struct strip *strip_info) ! { ! static const char InitString[] = "\rat\r\rate0q1dt**starmode\r\r**"; /* If the radio isn't working anymore, we should clear the old status information. */ if (strip_info->working) --- 1069,1239 ---- return(buffer); } ! static int sprintf_neighbours(char *buffer, MetricomNodeTable *table, char *title) { ! /* We wrap this in a do/while loop, so if the table changes */ ! /* while we're reading it, we just go around and try again. */ ! struct timeval t; ! char *ptr; ! do ! { ! int i; ! t = table->timestamp; ! ptr = buffer; ! if (table->num_nodes) ptr += sprintf(ptr, "\n %s\n", title); ! for (i=0; inum_nodes; i++) ! { ! InterruptStatus intstat = DisableInterrupts(); ! MetricomNode node = table->node[i]; ! RestoreInterrupts(intstat); ! ptr += sprintf(ptr, " %s\n", node.c); ! } ! } while (table->timestamp.tv_sec != t.tv_sec || table->timestamp.tv_usec != t.tv_usec); ! return ptr - buffer; } /* ! * This function prints radio status information into the specified buffer. ! * I think the buffer size is 4K, so this routine should never print more ! * than 4K of data into it. With the maximum of 32 portables and 32 poletops ! * reported, the routine outputs 3107 bytes into the buffer. */ static int ! sprintf_status_info(char *buffer, struct strip *strip_info) { ! char temp[32]; ! char *p = buffer; MetricomAddressString addr_string; ! /* First, we must copy all of our data to a safe place, */ ! /* in case a serial interrupt comes in and changes it. */ ! InterruptStatus intstat = DisableInterrupts(); ! int tx_left = strip_info->tx_left; ! unsigned long rx_average_pps = strip_info->rx_average_pps; ! unsigned long tx_average_pps = strip_info->tx_average_pps; ! unsigned long sx_average_pps = strip_info->sx_average_pps; ! int working = strip_info->working; ! int firmware_level = strip_info->firmware_level; ! long watchdog_doprobe = strip_info->watchdog_doprobe; ! long watchdog_doreset = strip_info->watchdog_doreset; ! long gratuitous_arp = strip_info->gratuitous_arp; ! long arp_interval = strip_info->arp_interval; ! FirmwareVersion firmware_version = strip_info->firmware_version; ! SerialNumber serial_number = strip_info->serial_number; ! BatteryVoltage battery_voltage = strip_info->battery_voltage; ! char8 if_name = strip_info->if_name; ! MetricomAddress true_dev_addr = strip_info->true_dev_addr; ! MetricomAddress dev_dev_addr = *(MetricomAddress*)strip_info->dev.dev_addr; ! int manual_dev_addr = strip_info->manual_dev_addr; ! #ifdef EXT_COUNTERS ! unsigned long rx_bytes = strip_info->rx_bytes; ! unsigned long tx_bytes = strip_info->tx_bytes; ! unsigned long rx_rbytes = strip_info->rx_rbytes; ! unsigned long tx_rbytes = strip_info->tx_rbytes; ! unsigned long rx_sbytes = strip_info->rx_sbytes; ! unsigned long tx_sbytes = strip_info->tx_sbytes; ! unsigned long rx_ebytes = strip_info->rx_ebytes; ! unsigned long tx_ebytes = strip_info->tx_ebytes; ! #endif ! RestoreInterrupts(intstat); ! p += sprintf(p, "\nInterface name\t\t%s\n", if_name.c); ! p += sprintf(p, " Radio working:\t\t%s\n", working ? "Yes" : "No"); ! radio_address_to_string(&true_dev_addr, &addr_string); ! p += sprintf(p, " Radio address:\t\t%s\n", addr_string.c); ! if (manual_dev_addr) ! { ! radio_address_to_string(&dev_dev_addr, &addr_string); ! p += sprintf(p, " Device address:\t%s\n", addr_string.c); ! } ! p += sprintf(p, " Firmware version:\t%s", !working ? "Unknown" : ! !firmware_level ? "Should be upgraded" : ! firmware_version.c); ! if (firmware_level >= ChecksummedMessages) p += sprintf(p, " (Checksums Enabled)"); ! p += sprintf(p, "\n"); ! p += sprintf(p, " Serial number:\t\t%s\n", serial_number.c); ! p += sprintf(p, " Battery voltage:\t%s\n", battery_voltage.c); ! p += sprintf(p, " Transmit queue (bytes):%d\n", tx_left); ! p += sprintf(p, " Receive packet rate: %ld packets per second\n", rx_average_pps / 8); ! p += sprintf(p, " Transmit packet rate: %ld packets per second\n", tx_average_pps / 8); ! p += sprintf(p, " Sent packet rate: %ld packets per second\n", sx_average_pps / 8); ! p += sprintf(p, " Next watchdog probe:\t%s\n", time_delta(temp, watchdog_doprobe)); ! p += sprintf(p, " Next watchdog reset:\t%s\n", time_delta(temp, watchdog_doreset)); ! p += sprintf(p, " Next gratuitous ARP:\t"); ! if (!memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address))) ! p += sprintf(p, "Disabled\n"); ! else { ! p += sprintf(p, "%s\n", time_delta(temp, gratuitous_arp)); ! p += sprintf(p, " Next ARP interval:\t%ld seconds\n", JIFFIE_TO_SEC(arp_interval)); } ! if (working) ! { ! #ifdef EXT_COUNTERS ! p += sprintf(p, "\n"); ! p += sprintf(p, " Total bytes: \trx:\t%lu\ttx:\t%lu\n", rx_bytes, tx_bytes); ! p += sprintf(p, " thru radio: \trx:\t%lu\ttx:\t%lu\n", rx_rbytes, tx_rbytes); ! p += sprintf(p, " thru serial port: \trx:\t%lu\ttx:\t%lu\n", rx_sbytes, tx_sbytes); ! p += sprintf(p, " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n", rx_ebytes, tx_ebytes); ! #endif ! p += sprintf_neighbours(p, &strip_info->poletops, "Poletops:"); ! p += sprintf_neighbours(p, &strip_info->portables, "Portables:"); ! } ! return p - buffer; } /* ! * This function is exports status information from the STRIP driver through ! * the /proc file system. */ ! static int get_status_info(char *buffer, char **start, off_t req_offset, int req_len, int dummy) { ! int total = 0, slop = 0; ! struct strip *strip_info = struct_strip_list; ! char *buf = buffer; ! buf += sprintf(buf, "strip_version: %s\n", StripVersion); ! if (shift_buffer(buffer, req_offset, req_len, &total, &slop, &buf)) goto exit; ! ! while (strip_info != NULL) ! { ! buf += sprintf_status_info(buf, strip_info); ! if (shift_buffer(buffer, req_offset, req_len, &total, &slop, &buf)) break; ! strip_info = strip_info->next; ! } ! exit: ! return(calc_start_len(buffer, start, req_offset, req_len, total, buf)); } ! static const char proc_strip_status_name[] = "strip"; ! static struct proc_dir_entry proc_strip_get_status_info = { ! PROC_NET_STRIP_STATUS, /* unsigned short low_ino */ ! sizeof(proc_strip_status_name)-1, /* unsigned short namelen */ ! proc_strip_status_name, /* const char *name */ ! S_IFREG | S_IRUGO, /* mode_t mode */ ! 1, /* nlink_t nlink */ ! 0, 0, 0, /* uid_t uid, gid_t gid, unsigned long size */ ! &proc_net_inode_operations, /* struct inode_operations * ops */ ! &get_status_info, /* int (*get_info)(...) */ ! NULL, /* void (*fill_inode)(struct inode *); */ ! NULL, NULL, NULL, /* struct proc_dir_entry *next, *parent, *subdir; */ ! NULL /* void *data; */ ! }; /************************************************************************/ /* Sending routines */ + #define InitString "ate0q1dt**starmode" + static void ResetRadio(struct strip *strip_info) ! { ! static const char s[] = "\r" InitString "\r**"; /* If the radio isn't working anymore, we should clear the old status information. */ if (strip_info->working) *************** *** 1530,1543 **** strip_info->firmware_version.c[0] = '\0'; strip_info->serial_number.c[0] = '\0'; strip_info->battery_voltage.c[0] = '\0'; } /* Mark radio address as unknown */ ! *(MetricomAddress*)&strip_info->dev.dev_addr = zero_address; strip_info->working = FALSE; ! strip_info->structured_messages = FALSE; strip_info->watchdog_doprobe = jiffies + 10 * HZ; strip_info->watchdog_doreset = jiffies + 1 * HZ; ! strip_info->tty->driver.write(strip_info->tty, 0, (char *)InitString, sizeof(InitString)-1); } /* --- 1242,1273 ---- strip_info->firmware_version.c[0] = '\0'; strip_info->serial_number.c[0] = '\0'; strip_info->battery_voltage.c[0] = '\0'; + strip_info->portables.num_nodes = 0; + do_gettimeofday(&strip_info->portables.timestamp); + strip_info->poletops.num_nodes = 0; + do_gettimeofday(&strip_info->poletops.timestamp); } + + strip_info->pps_timer = jiffies; + strip_info->rx_pps_count = 0; + strip_info->tx_pps_count = 0; + strip_info->sx_pps_count = 0; + strip_info->rx_average_pps = 0; + strip_info->tx_average_pps = 0; + strip_info->sx_average_pps = 0; + /* Mark radio address as unknown */ ! *(MetricomAddress*)&strip_info->true_dev_addr = zero_address; ! if (!strip_info->manual_dev_addr) *(MetricomAddress*)strip_info->dev.dev_addr = zero_address; strip_info->working = FALSE; ! strip_info->firmware_level = NoStructure; ! strip_info->next_command = CompatibilityCommand; strip_info->watchdog_doprobe = jiffies + 10 * HZ; strip_info->watchdog_doreset = jiffies + 1 * HZ; ! strip_info->tty->driver.write(strip_info->tty, 0, (char *)s, sizeof(s)-1); ! #ifdef EXT_COUNTERS ! strip_info->tx_ebytes += sizeof(s) - 1; ! #endif } /* *************** *** 1573,1578 **** --- 1303,1311 ---- int num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left); strip_info->tx_left -= num_written; strip_info->tx_head += num_written; + #ifdef EXT_COUNTERS + strip_info->tx_sbytes += num_written; + #endif RestoreInterrupts(intstat); } else /* Else start transmission of another packet */ *************** *** 1583,1594 **** } } ! static unsigned char *strip_make_packet(unsigned char *ptr, struct strip *strip_info, struct sk_buff *skb) { ! #if DO_PROC_NET_STRIP_TRACE ! unsigned char *start_ptr; ! #endif DO_PROC_NET_STRIP_TRACE __u8 *stuffstate = NULL; STRIP_Header *header = (STRIP_Header *)skb->data; MetricomAddress haddr = header->dst_addr; --- 1316,1336 ---- } } ! static __u8 *add_checksum(__u8 *buffer, __u8 *end) { ! __u16 sum = 0; ! __u8 *p = buffer; ! while (p < end) sum += *p++; ! end[3] = hextable[sum & 0xF]; sum >>= 4; ! end[2] = hextable[sum & 0xF]; sum >>= 4; ! end[1] = hextable[sum & 0xF]; sum >>= 4; ! end[0] = hextable[sum & 0xF]; ! return(end+4); ! } + static unsigned char *strip_make_packet(unsigned char *buffer, struct strip *strip_info, struct sk_buff *skb) + { + __u8 *ptr = buffer; __u8 *stuffstate = NULL; STRIP_Header *header = (STRIP_Header *)skb->data; MetricomAddress haddr = header->dst_addr; *************** *** 1603,1609 **** { printk(KERN_ERR "%s: strip_make_packet: Unknown packet type 0x%04X\n", strip_info->dev.name, ntohs(header->protocol)); - strip_info->tx_dropped++; return(NULL); } --- 1345,1350 ---- *************** *** 1611,1617 **** { printk(KERN_ERR "%s: Dropping oversized transmit packet: %d bytes\n", strip_info->dev.name, len); - strip_info->tx_dropped++; return(NULL); } --- 1352,1357 ---- *************** *** 1620,1642 **** * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) */ if (haddr.c[0] == 0xFF) - { - /*IPaddr a; - a.l = strip_info->dev.pa_brdaddr; - printk(KERN_INFO "%s: Broadcast packet! Sending to %d.%d.%d.%d\n", - strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]);*/ - if (!arp_query(haddr.c, strip_info->dev.pa_brdaddr, &strip_info->dev)) { ! /*IPaddr a; ! a.l = strip_info->dev.pa_brdaddr; ! printk(KERN_INFO "%s: No ARP cache entry for %d.%d.%d.%d\n", ! strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]); ! strip_info->tx_dropped++;*/ return(NULL); } - } *ptr++ = '*'; *ptr++ = hextable[haddr.c[2] >> 4]; *ptr++ = hextable[haddr.c[2] & 0xF]; --- 1360,1379 ---- * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) */ if (haddr.c[0] == 0xFF) if (!arp_query(haddr.c, strip_info->dev.pa_brdaddr, &strip_info->dev)) { ! printk(KERN_ERR "%s: Unable to send packet (no broadcast hub configured)\n", ! strip_info->dev.name); return(NULL); } + /* + * If we're sending to ourselves, discard the packet. + * (Metricom radios choke if they try to send a packet to their own address.) + */ + if (!memcmp(haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) return(NULL); + + *ptr++ = 0x0D; *ptr++ = '*'; *ptr++ = hextable[haddr.c[2] >> 4]; *ptr++ = hextable[haddr.c[2] & 0xF]; *************** *** 1653,1669 **** *ptr++ = key.c[2]; *ptr++ = key.c[3]; - #if DO_PROC_NET_STRIP_TRACE - start_ptr = ptr; - #endif DO_PROC_NET_STRIP_TRACE - ptr = StuffData(skb->data + sizeof(STRIP_Header), len, ptr, &stuffstate); ! #if DO_PROC_NET_STRIP_TRACE ! packet_log(strip_info, skb->data + sizeof(STRIP_Header), EntrySend, ! header, len, ptr-start_ptr, ! slip_len(skb->data + sizeof(STRIP_Header), len)); ! #endif DO_PROC_NET_STRIP_TRACE *ptr++ = 0x0D; return(ptr); --- 1390,1398 ---- *ptr++ = key.c[2]; *ptr++ = key.c[3]; ptr = StuffData(skb->data + sizeof(STRIP_Header), len, ptr, &stuffstate); ! if (strip_info->firmware_level >= ChecksummedMessages) ptr = add_checksum(buffer+1, ptr); *ptr++ = 0x0D; return(ptr); *************** *** 1671,1728 **** static void strip_send(struct strip *strip_info, struct sk_buff *skb) { unsigned char *ptr = strip_info->tx_buff; ! /* If we have a packet, encapsulate it and put it in the buffer */ if (skb) { ! ptr = strip_make_packet(ptr, strip_info, skb); ! /* If error, unlock and return */ ! if (!ptr) { strip_unlock(strip_info); return; } ! strip_info->tx_packets++; /* Count another successful packet */ ! /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);*/ ! /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);*/ ! } ! ! /* Set up the strip_info ready to send the data */ ! strip_info->tx_head = strip_info->tx_buff; ! strip_info->tx_left = ptr - strip_info->tx_buff; ! strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); ! ! /* If watchdog has expired, reset the radio */ ! if ((long)jiffies - strip_info->watchdog_doreset >= 0) ! { ! ResetRadio(strip_info); ! return; ! /* Note: if there's a packet to send, strip_write_some_more ! will do it after the reset has finished */ } ! /* No reset. ! * If it is time for another tickle, tack it on the end of the packet */ ! if ((long)jiffies - strip_info->watchdog_doprobe >= 0) { ! /* Send tickle to make radio protest */ ! /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);*/ ! const char *TickleString = TickleString1; ! int length = sizeof(TickleString1)-1; ! if (strip_info->structured_messages) { ! TickleString = TickleString2; ! length = sizeof(TickleString2)-1; } ! memcpy(ptr, TickleString, length); ! strip_info->tx_left += length; strip_info->watchdog_doprobe = jiffies + 10 * HZ; strip_info->watchdog_doreset = jiffies + 1 * HZ; } /* ! * If it is time for a periodic ARP, queue one up to be sent */ if (strip_info->working && (long)jiffies - strip_info->gratuitous_arp >= 0 && ! memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address))) { /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", strip_info->dev.name, strip_info->arp_interval / HZ);*/ --- 1400,1509 ---- static void strip_send(struct strip *strip_info, struct sk_buff *skb) { + MetricomAddress haddr; unsigned char *ptr = strip_info->tx_buff; + int doreset = (long)jiffies - strip_info->watchdog_doreset >= 0; + int doprobe = (long)jiffies - strip_info->watchdog_doprobe >= 0 && !doreset; ! /* ! * 1. If we have a packet, encapsulate it and put it in the buffer ! */ if (skb) { ! char *newptr = strip_make_packet(ptr, strip_info, skb); ! strip_info->tx_pps_count++; ! if (!newptr) strip_info->tx_dropped++; ! else ! { ! ptr = newptr; ! strip_info->sx_pps_count++; ! strip_info->tx_packets++; /* Count another successful packet */ ! #ifdef EXT_COUNTERS ! strip_info->tx_bytes += skb->len; ! strip_info->tx_rbytes += ptr - strip_info->tx_buff; ! #endif ! /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);*/ ! /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);*/ ! } } ! /* ! * 2. If it is time for another tickle, tack it on, after the packet */ ! if (doprobe) { ! StringDescriptor ts = CommandString[strip_info->next_command]; ! #if TICKLE_TIMERS { ! struct timeval tv; ! do_gettimeofday(&tv); ! printk(KERN_INFO "**** Sending tickle string %d at %02d.%06d\n", ! strip_info->next_command, tv.tv_sec % 100, tv.tv_usec); } ! #endif ! if (ptr == strip_info->tx_buff) *ptr++ = 0x0D; ! ! *ptr++ = '*'; /* First send "**" to provoke an error message */ ! *ptr++ = '*'; ! ! /* Then add the command */ ! memcpy(ptr, ts.string, ts.length); ! ! /* Add a checksum ? */ ! if (strip_info->firmware_level < ChecksummedMessages) ptr += ts.length; ! else ptr = add_checksum(ptr, ptr + ts.length); ! ! *ptr++ = 0x0D; /* Terminate the command with a */ ! ! /* Cycle to next periodic command? */ ! if (strip_info->firmware_level >= StructuredMessages) ! if (++strip_info->next_command >= ELEMENTS_OF(CommandString)) ! strip_info->next_command = 0; ! #ifdef EXT_COUNTERS ! strip_info->tx_ebytes += ts.length; ! #endif strip_info->watchdog_doprobe = jiffies + 10 * HZ; strip_info->watchdog_doreset = jiffies + 1 * HZ; + /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);*/ } /* ! * 3. Set up the strip_info ready to send the data (if any). ! */ ! strip_info->tx_head = strip_info->tx_buff; ! strip_info->tx_left = ptr - strip_info->tx_buff; ! strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); ! ! /* ! * 4. Debugging check to make sure we're not overflowing the buffer. ! */ ! if (strip_info->tx_size - strip_info->tx_left < 20) ! printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", strip_info->dev.name, ! strip_info->tx_left, strip_info->tx_size - strip_info->tx_left); ! ! /* ! * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in ! * the buffer, strip_write_some_more will send it after the reset has finished ! */ ! if (doreset) { ResetRadio(strip_info); return; } ! ! /* ! * 6. If it is time for a periodic ARP, queue one up to be sent. ! * We only do this if: ! * 1. The radio is working ! * 2. It's time to send another periodic ARP ! * 3. We really know what our address is (and it is not manually set to zero) ! * 4. We have a designated broadcast address configured ! * If we queue up an ARP packet when we don't have a designated broadcast ! * address configured, then the packet will just have to be discarded in ! * strip_make_packet. This is not fatal, but it causes misleading information ! * to be displayed in tcpdump. tcpdump will report that periodic APRs are ! * being sent, when in fact they are not, because they are all being dropped ! * in the strip_make_packet routine. */ if (strip_info->working && (long)jiffies - strip_info->gratuitous_arp >= 0 && ! memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) && ! arp_query(haddr.c, strip_info->dev.pa_brdaddr, &strip_info->dev)) { /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", strip_info->dev.name, strip_info->arp_interval / HZ);*/ *************** *** 1730,1745 **** strip_info->arp_interval *= 2; if (strip_info->arp_interval > MaxARPInterval) strip_info->arp_interval = MaxARPInterval; ! arp_send(ARPOP_REPLY, ETH_P_ARP, strip_info->dev.pa_addr, ! &strip_info->dev, strip_info->dev.pa_addr, ! NULL, strip_info->dev.dev_addr, NULL); } ! if (strip_info->tx_size - strip_info->tx_left < 20) ! printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", strip_info->dev.name, ! strip_info->tx_left, strip_info->tx_size - strip_info->tx_left); ! ! /* All ready. Start the transmission */ strip_write_some_more(strip_info->tty); } --- 1511,1528 ---- strip_info->arp_interval *= 2; if (strip_info->arp_interval > MaxARPInterval) strip_info->arp_interval = MaxARPInterval; ! arp_send(ARPOP_REPLY, ETH_P_ARP, ! strip_info->dev.pa_addr, /* Target address of ARP packet is our address */ ! &strip_info->dev, /* Device to send packet on */ ! strip_info->dev.pa_addr, /* Source IP address this ARP packet comes from */ ! NULL, /* Destination HW address is NULL (broadcast it) */ ! strip_info->dev.dev_addr, /* Source HW address is our HW address */ ! strip_info->dev.dev_addr); /* Target HW address is our HW address (redundant) */ } ! /* ! * 7. All ready. Start the transmission ! */ strip_write_some_more(strip_info->tty); } *************** *** 1760,1765 **** --- 1543,1575 ---- if (strip_info->mtu != strip_info->dev.mtu) strip_changedmtu(strip_info); + if (jiffies - strip_info->pps_timer > HZ) + { + unsigned long t = jiffies - strip_info->pps_timer; + unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t/2) / t; + unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t/2) / t; + unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t/2) / t; + + strip_info->pps_timer = jiffies; + strip_info->rx_pps_count = 0; + strip_info->tx_pps_count = 0; + strip_info->sx_pps_count = 0; + + strip_info->rx_average_pps = (strip_info->rx_average_pps + rx_pps_count + 1) / 2; + strip_info->tx_average_pps = (strip_info->tx_average_pps + tx_pps_count + 1) / 2; + strip_info->sx_average_pps = (strip_info->sx_average_pps + sx_pps_count + 1) / 2; + + if (rx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Receiving %ld packets per second.\n", + strip_info->dev.name, rx_pps_count / 8); + if (tx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Tx %ld packets per second.\n", + strip_info->dev.name, tx_pps_count / 8); + if (sx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Sending %ld packets per second.\n", + strip_info->dev.name, sx_pps_count / 8); + } + strip_send(strip_info, skb); if (skb) dev_kfree_skb(skb, FREE_WRITE); *************** *** 1767,1772 **** --- 1577,1593 ---- } /* + * IdleTask periodically calls strip_xmit, so even when we have no IP packets + * to send for an extended period of time, the watchdog processing still gets + * done to ensure that the radio stays in Starmode + */ + + static void strip_IdleTask(unsigned long parameter) + { + strip_xmit(NULL, (struct device *)parameter); + } + + /* * Create the MAC header for an arbitrary protocol layer * * saddr!=NULL means use this specific address (n/a for Metricom) *************** *** 1780,1798 **** static int strip_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { STRIP_Header *header = (STRIP_Header *)skb_push(skb, sizeof(STRIP_Header)); /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type, type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : "");*/ ! memcpy(header->src_addr.c, dev->dev_addr, dev->addr_len); header->protocol = htons(type); /*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len);*/ if (!daddr) return(-dev->hard_header_len); ! memcpy(header->dst_addr.c, daddr, dev->addr_len); return(dev->hard_header_len); } --- 1601,1620 ---- static int strip_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { + struct strip *strip_info = (struct strip *)(dev->priv); STRIP_Header *header = (STRIP_Header *)skb_push(skb, sizeof(STRIP_Header)); /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type, type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : "");*/ ! header->src_addr = strip_info->true_dev_addr; header->protocol = htons(type); /*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len);*/ if (!daddr) return(-dev->hard_header_len); ! header->dst_addr = *(MetricomAddress*)daddr; return(dev->hard_header_len); } *************** *** 1820,1862 **** #endif } /* ! * IdleTask periodically calls strip_xmit, so even when we have no IP packets ! * to send for an extended period of time, the watchdog processing still gets ! * done to ensure that the radio stays in Starmode */ ! ! static void strip_IdleTask(unsigned long parameter) { ! strip_xmit(NULL, (struct device *)parameter); } ! /************************************************************************/ ! /* Receiving routines */ ! static int strip_receive_room(struct tty_struct *tty) { ! return 0x10000; /* We can handle an infinite amount of data. :-) */ } ! static void get_radio_address(struct strip *strip_info, __u8 *p) { MetricomAddress addr; ! string_to_radio_address(&addr, p); /* See if our radio address has changed */ ! if (memcmp(strip_info->dev.dev_addr, addr.c, sizeof(addr))) { MetricomAddressString addr_string; radio_address_to_string(&addr, &addr_string); ! printk(KERN_INFO "%s: My radio address = %s\n", strip_info->dev.name, addr_string.c); ! memcpy(strip_info->dev.dev_addr, addr.c, sizeof(addr)); /* Give the radio a few seconds to get its head straight, then send an arp */ ! strip_info->gratuitous_arp = jiffies + 6 * HZ; strip_info->arp_interval = 1 * HZ; } } static void RecvErr(char *msg, struct strip *strip_info) --- 1642,1771 ---- #endif } + + /************************************************************************/ + /* Receiving routines */ + + static int strip_receive_room(struct tty_struct *tty) + { + return 0x10000; /* We can handle an infinite amount of data. :-) */ + } + /* ! * This function parses the response to the ATS300? command, ! * extracting the radio version and serial number. */ ! static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end) { ! __u8 *p, *value_begin, *value_end; ! int len; ! ! /* Determine the beginning of the second line of the payload */ ! p = ptr; ! while (p < end && *p != 10) p++; ! if (p >= end) return; ! p++; ! value_begin = p; ! ! /* Determine the end of line */ ! while (p < end && *p != 10) p++; ! if (p >= end) return; ! value_end = p; ! p++; ! ! len = value_end - value_begin; ! len = MIN(len, sizeof(FirmwareVersion) - 1); ! if (strip_info->firmware_version.c[0] == 0) ! printk(KERN_INFO "%s: Radio Firmware: %.*s\n", ! strip_info->dev.name, len, value_begin); ! sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); ! ! /* Look for the first colon */ ! while (p < end && *p != ':') p++; ! if (p >= end) return; ! /* Skip over the space */ ! p += 2; ! len = sizeof(SerialNumber) - 1; ! if (p + len <= end) { ! sprintf(strip_info->serial_number.c, "%.*s", len, p); ! } ! else { ! printk(KERN_DEBUG "STRIP: radio serial number shorter (%d) than expected (%d)\n", ! end - p, len); ! } } + /* + * This function parses the response to the ATS325? command, + * extracting the radio battery voltage. + */ + static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end) + { + int len; ! len = sizeof(BatteryVoltage) - 1; ! if (ptr + len <= end) { ! sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); ! } ! else { ! printk(KERN_DEBUG "STRIP: radio voltage string shorter (%d) than expected (%d)\n", ! end - ptr, len); ! } ! } ! /* ! * This function parses the responses to the AT~LA and ATS311 commands, ! * which list the radio's neighbours. ! */ ! static void get_radio_neighbours(MetricomNodeTable *table, __u8 *ptr, __u8 *end) { ! table->num_nodes = 0; ! while (ptr < end && table->num_nodes < NODE_TABLE_SIZE) ! { ! MetricomNode *node = &table->node[table->num_nodes++]; ! char *dst = node->c, *limit = dst + sizeof(*node) - 1; ! while (ptr < end && *ptr <= 32) ptr++; ! while (ptr < end && dst < limit && *ptr != 10) *dst++ = *ptr++; ! *dst++ = 0; ! while (ptr < end && ptr[-1] != 10) ptr++; ! } ! do_gettimeofday(&table->timestamp); } ! static int get_radio_address(struct strip *strip_info, __u8 *p) { MetricomAddress addr; ! if (string_to_radio_address(&addr, p)) return(1); /* See if our radio address has changed */ ! if (memcmp(strip_info->true_dev_addr.c, addr.c, sizeof(addr))) { MetricomAddressString addr_string; radio_address_to_string(&addr, &addr_string); ! printk(KERN_INFO "%s: Radio address = %s\n", strip_info->dev.name, addr_string.c); ! strip_info->true_dev_addr = addr; ! if (!strip_info->manual_dev_addr) *(MetricomAddress*)strip_info->dev.dev_addr = addr; /* Give the radio a few seconds to get its head straight, then send an arp */ ! strip_info->gratuitous_arp = jiffies + 15 * HZ; strip_info->arp_interval = 1 * HZ; } + return(0); + } + + static int verify_checksum(struct strip *strip_info) + { + __u8 *p = strip_info->sx_buff; + __u8 *end = strip_info->sx_buff + strip_info->sx_count - 4; + u_short sum = (READHEX16(end[0]) << 12) | (READHEX16(end[1]) << 8) | + (READHEX16(end[2]) << 4) | (READHEX16(end[3])); + while (p < end) sum -= *p++; + if (sum == 0 && strip_info->firmware_level == StructuredMessages) + { + strip_info->firmware_level = ChecksummedMessages; + printk(KERN_INFO "%s: Radio provides message checksums\n", strip_info->dev.name); + } + return(sum == 0); } static void RecvErr(char *msg, struct strip *strip_info) *************** *** 1869,1982 **** static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __u8 *msg) { ! static const char ERR_001[] = "001"; /* Not in StarMode! */ ! static const char ERR_002[] = "002"; /* Remap handle */ ! static const char ERR_003[] = "003"; /* Can't resolve name */ ! static const char ERR_004[] = "004"; /* Name too small or missing */ ! static const char ERR_005[] = "005"; /* Bad count specification */ ! static const char ERR_006[] = "006"; /* Header too big */ ! static const char ERR_007[] = "007"; /* Body too big */ ! static const char ERR_008[] = "008"; /* Bad character in name */ ! static const char ERR_009[] = "009"; /* No count or line terminator */ ! ! if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1)) { RecvErr("Error Msg:", strip_info); printk(KERN_INFO "%s: Radio %s is not in StarMode\n", strip_info->dev.name, sendername); } ! else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1)) { ! RecvErr("Error Msg:", strip_info); ! #ifdef notyet /*Kernel doesn't have scanf!*/ ! int handle; ! __u8 newname[64]; ! sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname); ! printk(KERN_INFO "%s: Radio name %s is handle %d\n", ! strip_info->dev.name, newname, handle); ! #endif } ! else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1)) { RecvErr("Error Msg:", strip_info); printk(KERN_INFO "%s: Destination radio name is unknown\n", strip_info->dev.name); } ! else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) { strip_info->watchdog_doreset = jiffies + LongTime; if (!strip_info->working) { strip_info->working = TRUE; ! printk(KERN_INFO "%s: Radio now in starmode\n", ! strip_info->dev.name); /* * If the radio has just entered a working state, we should do our first * probe ASAP, so that we find out our radio address etc. without delay. */ strip_info->watchdog_doprobe = jiffies; } ! if (!strip_info->structured_messages && sendername) { ! strip_info->structured_messages = TRUE; ! printk(KERN_INFO "%s: Radio provides structured messages\n", ! strip_info->dev.name); } } ! else if (!strncmp(msg, ERR_005, sizeof(ERR_005)-1)) RecvErr("Error Msg:", strip_info); ! else if (!strncmp(msg, ERR_006, sizeof(ERR_006)-1)) RecvErr("Error Msg:", strip_info); ! else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1)) { - /* - * Note: This error knocks the radio back into - * command mode. - */ RecvErr("Error Msg:", strip_info); ! printk(KERN_ERR "%s: Error! Packet size too big for radio.", strip_info->dev.name); - strip_info->watchdog_doreset = jiffies; /* Do reset ASAP */ } ! else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1)) { RecvErr("Error Msg:", strip_info); printk(KERN_ERR "%s: Radio name contains illegal character\n", strip_info->dev.name); } ! else if (!strncmp(msg, ERR_009, sizeof(ERR_009)-1)) RecvErr("Error Msg:", strip_info); else RecvErr("Error Msg:", strip_info); } static void process_AT_response(struct strip *strip_info, __u8 *ptr, __u8 *end) { - static const char ATS305[] = "ATS305?"; - static const char ATS300[] = "ATS300?"; - static const char ATS325[] = "ATS325?"; - static const char ATI2[] = "AT~I2 nn"; - - /* Skip to the first newline character */ __u8 *p = ptr; ! while (p < end && *p != 10) p++; ! if (p >= end) return; ! p++; ! if (!strncmp(ptr, ATS305, sizeof(ATS305)-1)) { ! if (IS_RADIO_ADDRESS(p)) get_radio_address(strip_info, p); ! } ! else if (!strncmp(ptr, ATS300, sizeof(ATS300)-1)) { ! get_radio_version(strip_info, p, end); ! } ! else if (!strncmp(ptr, ATS325, sizeof(ATS325)-1)) { ! get_radio_voltage(strip_info, p, end); } ! else if (!strncmp(ptr, ATI2, sizeof(ATI2)-1)) { ! get_radio_neighbors(strip_info, p, end); } ! else RecvErr("Unknown AT Response:", strip_info); } /* --- 1778,1933 ---- static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __u8 *msg) { ! if (has_prefix(msg, "001")) /* Not in StarMode! */ { RecvErr("Error Msg:", strip_info); printk(KERN_INFO "%s: Radio %s is not in StarMode\n", strip_info->dev.name, sendername); } ! ! else if (has_prefix(msg, "002")) /* Remap handle */ { ! /* We ignore "Remap handle" messages for now */ } ! ! else if (has_prefix(msg, "003")) /* Can't resolve name */ { RecvErr("Error Msg:", strip_info); printk(KERN_INFO "%s: Destination radio name is unknown\n", strip_info->dev.name); } ! ! else if (has_prefix(msg, "004")) /* Name too small or missing */ { strip_info->watchdog_doreset = jiffies + LongTime; + #if TICKLE_TIMERS + { + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO "**** Got ERR_004 response at %02d.%06d\n", + tv.tv_sec % 100, tv.tv_usec); + } + #endif if (!strip_info->working) { strip_info->working = TRUE; ! printk(KERN_INFO "%s: Radio now in starmode\n", strip_info->dev.name); /* * If the radio has just entered a working state, we should do our first * probe ASAP, so that we find out our radio address etc. without delay. */ strip_info->watchdog_doprobe = jiffies; } ! if (strip_info->firmware_level == NoStructure && sendername) { ! strip_info->firmware_level = StructuredMessages; ! strip_info->next_command = 0; /* Try to enable checksums ASAP */ ! printk(KERN_INFO "%s: Radio provides structured messages\n", strip_info->dev.name); ! } ! if (strip_info->firmware_level >= StructuredMessages) ! { ! verify_checksum(strip_info); ! /* ! * If the radio has structured messages but we don't yet have all our information about it, we should do ! * probes without delay, until we have gathered all the information ! */ ! if (!GOT_ALL_RADIO_INFO(strip_info)) strip_info->watchdog_doprobe = jiffies; } } ! ! else if (has_prefix(msg, "005")) /* Bad count specification */ RecvErr("Error Msg:", strip_info); ! ! else if (has_prefix(msg, "006")) /* Header too big */ RecvErr("Error Msg:", strip_info); ! ! else if (has_prefix(msg, "007")) /* Body too big */ { RecvErr("Error Msg:", strip_info); ! printk(KERN_ERR "%s: Error! Packet size too big for radio.\n", strip_info->dev.name); } ! ! else if (has_prefix(msg, "008")) /* Bad character in name */ { RecvErr("Error Msg:", strip_info); printk(KERN_ERR "%s: Radio name contains illegal character\n", strip_info->dev.name); } ! ! else if (has_prefix(msg, "009")) /* No count or line terminator */ ! RecvErr("Error Msg:", strip_info); ! ! else if (has_prefix(msg, "010")) /* Invalid checksum */ ! RecvErr("Error Msg:", strip_info); ! ! else if (has_prefix(msg, "011")) /* Checksum didn't match */ ! RecvErr("Error Msg:", strip_info); ! ! else if (has_prefix(msg, "012")) /* Failed to transmit packet */ RecvErr("Error Msg:", strip_info); + else RecvErr("Error Msg:", strip_info); } static void process_AT_response(struct strip *strip_info, __u8 *ptr, __u8 *end) { __u8 *p = ptr; ! while (p < end && p[-1] != 10) p++; /* Skip past first newline character */ ! /* Now ptr points to the AT command, and p points to the text of the response. */ ! #if TICKLE_TIMERS { ! struct timeval tv; ! do_gettimeofday(&tv); ! printk(KERN_INFO "**** Got AT response %.7s at %02d.%06d\n", ! ptr, tv.tv_sec % 100, tv.tv_usec); } ! #endif ! ! if (has_prefix(ptr, "ATS300?" )) get_radio_version(strip_info, p, end); ! else if (has_prefix(ptr, "ATS305?" )) get_radio_address(strip_info, p); ! else if (has_prefix(ptr, "ATS311?" )) get_radio_neighbours(&strip_info->poletops, p, end); ! else if (has_prefix(ptr, "ATS319=7")) verify_checksum(strip_info); ! else if (has_prefix(ptr, "ATS325?" )) get_radio_voltage(strip_info, p, end); ! else if (has_prefix(ptr, "AT~LA" )) get_radio_neighbours(&strip_info->portables, p, end); ! else RecvErr("Unknown AT Response:", strip_info); ! } ! ! static void process_ACK(struct strip *strip_info, __u8 *ptr, __u8 *end) ! { ! /* Currently we don't do anything with ACKs from the radio */ ! } ! ! static void process_Info(struct strip *strip_info, __u8 *ptr, __u8 *end) ! { ! if (ptr+16 > end) RecvErr("Bad Info Msg:", strip_info); ! } ! ! static struct device *get_strip_dev(struct strip *strip_info) ! { ! /* If our hardware address is *manually set* to zero, and we know our */ ! /* real radio hardware address, try to find another strip device that has been */ ! /* manually set to that address that we can 'transfer ownership' of this packet to */ ! if (strip_info->manual_dev_addr && ! !memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) && ! memcmp(&strip_info->true_dev_addr, zero_address.c, sizeof(zero_address))) ! { ! struct device *dev = dev_base; ! while (dev) ! { ! if (dev->type == strip_info->dev.type && ! !memcmp(dev->dev_addr, &strip_info->true_dev_addr, sizeof(MetricomAddress))) ! { ! printk(KERN_INFO "%s: Transferred packet ownership to %s.\n", ! strip_info->dev.name, dev->name); ! return(dev); ! } ! dev = dev->next; ! } } ! return(&strip_info->dev); } /* *************** *** 1988,2001 **** struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen); if (!skb) { ! printk(KERN_INFO "%s: memory squeeze, dropping packet.\n", strip_info->dev.name); strip_info->rx_dropped++; } else { memcpy(skb_put(skb, sizeof(STRIP_Header)), header, sizeof(STRIP_Header)); memcpy(skb_put(skb, packetlen), strip_info->rx_buff, packetlen); ! skb->dev = &strip_info->dev; skb->protocol = header->protocol; skb->mac.raw = skb->data; --- 1939,1952 ---- struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen); if (!skb) { ! printk(KERN_ERR "%s: memory squeeze, dropping packet.\n", strip_info->dev.name); strip_info->rx_dropped++; } else { memcpy(skb_put(skb, sizeof(STRIP_Header)), header, sizeof(STRIP_Header)); memcpy(skb_put(skb, packetlen), strip_info->rx_buff, packetlen); ! skb->dev = get_strip_dev(strip_info); skb->protocol = header->protocol; skb->mac.raw = skb->data; *************** *** 2006,2011 **** --- 1957,1966 ---- /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */ strip_info->rx_packets++; + strip_info->rx_pps_count++; + #ifdef EXT_COUNTERS + strip_info->rx_bytes += packetlen; + #endif netif_rx(skb); } } *************** *** 2014,2023 **** { __u16 packetlen; - #if DO_PROC_NET_STRIP_TRACE - __u8 *start_ptr = ptr; - #endif DO_PROC_NET_STRIP_TRACE - /* Decode start of the IP packet header */ ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); if (!ptr) --- 1969,1974 ---- *************** *** 2028,2036 **** packetlen = ((__u16)strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; ! if (packetlen > MAX_STRIP_MTU) { ! printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n", strip_info->dev.name, packetlen); strip_info->rx_dropped++; return; --- 1979,1987 ---- packetlen = ((__u16)strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; ! if (packetlen > MAX_RECV_MTU) { ! printk(KERN_INFO "%s: Dropping oversized received IP packet: %d bytes\n", strip_info->dev.name, packetlen); strip_info->rx_dropped++; return; *************** *** 2054,2064 **** header->protocol = htons(ETH_P_IP); - #if DO_PROC_NET_STRIP_TRACE - packet_log(strip_info, strip_info->rx_buff, EntryReceive, header, - packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); - #endif DO_PROC_NET_STRIP_TRACE - deliver_packet(strip_info, header, packetlen); } --- 2005,2010 ---- *************** *** 2067,2076 **** __u16 packetlen; struct arphdr *arphdr = (struct arphdr *)strip_info->rx_buff; - #if DO_PROC_NET_STRIP_TRACE - __u8 *start_ptr = ptr; - #endif DO_PROC_NET_STRIP_TRACE - /* Decode start of the ARP packet */ ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8); if (!ptr) --- 2013,2018 ---- *************** *** 2081,2089 **** packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2; ! if (packetlen > MAX_STRIP_MTU) { ! printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n", strip_info->dev.name, packetlen); strip_info->rx_dropped++; return; --- 2023,2031 ---- packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2; ! if (packetlen > MAX_RECV_MTU) { ! printk(KERN_INFO "%s: Dropping oversized received ARP packet: %d bytes\n", strip_info->dev.name, packetlen); strip_info->rx_dropped++; return; *************** *** 2109,2123 **** header->protocol = htons(ETH_P_ARP); - #if DO_PROC_NET_STRIP_TRACE - packet_log(strip_info, strip_info->rx_buff, EntryReceive, header, - packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); - #endif DO_PROC_NET_STRIP_TRACE - deliver_packet(strip_info, header, packetlen); } ! static void process_packet(struct strip *strip_info) { STRIP_Header header = { zero_address, zero_address, 0 }; __u8 *ptr = strip_info->sx_buff; --- 2051,2097 ---- header->protocol = htons(ETH_P_ARP); deliver_packet(strip_info, header, packetlen); } ! /* ! * process_text_message processes a -terminated block of data received ! * from the radio that doesn't begin with a '*' character. All normal ! * Starmode communication messages with the radio begin with a '*', ! * so any text that does not indicates a serial port error, a radio that ! * is in Hayes command mode instead of Starmode, or a radio with really ! * old firmware that doesn't frame its Starmode responses properly. ! */ ! static void process_text_message(struct strip *strip_info) ! { ! __u8 *msg = strip_info->sx_buff; ! int len = strip_info->sx_count; ! ! /* Check for anything that looks like it might be our radio name */ ! /* (This is here for backwards compatibility with old firmware) */ ! if (len == 9 && get_radio_address(strip_info, msg) == 0) return; ! ! if (text_equal(msg, len, "OK" )) return; /* Ignore 'OK' responses from prior commands */ ! if (text_equal(msg, len, "ERROR" )) return; /* Ignore 'ERROR' messages */ ! if (text_equal(msg, len, InitString)) return; /* Ignore character echo back from the radio */ ! ! /* Catch other error messages */ ! /* (This is here for backwards compatibility with old firmware) */ ! if (has_prefix(msg, "ERR_")) { RecvErr_Message(strip_info, NULL, &msg[4]); return; } ! ! RecvErr("No initial *", strip_info); ! } ! ! /* ! * process_message processes a -terminated block of data received ! * from the radio. If the radio is not in Starmode or has old firmware, ! * it may be a line of text in response to an AT command. Ideally, with ! * a current radio that's properly in Starmode, all data received should ! * be properly framed and checksummed radio message blocks, containing ! * either a starmode packet, or a other communication from the radio ! * firmware, like "INF_" Info messages and &COMMAND responses. ! */ ! static void process_message(struct strip *strip_info) { STRIP_Header header = { zero_address, zero_address, 0 }; __u8 *ptr = strip_info->sx_buff; *************** *** 2125,2153 **** __u8 sendername[32], *sptr = sendername; MetricomKey key; - /* Ignore 'OK' responses from prior commands */ - if (strip_info->sx_count == 2 && ptr[0] == 'O' && ptr[1] == 'K') return; - - /* Check for anything that looks like it might be our radio name: dddd-dddd */ - /* (This is here for backwards compatibility with old firmware) */ - if (strip_info->sx_count == 9 && IS_RADIO_ADDRESS(ptr)) - { - get_radio_address(strip_info, ptr); - return; - } - /*HexDump("Receiving", strip_info, ptr, end);*/ /* Check for start of address marker, and then skip over it */ ! if (*ptr != '*') ! { ! /* Catch other error messages */ ! if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_') ! RecvErr_Message(strip_info, NULL, &ptr[4]); ! else RecvErr("No initial *", strip_info); ! return; ! } ! ptr++; /* Skip the initial '*' */ /* Copy out the return address */ while (ptr < end && *ptr != '*' && sptr < ARRAY_END(sendername)-1) *sptr++ = *ptr++; --- 2099,2109 ---- __u8 sendername[32], *sptr = sendername; MetricomKey key; /*HexDump("Receiving", strip_info, ptr, end);*/ /* Check for start of address marker, and then skip over it */ ! if (*ptr == '*') ptr++; ! else { process_text_message(strip_info); return; } /* Copy out the return address */ while (ptr < end && *ptr != '*' && sptr < ARRAY_END(sendername)-1) *sptr++ = *ptr++; *************** *** 2165,2180 **** /* (This is here for backwards compatibility with old firmware) */ if (!strcmp(sendername, "&COMMAND")) { ! strip_info->structured_messages = FALSE; return; } ! if (ptr+4 >= end) { RecvErr("No proto key", strip_info); return; } /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev.name, sendername);*/ /* --- 2121,2159 ---- /* (This is here for backwards compatibility with old firmware) */ if (!strcmp(sendername, "&COMMAND")) { ! strip_info->firmware_level = NoStructure; ! strip_info->next_command = CompatibilityCommand; return; } ! if (ptr+4 > end) { RecvErr("No proto key", strip_info); return; } + /* Get the protocol key out of the buffer */ + key.c[0] = *ptr++; + key.c[1] = *ptr++; + key.c[2] = *ptr++; + key.c[3] = *ptr++; + + /* If we're using checksums, verify the checksum at the end of the packet */ + if (strip_info->firmware_level >= ChecksummedMessages) + { + end -= 4; /* Chop the last four bytes off the packet (they're the checksum) */ + if (ptr > end) + { + RecvErr("Missing Checksum", strip_info); + return; + } + if (!verify_checksum(strip_info)) + { + RecvErr("Bad Checksum", strip_info); + return; + } + } + /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev.name, sendername);*/ /* *************** *** 2182,2219 **** * We assume that the destination address was our address (the radio does not * tell us this). If the radio supplies a source address, then we use it. */ ! memcpy(&header.dst_addr, strip_info->dev.dev_addr, sizeof(MetricomAddress)); ! if (IS_RADIO_ADDRESS(sendername)) string_to_radio_address(&header.src_addr, sendername); ! /* Get the protocol key out of the buffer */ ! key.c[0] = *ptr++; ! key.c[1] = *ptr++; ! key.c[2] = *ptr++; ! key.c[3] = *ptr++; ! ! if (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end); ! else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end); else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end); ! else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr); ! else /* RecvErr("Unrecognized protocol key", strip_info); */ ! ! /* Note, this "else" block is temporary, until Metricom fix their */ ! /* packet corruption bug */ ! { ! RecvErr("Unrecognized protocol key (retrying)", strip_info); ! ptr -= 3; /* Back up and try again */ ! key.c[0] = *ptr++; ! key.c[1] = *ptr++; ! key.c[2] = *ptr++; ! key.c[3] = *ptr++; ! if (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end); ! else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end); ! else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end); ! else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr); ! else RecvErr("Unrecognized protocol key", strip_info); ! } } /* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when --- 2161,2205 ---- * We assume that the destination address was our address (the radio does not * tell us this). If the radio supplies a source address, then we use it. */ ! header.dst_addr = strip_info->true_dev_addr; ! string_to_radio_address(&header.src_addr, sendername); ! #ifdef EXT_COUNTERS ! if (key.l == SIP0Key.l) { ! strip_info->rx_rbytes += (end - ptr); ! process_IP_packet(strip_info, &header, ptr, end); ! } else if (key.l == ARP0Key.l) { ! strip_info->rx_rbytes += (end - ptr); ! process_ARP_packet(strip_info, &header, ptr, end); ! } else if (key.l == ATR_Key.l) { ! strip_info->rx_ebytes += (end - ptr); ! process_AT_response(strip_info, ptr, end); ! } else if (key.l == ACK_Key.l) { ! strip_info->rx_ebytes += (end - ptr); ! process_ACK(strip_info, ptr, end); ! } else if (key.l == INF_Key.l) { ! strip_info->rx_ebytes += (end - ptr); ! process_Info(strip_info, ptr, end); ! } else if (key.l == ERR_Key.l) { ! strip_info->rx_ebytes += (end - ptr); ! RecvErr_Message(strip_info, sendername, ptr); ! } else RecvErr("Unrecognized protocol key", strip_info); ! #else ! if (key.l == SIP0Key.l) process_IP_packet (strip_info, &header, ptr, end); ! else if (key.l == ARP0Key.l) process_ARP_packet (strip_info, &header, ptr, end); else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end); ! else if (key.l == ACK_Key.l) process_ACK (strip_info, ptr, end); ! else if (key.l == INF_Key.l) process_Info (strip_info, ptr, end); ! else if (key.l == ERR_Key.l) RecvErr_Message (strip_info, sendername, ptr); ! else RecvErr("Unrecognized protocol key", strip_info); ! #endif } + #define TTYERROR(X) ((X) == TTY_BREAK ? "Break" : \ + (X) == TTY_FRAME ? "Framing Error" : \ + (X) == TTY_PARITY ? "Parity Error" : \ + (X) == TTY_OVERRUN ? "Hardware Overrun" : "Unknown Error") + /* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when *************** *** 2238,2254 **** { struct timeval tv; do_gettimeofday(&tv); ! printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %d.%06d\n", count, tv.tv_sec % 100, tv.tv_usec); } #endif /* Read the characters out of the buffer */ while (cp < end) { if (fp && *fp++ && !strip_info->discard) /* If there's a serial error, record it */ { ! strip_info->discard = 1; strip_info->rx_errors++; } --- 2224,2246 ---- { struct timeval tv; do_gettimeofday(&tv); ! printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %02d.%06d\n", count, tv.tv_sec % 100, tv.tv_usec); } #endif + #ifdef EXT_COUNTERS + strip_info->rx_sbytes += count; + #endif + /* Read the characters out of the buffer */ while (cp < end) { + if (fp && *fp) printk(KERN_INFO "%s: %s on serial port\n", strip_info->dev.name, TTYERROR(*fp)); if (fp && *fp++ && !strip_info->discard) /* If there's a serial error, record it */ { ! /* If we have some characters in the buffer, discard them */ ! strip_info->discard = strip_info->sx_count; strip_info->rx_errors++; } *************** *** 2258,2278 **** if (*cp == 0x0D) /* If end of packet, decide what to do with it */ { if (strip_info->sx_count > 3000) ! printk(KERN_INFO "Cut a %d byte packet (%d bytes remaining)%s\n", ! strip_info->sx_count, end-cp-1, strip_info->discard ? " (discarded)" : ""); if (strip_info->sx_count > strip_info->sx_size) { - strip_info->discard = 1; strip_info->rx_over_errors++; printk(KERN_INFO "%s: sx_buff overflow (%d bytes total)\n", strip_info->dev.name, strip_info->sx_count); } ! if (!strip_info->discard) process_packet(strip_info); strip_info->discard = 0; strip_info->sx_count = 0; } ! else if (!strip_info->discard) /* If we're not discarding, store the character */ { /* Make sure we have space in the buffer */ if (strip_info->sx_count < strip_info->sx_size) --- 2250,2272 ---- if (*cp == 0x0D) /* If end of packet, decide what to do with it */ { if (strip_info->sx_count > 3000) ! printk(KERN_INFO "%s: Cut a %d byte packet (%d bytes remaining)%s\n", ! strip_info->dev.name, strip_info->sx_count, end-cp-1, strip_info->discard ? " (discarded)" : ""); if (strip_info->sx_count > strip_info->sx_size) { strip_info->rx_over_errors++; printk(KERN_INFO "%s: sx_buff overflow (%d bytes total)\n", strip_info->dev.name, strip_info->sx_count); } ! else if (strip_info->discard) ! printk(KERN_INFO "%s: Discarding bad packet (%d/%d)\n", ! strip_info->dev.name, strip_info->discard, strip_info->sx_count); ! else process_message(strip_info); strip_info->discard = 0; strip_info->sx_count = 0; } ! else { /* Make sure we have space in the buffer */ if (strip_info->sx_count < strip_info->sx_size) *************** *** 2288,2296 **** /************************************************************************/ /* General control routines */ ! static int strip_set_dev_mac_address(struct device *dev, void *addr) { ! return -1; /* You cannot override a Metricom radio's address */ } static struct enet_statistics *strip_get_stats(struct device *dev) --- 2282,2309 ---- /************************************************************************/ /* General control routines */ ! static int set_mac_address(struct strip *strip_info, MetricomAddress *addr) ! { ! /* ! * We're using a manually specified address if the address is set ! * to anything other than all ones. Setting the address to all ones ! * disables manual mode and goes back to automatic address determination ! * (tracking the true address that the radio has). ! */ ! strip_info->manual_dev_addr = memcmp(addr->c, broadcast_address.c, sizeof(broadcast_address)); ! if (strip_info->manual_dev_addr) ! *(MetricomAddress*)strip_info->dev.dev_addr = *addr; ! else *(MetricomAddress*)strip_info->dev.dev_addr = strip_info->true_dev_addr; ! return 0; ! } ! ! static int dev_set_mac_address(struct device *dev, void *addr) { ! struct strip *strip_info = (struct strip *)(dev->priv); ! struct sockaddr *sa = addr; ! printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name); ! set_mac_address(strip_info, (MetricomAddress *)sa->sa_data); ! return 0; } static struct enet_statistics *strip_get_stats(struct device *dev) *************** *** 2348,2359 **** if (!allocate_buffers(strip_info)) return(-ENOMEM); - strip_info->discard = 0; - strip_info->working = FALSE; - strip_info->structured_messages = FALSE; strip_info->sx_count = 0; strip_info->tx_left = 0; /* * Needed because address '0' is special */ --- 2361,2374 ---- if (!allocate_buffers(strip_info)) return(-ENOMEM); strip_info->sx_count = 0; strip_info->tx_left = 0; + strip_info->discard = 0; + strip_info->working = FALSE; + strip_info->firmware_level = NoStructure; + strip_info->next_command = CompatibilityCommand; + /* * Needed because address '0' is special */ *************** *** 2460,2466 **** dev->rebuild_header = strip_rebuild_header; /* dev->type_trans unused */ /* dev->set_multicast_list unused */ ! dev->set_mac_address = strip_set_dev_mac_address; /* dev->do_ioctl unused */ /* dev->set_config unused */ dev->get_stats = strip_get_stats; --- 2475,2481 ---- dev->rebuild_header = strip_rebuild_header; /* dev->type_trans unused */ /* dev->set_multicast_list unused */ ! dev->set_mac_address = dev_set_mac_address; /* dev->do_ioctl unused */ /* dev->set_config unused */ dev->get_stats = strip_get_stats; *************** *** 2473,2491 **** static void strip_free(struct strip *strip_info) { - MetricomNode *node, *free; - *(strip_info->referrer) = strip_info->next; if (strip_info->next) strip_info->next->referrer = strip_info->referrer; strip_info->magic = 0; - - for (node = strip_info->neighbor_list; node != NULL; ) - { - free = node; - node = node->next; - kfree(free); - } kfree(strip_info); } --- 2488,2497 ---- *************** *** 2540,2552 **** strip_info->idle_timer.data = (long)&strip_info->dev; strip_info->idle_timer.function = strip_IdleTask; - strip_info->neighbor_list = kmalloc(sizeof(MetricomNode), GFP_KERNEL); - strip_info->neighbor_list->type = 0; - strip_info->neighbor_list->next = NULL; - /* Note: strip_info->if_name is currently 8 characters long */ ! sprintf(strip_info->if_name, "st%d", channel_id); ! strip_info->dev.name = strip_info->if_name; strip_info->dev.base_addr = channel_id; strip_info->dev.priv = (void*)strip_info; strip_info->dev.next = NULL; --- 2546,2554 ---- strip_info->idle_timer.data = (long)&strip_info->dev; strip_info->idle_timer.function = strip_IdleTask; /* Note: strip_info->if_name is currently 8 characters long */ ! sprintf(strip_info->if_name.c, "st%d", channel_id); ! strip_info->dev.name = strip_info->if_name.c; strip_info->dev.base_addr = channel_id; strip_info->dev.priv = (void*)strip_info; strip_info->dev.next = NULL; *************** *** 2616,2621 **** --- 2618,2626 ---- #ifdef MODULE MOD_INC_USE_COUNT; #endif + + printk(KERN_INFO "STRIP: device \"%s\" activated\n", strip_info->if_name.c); + /* * Done. We have linked the TTY line to a channel. */ *************** *** 2645,2650 **** --- 2650,2656 ---- tty->disc_data = 0; strip_info->tty = NULL; + printk(KERN_INFO "STRIP: device \"%s\" closed down\n", strip_info->if_name.c); strip_free(strip_info); tty->disc_data = NULL; #ifdef MODULE *************** *** 2680,2686 **** return 0; case SIOCSIFHWADDR: ! return -EINVAL; /* * Allow stty to read, but not set, the serial port --- 2686,2699 ---- return 0; case SIOCSIFHWADDR: ! { ! MetricomAddress addr; ! printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev.name); ! err = verify_area(VERIFY_READ, (void*)arg, sizeof(MetricomAddress)); ! if (err) return -err; ! memcpy_fromfs(&addr, (void*)arg, sizeof(MetricomAddress)); ! return(set_mac_address(strip_info, &addr)); ! } /* * Allow stty to read, but not set, the serial port *************** *** 2701,2732 **** /* Initialization */ /* - * Registers with the /proc file system to create different /proc/net files. - */ - - static int strip_proc_net_register(unsigned short type, char *file_name, - int (*get_info)(char *, char **, off_t, int, int)) - { - struct proc_dir_entry *strip_entry; - - strip_entry = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); - - memset(strip_entry, 0, sizeof(struct proc_dir_entry)); - strip_entry->low_ino = type; - strip_entry->namelen = strlen(file_name); - strip_entry->name = file_name; - strip_entry->mode = S_IFREG | S_IRUGO; - strip_entry->nlink = 1; - strip_entry->uid = 0; - strip_entry->gid = 0; - strip_entry->size = 0; - strip_entry->ops = &proc_net_inode_operations; - strip_entry->get_info = get_info; - - return proc_net_register(strip_entry); - } - - /* * Initialize the STRIP driver. * This routine is called at boot time, to bootstrap the multi-channel * STRIP driver --- 2714,2719 ---- *************** *** 2740,2746 **** static struct tty_ldisc strip_ldisc; int status; ! printk("STRIP: version %s (unlimited channels)\n", StripVersion); /* * Fill in our line protocol discipline, and register it --- 2727,2733 ---- static struct tty_ldisc strip_ldisc; int status; ! printk(KERN_INFO "STRIP: Version %s (unlimited channels)\n", StripVersion); /* * Fill in our line protocol discipline, and register it *************** *** 2765,2788 **** } /* ! * Register the status and trace files with /proc */ ! ! #if DO_PROC_NET_STRIP_STATUS ! if (strip_proc_net_register(PROC_NET_STRIP_STATUS, "strip_status", ! &strip_get_status_info) != 0) { ! printk(KERN_ERR "strip: status strip_proc_net_register() failed.\n"); } - #endif - - #if DO_PROC_NET_STRIP_TRACE - if (strip_proc_net_register(PROC_NET_STRIP_TRACE, "strip_trace", - &strip_get_trace_info) != 0) - { - printk(KERN_ERR "strip: trace strip_proc_net_register() failed.\n"); - } - #endif #ifdef MODULE return status; --- 2752,2763 ---- } /* ! * Register the status file with /proc */ ! if (proc_net_register(&proc_strip_get_status_info) != 0) { ! printk(KERN_ERR "strip: status proc_net_register() failed.\n"); } #ifdef MODULE return status; *************** *** 2812,2827 **** while (struct_strip_list) strip_free(struct_strip_list); ! /* Unregister with the /proc/net files here. */ ! ! #if DO_PROC_NET_STRIP_TRACE ! proc_net_unregister(PROC_NET_STRIP_TRACE); ! #endif ! #if DO_PROC_NET_STRIP_STATUS proc_net_unregister(PROC_NET_STRIP_STATUS); - #endif if ((i = tty_register_ldisc(N_STRIP, NULL))) printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); } #endif /* MODULE */ --- 2787,2798 ---- while (struct_strip_list) strip_free(struct_strip_list); ! /* Unregister with the /proc/net file here. */ proc_net_unregister(PROC_NET_STRIP_STATUS); if ((i = tty_register_ldisc(N_STRIP, NULL))) printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); + + printk(KERN_INFO "STRIP: Module Unloaded\n"); } #endif /* MODULE */ Only in linux-2.0.30.strip.iw/drivers/net: strip.c.orig diff -rc linux/include/asm-i386/irq.h linux-2.0.30.strip.iw/include/asm-i386/irq.h *** linux/include/asm-i386/irq.h Wed Mar 5 11:20:45 1997 --- linux-2.0.30.strip.iw/include/asm-i386/irq.h Sun Jun 29 23:50:44 1997 *************** *** 73,80 **** "popl %edx\n\t" \ "popl %eax\n\t" \ "pop %ds\n\t" \ ! "pop %es\n\t" \ ! "iret" /* * The "inb" instructions are not needed, but seem to change the timings --- 73,79 ---- "popl %edx\n\t" \ "popl %eax\n\t" \ "pop %ds\n\t" \ ! "pop %es\n\t" /* * The "inb" instructions are not needed, but seem to change the timings *************** *** 127,132 **** --- 126,132 ---- #define IRQ_NAME2(nr) nr##_interrupt(void) #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) #define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr) + #define ADAPTIVE_IRQ_NAME(nr) IRQ_NAME2(adaptive_IRQ##nr) #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) #ifdef __SMP__ *************** *** 200,205 **** --- 200,206 ---- #define BUILD_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ + asmlinkage void ADAPTIVE_IRQ_NAME(nr); \ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ *************** *** 209,214 **** --- 210,216 ---- ENTER_KERNEL \ ACK_##chip(mask,(nr&7)) \ "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ + "movl $100+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "sti\n\t" \ "movl %esp,%ebx\n\t" \ "pushl %ebx\n\t" \ *************** *** 219,224 **** --- 221,227 ---- UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ *************** *** 232,255 **** "cli\n\t" \ UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ LEAVE_KERNEL \ RESTORE_MOST \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ ENTER_KERNEL \ ACK_##chip(mask,(nr&7)) \ LEAVE_KERNEL \ ! RESTORE_MOST); #define BUILD_TIMER_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ --- 235,294 ---- "cli\n\t" \ UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ LEAVE_KERNEL \ RESTORE_MOST \ + "iret" \ + "\n"__ALIGN_STR"\n" \ + SYMBOL_NAME_STR(adaptive_IRQ) #nr "_interrupt:\n\t" \ + SAVE_MOST \ + ENTER_KERNEL \ + ACK_##chip(mask,(nr&7)) \ + "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "pushl $" #nr "\n\t" \ + "call "SYMBOL_NAME_STR(do_adaptive_IRQ)"\n\t" \ + "addl $4,%esp\n\t" \ + "cli\n\t" \ + "testl %eax,%eax\n\t" \ + "jne "SYMBOL_NAME_STR(adaptive_IRQ) #nr "_sys_call_return\n\t" \ + UNBLK_##chip(mask) \ + "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ + LEAVE_KERNEL \ + RESTORE_MOST \ + "iret" \ + "\n"__ALIGN_STR"\n" \ + SYMBOL_NAME_STR(adaptive_IRQ) #nr "_sys_call_return:\n\t" \ + UNBLK_##chip(mask) \ + "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + LEAVE_KERNEL \ + RESTORE_MOST \ + "pushl $-"#nr"-2\n\t" \ + SAVE_ALL \ + ENTER_KERNEL \ + "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ + "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ ENTER_KERNEL \ ACK_##chip(mask,(nr&7)) \ + "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ LEAVE_KERNEL \ ! RESTORE_MOST \ ! "iret"); #define BUILD_TIMER_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ + asmlinkage void ADAPTIVE_IRQ_NAME(nr); \ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ + SYMBOL_NAME_STR(adaptive_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ *************** *** 266,281 **** --- 305,324 ---- UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "jmp ret_from_sys_call\n"); /* * Message pass must be a fast IRQ.. + * (In light of the above comment, for now I've make adaptive IRQ + * just be the same as fast IRQ -- Stuart Cheshire) */ #define BUILD_MSGIRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ + asmlinkage void ADAPTIVE_IRQ_NAME(nr); \ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ *************** *** 285,290 **** --- 328,334 ---- ENTER_KERNEL \ ACK_##chip(mask,(nr&7)) \ "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ + "movl $100+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "sti\n\t" \ "movl %esp,%ebx\n\t" \ "pushl %ebx\n\t" \ *************** *** 297,302 **** --- 341,347 ---- "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" \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ *************** *** 308,319 **** "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" \ SAVE_MOST \ ACK_##chip(mask,(nr&7)) \ ! RESTORE_MOST); #define BUILD_RESCHEDIRQ(nr) \ asmlinkage void IRQ_NAME(nr); \ --- 353,381 ---- "addl $4,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ + "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ RESTORE_MOST \ + "iret" \ + "\n"__ALIGN_STR"\n" \ + SYMBOL_NAME_STR(adaptive_IRQ) #nr "_interrupt:\n\t" \ + SAVE_MOST \ + ACK_##chip(mask,(nr&7)) \ + SMP_PROF_IPI_CNT \ + "pushl $" #nr "\n\t" \ + "call "SYMBOL_NAME_STR(do_adaptive_IRQ)"\n\t" \ + "addl $4,%esp\n\t" \ + "cli\n\t" \ + UNBLK_##chip(mask) \ + "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ + RESTORE_MOST \ + "iret" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ ACK_##chip(mask,(nr&7)) \ ! "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ ! RESTORE_MOST \ ! "iret"); #define BUILD_RESCHEDIRQ(nr) \ asmlinkage void IRQ_NAME(nr); \ *************** *** 324,329 **** --- 386,392 ---- SAVE_ALL \ ENTER_KERNEL \ "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ + "movl $100+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "sti\n\t" \ "movl %esp,%ebx\n\t" \ "pushl %ebx\n\t" \ *************** *** 333,344 **** --- 396,409 ---- "cli\n\t" \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "jmp ret_from_sys_call\n"); #else #define BUILD_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ + asmlinkage void ADAPTIVE_IRQ_NAME(nr); \ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ *************** *** 347,352 **** --- 412,418 ---- SAVE_ALL \ ACK_##chip(mask,(nr&7)) \ "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ + "movl $100+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "sti\n\t" \ "movl %esp,%ebx\n\t" \ "pushl %ebx\n\t" \ *************** *** 356,361 **** --- 422,428 ---- "cli\n\t" \ UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ *************** *** 368,387 **** "cli\n\t" \ UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ RESTORE_MOST \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ ACK_##chip(mask,(nr&7)) \ ! RESTORE_MOST); #define BUILD_TIMER_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ --- 435,485 ---- "cli\n\t" \ UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ RESTORE_MOST \ + "iret" \ + "\n"__ALIGN_STR"\n" \ + SYMBOL_NAME_STR(adaptive_IRQ) #nr "_interrupt:\n\t" \ + SAVE_MOST \ + ACK_##chip(mask,(nr&7)) \ + "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "pushl $" #nr "\n\t" \ + "call "SYMBOL_NAME_STR(do_adaptive_IRQ)"\n\t" \ + "addl $4,%esp\n\t" \ + "cli\n\t" \ + "testl %eax,%eax\n\t" \ + "jne "SYMBOL_NAME_STR(adaptive_IRQ) #nr "_sys_call_return\n\t" \ + UNBLK_##chip(mask) \ + "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ + RESTORE_MOST \ + "iret" \ + "\n"__ALIGN_STR"\n" \ + SYMBOL_NAME_STR(adaptive_IRQ) #nr "_sys_call_return:\n\t" \ + UNBLK_##chip(mask) \ + "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + RESTORE_MOST \ + "pushl $-"#nr"-2\n\t" \ + SAVE_ALL \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ + "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ ACK_##chip(mask,(nr&7)) \ ! "movl $200+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ ! RESTORE_MOST \ ! "iret"); #define BUILD_TIMER_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ + asmlinkage void ADAPTIVE_IRQ_NAME(nr); \ asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ + SYMBOL_NAME_STR(adaptive_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ *************** *** 396,401 **** --- 494,500 ---- "cli\n\t" \ UNBLK_##chip(mask) \ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ + "movl $300+" #nr "," SYMBOL_NAME_STR(serial_oe_last_interrupt) "\n\t" \ "jmp ret_from_sys_call\n"); #endif Only in linux-2.0.30.strip.iw/include/asm-i386: irq.h.orig diff -rc linux/include/asm-i386/signal.h linux-2.0.30.strip.iw/include/asm-i386/signal.h *** linux/include/asm-i386/signal.h Wed Jul 17 05:10:03 1996 --- linux-2.0.30.strip.iw/include/asm-i386/signal.h Sun Jun 29 23:50:44 1997 *************** *** 53,58 **** --- 53,59 ---- * SA_SHIRQ flag is for shared interrupt support on PCI and EISA. */ #define SA_NOCLDSTOP 1 + #define SA_ADAPTIVE 0x02000000 #define SA_SHIRQ 0x04000000 #define SA_STACK 0x08000000 #define SA_RESTART 0x10000000 Only in linux-2.0.30.strip.iw/include/asm-i386: signal.h.orig diff -rc linux/include/asm-i386/socket.h linux-2.0.30.strip.iw/include/asm-i386/socket.h *** linux/include/asm-i386/socket.h Sun Mar 24 02:47:39 1996 --- linux-2.0.30.strip.iw/include/asm-i386/socket.h Sun Jun 29 23:54:14 1997 *************** *** 22,25 **** --- 22,27 ---- #define SO_BSDCOMPAT 14 /* To add :#define SO_REUSEPORT 15 */ + #define SO_BINDTODEVICE 25 + #endif /* _ASM_SOCKET_H */ Only in linux-2.0.30.strip.iw/include/asm-i386: socket.h.orig diff -rc linux/include/asm-i386/system.h linux-2.0.30.strip.iw/include/asm-i386/system.h *** linux/include/asm-i386/system.h Mon Mar 17 15:00:50 1997 --- linux-2.0.30.strip.iw/include/asm-i386/system.h Mon Jun 30 00:12:15 1997 *************** *** 3,8 **** --- 3,41 ---- #include + #define INTERRUPT_WATCHDOG 0 + + #if INTERRUPT_WATCHDOG + + #define sti_record_mark() \ + do { \ + serial_oe_last_line = __LINE__; \ + serial_oe_last_file = __FILE__; \ + serial_oe_last_base = __BASE_FILE__; \ + } while(0) + + #define sti_clear_mark() \ + do { \ + volatile int i,j=0; \ + for (i=0; i<100; i++) j+=i; \ + serial_oe_last_line = -j; \ + serial_oe_last_line = 0; \ + serial_oe_last_file = "Not set"; \ + serial_oe_last_base = ""; \ + } while(0) + + #else + + #define sti_record_mark() + #define sti_clear_mark() + + #endif + + extern volatile int serial_oe_last_line; + extern volatile char *serial_oe_last_file; + extern volatile char *serial_oe_last_base; + extern volatile int serial_oe_last_interrupt; + /* * Entry into gdt where to find first TSS. GDT layout: * 0 - null *************** *** 77,82 **** --- 110,116 ---- prev->lock_depth=syscall_count; \ kernel_counter+=next->lock_depth-prev->lock_depth; \ syscall_count=next->lock_depth; \ + sti_record_mark(); \ __asm__("pushl %%edx\n\t" \ "movl "SYMBOL_NAME_STR(apic_reg)",%%edx\n\t" \ "movl 0x20(%%edx), %%edx\n\t" \ *************** *** 89,94 **** --- 123,129 ---- : /* no output */ \ :"m" (*(((char *)&next->tss.tr)-4)), \ "c" (next)); \ + sti_clear_mark(); \ /* Now maybe reload the debug registers */ \ if(prev->debugreg[7]){ \ loaddebug(prev,0); \ *************** *** 221,236 **** } #define mb() __asm__ __volatile__ ("" : : :"memory") ! #define sti() __asm__ __volatile__ ("sti": : :"memory") #define cli() __asm__ __volatile__ ("cli": : :"memory") #define save_flags(x) \ __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory") #define restore_flags(x) \ ! __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") ! ! #define iret() __asm__ __volatile__ ("iret": : :"memory") #define _set_gate(gate_addr,type,dpl,addr) \ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ --- 256,291 ---- } #define mb() __asm__ __volatile__ ("" : : :"memory") ! #define sti() \ ! do { \ ! sti_record_mark(); \ ! __asm__ __volatile__ ("sti": : :"memory"); \ ! sti_clear_mark(); \ ! } while(0) #define cli() __asm__ __volatile__ ("cli": : :"memory") #define save_flags(x) \ __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory") + /* + * If this restore_flags is actually going to enable interrupts, then record + * our mark. If it's just restoring flags to an interrupt-disabled state, + * then leave the watchdog mark alone + */ #define restore_flags(x) \ ! if (x & 0x00000200) \ ! { \ ! sti_record_mark(); \ ! __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory"); \ ! sti_clear_mark(); \ ! } \ ! else __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") ! ! #define iret() \ ! do { \ ! sti_record_mark(); \ ! __asm__ __volatile__ ("iret": : :"memory"); \ ! } while(0) #define _set_gate(gate_addr,type,dpl,addr) \ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ Only in linux-2.0.30.strip.iw/include/asm-i386: system.h.orig diff -rc linux/include/linux/route.h linux-2.0.30.strip.iw/include/linux/route.h *** linux/include/linux/route.h Tue Oct 8 09:48:40 1996 --- linux-2.0.30.strip.iw/include/linux/route.h Sun Jun 29 23:54:14 1997 *************** *** 52,57 **** --- 52,58 ---- #define RTF_WINDOW 0x0080 /* per route window clamping */ #define RTF_IRTT 0x0100 /* Initial round trip time */ #define RTF_REJECT 0x0200 /* Reject route */ + #define RTF_NOTCACHED 0x0400 /* this route isn't cached */ /* * This structure is passed from the kernel to user space by netlink Only in linux-2.0.30.strip.iw/include/linux: route.h.orig diff -rc linux/include/linux/sched.h linux-2.0.30.strip.iw/include/linux/sched.h *** linux/include/linux/sched.h Fri Mar 28 16:08:17 1997 --- linux-2.0.30.strip.iw/include/linux/sched.h Sun Jun 29 23:50:45 1997 *************** *** 347,352 **** --- 347,359 ---- extern int send_sig(unsigned long sig,struct task_struct * p,int priv); extern int in_group_p(gid_t grp); + typedef void DumbInterruptHandler(int, void *dev_id, struct pt_regs *regs); + typedef enum { FAST_RETURN = 0, SYSCALL_RETURN = 1 } irq_return; + typedef irq_return AdaptiveInterruptHandler(int, void *dev_id, struct pt_regs *regs); + #define request_adaptive_irq(I,H,F,D,ID) \ + request_irq((I),((DumbInterruptHandler*)(H)),\ + ((F) & ~ SA_INTERRUPT) | SA_ADAPTIVE,(D),(ID)) + extern int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, Only in linux-2.0.30.strip.iw/include/linux: sched.h.orig diff -rc linux/include/linux/skbuff.h linux-2.0.30.strip.iw/include/linux/skbuff.h *** linux/include/linux/skbuff.h Fri Mar 28 16:08:27 1997 --- linux-2.0.30.strip.iw/include/linux/skbuff.h Sun Jun 29 23:53:20 1997 *************** *** 95,100 **** --- 95,101 ---- localroute, /* Local routing asserted for this frame */ pkt_type, /* Packet class */ pkt_bridged, /* Tracker for bridging */ + ptype_all_flag, /* Set if skb already handed to ptype_all list */ ip_summed; /* Driver fed us an IP checksum */ #define PACKET_HOST 0 /* To us */ #define PACKET_BROADCAST 1 /* To all */ Only in linux-2.0.30.strip.iw/include/linux: skbuff.h.orig diff -rc linux/include/net/route.h linux-2.0.30.strip.iw/include/net/route.h *** linux/include/net/route.h Fri Mar 28 16:10:57 1997 --- linux-2.0.30.strip.iw/include/net/route.h Sun Jun 29 23:54:15 1997 *************** *** 13,18 **** --- 13,19 ---- * Alan Cox : Reformatted. Added ip_rt_local() * Alan Cox : Support for TCP parameters. * Alexey Kuznetsov: Major changes for new routing code. + * Elliot Poger : Added support for SO_BINDTODEVICE. * * FIXME: * Make atomic ops more generic and hide them in asm/... *************** *** 83,89 **** extern void ip_rt_flush(struct device *dev); extern void ip_rt_update(int event, struct device *dev); extern void ip_rt_redirect(__u32 src, __u32 dst, __u32 gw, struct device *dev); ! extern struct rtable *ip_rt_slow_route(__u32 daddr, int local); extern int rt_get_info(char * buffer, char **start, off_t offset, int length, int dummy); extern int rt_cache_get_info(char *buffer, char **start, off_t offset, int length, int dummy); extern int ip_rt_ioctl(unsigned int cmd, void *arg); --- 84,90 ---- extern void ip_rt_flush(struct device *dev); extern void ip_rt_update(int event, struct device *dev); extern void ip_rt_redirect(__u32 src, __u32 dst, __u32 gw, struct device *dev); ! extern struct rtable *ip_rt_slow_route(__u32 daddr, int local, struct device *dev); extern int rt_get_info(char * buffer, char **start, off_t offset, int length, int dummy); extern int rt_cache_get_info(char *buffer, char **start, off_t offset, int length, int dummy); extern int ip_rt_ioctl(unsigned int cmd, void *arg); *************** *** 131,139 **** #endif #ifdef CONFIG_KERNELD ! extern struct rtable * ip_rt_route(__u32 daddr, int local); #else ! extern __inline__ struct rtable * ip_rt_route(__u32 daddr, int local) #ifndef MODULE { struct rtable * rth; --- 132,140 ---- #endif #ifdef CONFIG_KERNELD ! extern struct rtable * ip_rt_route(__u32 daddr, int local, struct device *dev); #else ! extern __inline__ struct rtable * ip_rt_route(__u32 daddr, int local, struct device *dev) #ifndef MODULE { struct rtable * rth; *************** *** 142,148 **** for (rth=ip_rt_hash_table[ip_rt_hash_code(daddr)^local]; rth; rth=rth->rt_next) { ! if (rth->rt_dst == daddr) { rth->rt_lastuse = jiffies; atomic_inc(&rth->rt_use); --- 143,150 ---- for (rth=ip_rt_hash_table[ip_rt_hash_code(daddr)^local]; rth; rth=rth->rt_next) { ! /* If an interface is specified, make sure this route points to it. */ ! if ( (rth->rt_dst == daddr) && ((dev==NULL) || (dev==rth->rt_dev)) ) { rth->rt_lastuse = jiffies; atomic_inc(&rth->rt_use); *************** *** 151,173 **** return rth; } } ! return ip_rt_slow_route (daddr, local); } #else ; #endif #endif ! extern __inline__ struct rtable * ip_check_route(struct rtable ** rp, ! __u32 daddr, int local) { struct rtable * rt = *rp; ! if (!rt || rt->rt_dst != daddr || !(rt->rt_flags&RTF_UP) || ((local==1)^((rt->rt_flags&RTF_LOCAL) != 0))) { ip_rt_put(rt); ! rt = ip_rt_route(daddr, local); *rp = rt; } return rt; --- 153,175 ---- return rth; } } ! return ip_rt_slow_route (daddr, local, dev); } #else ; #endif #endif ! extern __inline__ struct rtable * ip_check_route(struct rtable ** rp, __u32 daddr, ! int local, struct device *dev) { struct rtable * rt = *rp; ! if (!rt || rt->rt_dst != daddr || !(rt->rt_flags&RTF_UP) || (dev!=NULL) || ((local==1)^((rt->rt_flags&RTF_LOCAL) != 0))) { ip_rt_put(rt); ! rt = ip_rt_route(daddr, local, dev); *rp = rt; } return rt; Only in linux-2.0.30.strip.iw/include/net: route.h.orig diff -rc linux/include/net/sock.h linux-2.0.30.strip.iw/include/net/sock.h *** linux/include/net/sock.h Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/include/net/sock.h Sun Jun 29 23:54:15 1997 *************** *** 23,28 **** --- 23,29 ---- * Pauline Middelink : identd support * Alan Cox : Eliminate low level recv/recvfrom * David S. Miller : New socket lookup architecture for ISS. + * Elliot Poger : New field for SO_BINDTODEVICE option. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License *************** *** 192,197 **** --- 193,199 ---- broadcast, nonagle, bsdism; + struct device * bound_device; unsigned long lingertime; int proc; Only in linux-2.0.30.strip.iw/include/net: sock.h.orig diff -rc linux/ipc/msg.c linux-2.0.30.strip.iw/ipc/msg.c *** linux/ipc/msg.c Sat Aug 31 23:15:33 1996 --- linux-2.0.30.strip.iw/ipc/msg.c Sun Jun 29 23:52:00 1997 *************** *** 78,84 **** msq->msg_first = msq->msg_last = NULL; restore_flags(flags); if (flushed) ! printk(KERN_WARNING "flushed %d old SYSVIPC messages", flushed); } static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) --- 78,84 ---- msq->msg_first = msq->msg_last = NULL; restore_flags(flags); if (flushed) ! printk(KERN_WARNING "flushed %d old SYSVIPC messages\n", flushed); } static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) Only in linux-2.0.30.strip.iw/ipc: msg.c.orig diff -rc linux/kernel/ksyms.c linux-2.0.30.strip.iw/kernel/ksyms.c *** linux/kernel/ksyms.c Tue Mar 11 14:37:16 1997 --- linux-2.0.30.strip.iw/kernel/ksyms.c Sun Jun 29 23:50:45 1997 *************** *** 46,51 **** --- 46,52 ---- #include #include #include + #include extern unsigned char aux_device_present, kbd_read_mask; *************** *** 233,238 **** --- 234,244 ---- X(unregister_sysctl_table), /* interrupt handling */ + X(serial_oe_last_line), + X(serial_oe_last_file), + X(serial_oe_last_base), + X(serial_oe_last_interrupt), + X(request_irq), X(free_irq), X(enable_irq), Only in linux-2.0.30.strip.iw/kernel: ksyms.c.orig diff -rc linux/kernel/sched.c linux-2.0.30.strip.iw/kernel/sched.c *** linux/kernel/sched.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/kernel/sched.c Sun Jun 29 23:50:45 1997 *************** *** 306,313 **** if (intr_count) goto scheduling_in_interrupt; ! if (bh_active & bh_mask) { intr_count = 1; do_bottom_half(); intr_count = 0; } --- 306,325 ---- if (intr_count) goto scheduling_in_interrupt; ! /* ! * Call do_bottom_half repeatedly, until all scheduled bottom halves ! * have executed. We have to do this repeatedly because some bottom ! * halves may mark others for execution. E.g. in IMMEDIATE_BH the ! * serial driver may hand a buffer to SLIP, and the SLIP driver then ! * extracts the IP packet from the buffer and marks NET_BH to actually ! * process the packet. We want the packet handled *NOW*, not the next ! * time the sheduler happens to run, some unspecified time in the ! * future. We do at most 32 repeats, to eliminate the possibility ! * of an infinite loop. ! */ ! for (c=0; bh_active & bh_mask && c<32; c++) { intr_count = 1; + sti(); do_bottom_half(); intr_count = 0; } Only in linux-2.0.30.strip.iw/kernel: sched.c.orig diff -rc linux/net/core/dev.c linux-2.0.30.strip.iw/net/core/dev.c *** linux/net/core/dev.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/core/dev.c Sun Jun 29 23:53:21 1997 *************** *** 424,430 **** /* copy outgoing packets to any sniffer packet handlers */ if (dev_nit) { struct packet_type *ptype; ! skb->stamp=xtime; for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) { /* Never send packets back to the socket --- 424,430 ---- /* copy outgoing packets to any sniffer packet handlers */ if (dev_nit) { struct packet_type *ptype; ! do_gettimeofday(&skb->stamp); for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) { /* Never send packets back to the socket *************** *** 495,501 **** skb->sk = NULL; skb->free = 1; if(skb->stamp.tv_sec==0) ! skb->stamp = xtime; /* * Check that we aren't overdoing things. --- 495,506 ---- skb->sk = NULL; skb->free = 1; if(skb->stamp.tv_sec==0) ! { ! if (dev_nit) ! do_gettimeofday(&skb->stamp); ! else ! skb->stamp = xtime; ! } /* * Check that we aren't overdoing things. *************** *** 658,663 **** --- 663,678 ---- */ pt_prev = NULL; + + /* + * The body of this "if" is intentionally not indented, so + * as to minimize the scope of the "diff". At such time as + * this change may be officially accepted into the Linux + * distribution, the indentation should be fixed. SC. + */ + if (!skb->ptype_all_flag) + { + skb->ptype_all_flag = TRUE; for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next) { if(!ptype->dev || ptype->dev == skb->dev) { *************** *** 668,673 **** --- 683,689 ---- } pt_prev=ptype; } + } } for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) Only in linux-2.0.30.strip.iw/net/core: dev.c.orig diff -rc linux/net/core/skbuff.c linux-2.0.30.strip.iw/net/core/skbuff.c *** linux/net/core/skbuff.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/core/skbuff.c Sun Jun 29 23:53:21 1997 *************** *** 692,697 **** --- 692,698 ---- skb->lock = 0; skb->pkt_type = PACKET_HOST; /* Default type */ skb->pkt_bridged = 0; /* Not bridged */ + skb->ptype_all_flag = 0; /* Not yet sent to ptype_all handlers */ skb->prev = skb->next = skb->link3 = NULL; skb->list = NULL; skb->sk = NULL; *************** *** 770,775 **** --- 771,777 ---- n->list = NULL; n->sk = NULL; n->free = 1; + n->ptype_all_flag = 0; n->tries = 0; n->lock = 0; n->users = 0; *************** *** 830,835 **** --- 832,838 ---- n->lock=0; n->users=0; n->pkt_type=skb->pkt_type; + n->ptype_all_flag=skb->ptype_all_flag; n->stamp=skb->stamp; IS_SKB(n); Only in linux-2.0.30.strip.iw/net/core: skbuff.c.orig diff -rc linux/net/core/sock.c linux-2.0.30.strip.iw/net/core/sock.c *** linux/net/core/sock.c Tue Oct 29 17:42:42 1996 --- linux-2.0.30.strip.iw/net/core/sock.c Sun Jun 29 23:54:15 1997 *************** *** 71,76 **** --- 71,77 ---- * Alan Cox : Generic socket allocation to make hooks * easier (suggested by Craig Metz). * Michael Pall : SO_ERROR returns positive errno again + * Elliot Poger : Added support for SO_BINDTODEVICE. * * To Fix: * *************** *** 128,133 **** --- 129,135 ---- int valbool; int err; struct linger ling; + struct ifreq req; /* * Options without arguments *************** *** 233,238 **** --- 235,268 ---- sk->bsdism = valbool; return 0; + case SO_BINDTODEVICE: + /* Bind this socket to a particular device like "eth0", + * as specified in an ifreq structure. If the device + * is "", socket is NOT bound to a device. */ + if (!valbool) { + sk->bound_device = NULL; + } else { + err=verify_area(VERIFY_READ,optval,sizeof(req)); + if(err) + return err; + memcpy_fromfs(&req,optval,sizeof(req)); + + /* Remove any cached route for this socket. */ + if (sk->ip_route_cache) { + ip_rt_put(sk->ip_route_cache); + sk->ip_route_cache=NULL; + } + + if (*(req.ifr_name) == '\0') { + sk->bound_device = NULL; + } else { + sk->bound_device = dev_get(req.ifr_name); + if (sk->bound_device == NULL) + return -EINVAL; + } + } + return 0; + default: return(-ENOPROTOOPT); } Only in linux-2.0.30.strip.iw/net/core: sock.c.orig diff -rc linux/net/ipv4/arp.c linux-2.0.30.strip.iw/net/ipv4/arp.c *** linux/net/ipv4/arp.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/arp.c Mon Jun 30 00:01:48 1997 *************** *** 134,139 **** --- 134,142 ---- int sysctl_arp_timeout = ARP_TIMEOUT; + #define dev_arp_timeout(dev) \ + (((dev)->type == ARPHRD_METRICOM) ? (30*60*HZ) : sysctl_arp_timeout) + /* * How often is ARP cache checked for expire. * It is useless to set ARP_CHECK_INTERVAL > ARP_TIMEOUT *************** *** 172,177 **** --- 175,183 ---- int sysctl_arp_res_time = ARP_RES_TIME; + #define dev_arp_res_time(dev) \ + (((dev)->type == ARPHRD_METRICOM) ? (2*HZ) : sysctl_arp_res_time) + /* * The number of times an broadcast arp request is send, until * the host is considered temporarily unreachable. *************** *** 181,186 **** --- 187,195 ---- int sysctl_arp_max_tries = ARP_MAX_TRIES; + #define dev_arp_max_tries(dev) \ + (((dev)->type == ARPHRD_METRICOM) ? (10) : sysctl_arp_max_tries) + /* * The entry is reconfirmed by sending point-to-point ARP * request after ARP_CONFIRM_INTERVAL. *************** *** 216,221 **** --- 225,233 ---- int sysctl_arp_max_pings = ARP_MAX_PINGS; + #define dev_arp_max_pings(dev) \ + (((dev)->type == ARPHRD_METRICOM) ? (5) : sysctl_arp_max_pings) + /* * When a host is dead, but someone tries to connect it, * we do not remove corresponding cache entry (it would *************** *** 282,288 **** static void arp_run_bh(void); static void arp_check_expire (unsigned long); static int arp_update (u32 sip, char *sha, struct device * dev, ! unsigned long updated, struct arp_table *ientry, int grat); static struct timer_list arp_timer = { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire }; --- 294,300 ---- static void arp_run_bh(void); static void arp_check_expire (unsigned long); static int arp_update (u32 sip, char *sha, struct device * dev, ! unsigned long updated, struct arp_table *ientry, int grat, int flags); static struct timer_list arp_timer = { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire }; *************** *** 316,321 **** --- 328,340 ---- #define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1)) /* + * The ascii representation of a hardware address can be up to + * 30 characters long + */ + + #define HBUFFERLEN 30 + + /* * ARP cache semaphore. * * Every time when someone wants to traverse arp table, *************** *** 700,706 **** else { arp_fast_lock(); ! arp_update(retreq->ip, retreq->ha, dev, retreq->updated, NULL, 0); arp_unlock(); } --- 719,725 ---- else { arp_fast_lock(); ! arp_update(retreq->ip, retreq->ha, dev, retreq->updated, NULL, 0, 0); arp_unlock(); } *************** *** 761,767 **** cli(); users = arp_count_hhs(entry); ! if (!users && now - entry->last_used > sysctl_arp_timeout) { *pentry = entry->next; restore_flags(flags); --- 780,786 ---- cli(); users = arp_count_hhs(entry); ! if (!users && now - entry->last_used > dev_arp_timeout(entry->dev)) { *pentry = entry->next; restore_flags(flags); *************** *** 840,846 **** } cli(); ! if (now - entry->last_used > sysctl_arp_timeout && !arp_count_hhs(entry)) { *pentry = entry->next; --- 859,865 ---- } cli(); ! if (now - entry->last_used > dev_arp_timeout(entry->dev) && !arp_count_hhs(entry)) { *pentry = entry->next; *************** *** 857,865 **** && !(entry->flags & ATF_PERM)) { struct device * dev = entry->dev; ! entry->retries = sysctl_arp_max_tries+sysctl_arp_max_pings; del_timer(&entry->timer); ! entry->timer.expires = jiffies + ARP_CONFIRM_TIMEOUT; add_timer(&entry->timer); arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, entry->ha, --- 876,884 ---- && !(entry->flags & ATF_PERM)) { struct device * dev = entry->dev; ! entry->retries = dev_arp_max_tries(dev)+ dev_arp_max_pings(dev); del_timer(&entry->timer); ! entry->timer.expires = jiffies + sysctl_arp_confirm_timeout; add_timer(&entry->timer); arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, entry->ha, *************** *** 941,956 **** if (entry->last_updated && --entry->retries > 0) { struct device *dev = entry->dev; #if RT_CACHE_DEBUG >= 2 printk("arp_expire_request: %08x timed out\n", entry->ip); #endif /* Set new timer. */ ! entry->timer.expires = jiffies + sysctl_arp_res_time; add_timer(&entry->timer); arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, ! entry->retries > sysctl_arp_max_tries ? entry->ha : NULL, ! dev->dev_addr, NULL); arp_unlock(); return; } --- 960,975 ---- if (entry->last_updated && --entry->retries > 0) { struct device *dev = entry->dev; + int pinging = entry->retries > dev_arp_max_tries(dev); #if RT_CACHE_DEBUG >= 2 printk("arp_expire_request: %08x timed out\n", entry->ip); #endif /* Set new timer. */ ! entry->timer.expires = jiffies + (pinging ? sysctl_arp_confirm_timeout : dev_arp_res_time(dev)); add_timer(&entry->timer); arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, ! pinging ? entry->ha : NULL, dev->dev_addr, NULL); arp_unlock(); return; } *************** *** 976,982 **** #if RT_CACHE_DEBUG >= 2 printk("arp_expire_request: %08x is dead\n", entry->ip); #endif ! entry->retries = sysctl_arp_max_tries; entry->flags &= ~ATF_COM; arp_invalidate_hhs(entry); restore_flags(flags); --- 995,1001 ---- #if RT_CACHE_DEBUG >= 2 printk("arp_expire_request: %08x is dead\n", entry->ip); #endif ! entry->retries = dev_arp_max_tries(dev); entry->flags &= ~ATF_COM; arp_invalidate_hhs(entry); restore_flags(flags); *************** *** 1146,1169 **** restore_flags(flags); } static int arp_update (u32 sip, char *sha, struct device * dev, ! unsigned long updated, struct arp_table *ientry, int grat) { struct arp_table * entry; - unsigned long hash; int do_arpd = 0; if (updated == 0) { updated = jiffies; do_arpd = 1; } ! hash = HASH(sip); ! ! for (entry=arp_tables[hash]; entry; entry = entry->next) if (entry->ip == sip && entry->dev == dev) break; --- 1165,1220 ---- restore_flags(flags); } + static void arp_print_hardware_address(char hbuffer[], char *ha, int len) + { + static const char hexbuf[] = "0123456789ABCDEF"; + int j = 0, k = 0; + while (j < len && k < HBUFFERLEN-3) + { + hbuffer[k++]=hexbuf[ (ha[j ]>>4)&15 ]; + hbuffer[k++]=hexbuf[ ha[j++]&15 ]; + hbuffer[k++]=':'; + } + hbuffer[--k]=0; + } + + static void arp_report_change(struct arp_table *entry, char *sha) + { + union { u32 l; u8 b[4]; } ip; + char old_addr[HBUFFERLEN]; + char new_addr[HBUFFERLEN]; + + /* + * Don't print address change message if the old address is all zeroes + */ + + if (empty(entry->ha, entry->dev->addr_len)) + return; + + arp_print_hardware_address(old_addr, entry->ha, entry->dev->addr_len); + arp_print_hardware_address(new_addr, sha, entry->dev->addr_len); + ip.l = entry->ip; + printk(KERN_INFO "ARP: %d.%d.%d.%d changed: %s->%s\n", + ip.b[0], ip.b[1], ip.b[2], ip.b[3], old_addr, new_addr); + } static int arp_update (u32 sip, char *sha, struct device * dev, ! unsigned long updated, struct arp_table *ientry, int grat, int flags) { + struct arp_table **arp_table = &arp_tables[HASH(sip)]; struct arp_table * entry; int do_arpd = 0; + if (flags & ATF_PUBL) arp_table = &arp_proxy_list; + if (updated == 0) { updated = jiffies; do_arpd = 1; } ! for (entry=*arp_table; entry; entry = entry->next) if (entry->ip == sip && entry->dev == dev) break; *************** *** 1178,1183 **** --- 1229,1235 ---- entry->last_updated = updated; if (memcmp(entry->ha, sha, dev->addr_len)!=0) { + arp_report_change(entry, sha); memcpy(entry->ha, sha, dev->addr_len); if (entry->flags & ATF_COM) arp_update_hhs(entry); *************** *** 1194,1199 **** --- 1246,1266 ---- */ entry->flags |= ATF_COM; arp_update_hhs(entry); + /* + * If this ARP reply just completed a Metricom STRIP ARP entry that we were + * waiting for, then that means we're about to send packets to this host, + * which most likely won't know our HW address in order to address the replies + * to us. To save it from also having to contact the broadcast hub to find out, + * we preemptively sent it a gratuitous ARP, to prime its cache. + */ + if (dev->type == ARPHRD_METRICOM) + arp_send(ARPOP_REPLY, ETH_P_ARP, + dev->pa_addr, /* Target address of ARP packet is our address */ + dev, /* Device to send packet on */ + dev->pa_addr, /* Source IP address this ARP packet comes from */ + entry->ha, /* Destination HW address we're sending it to */ + dev->dev_addr, /* Source HW address is our HW address */ + dev->dev_addr); /* Target HW address is our HW address (redundant) */ /* * Send out waiting packets. We might have problems, if someone is * manually removing entries right now -- entry might become invalid *************** *** 1219,1225 **** return 0; entry->ip = sip; ! entry->flags = ATF_COM; memcpy(entry->ha, sha, dev->addr_len); entry->dev = dev; } --- 1286,1292 ---- return 0; entry->ip = sip; ! entry->flags = ATF_COM | flags; memcpy(entry->ha, sha, dev->addr_len); entry->dev = dev; } *************** *** 1231,1238 **** if (!ARP_LOCKED()) { ! entry->next = arp_tables[hash]; ! arp_tables[hash] = entry; return 0; } #if RT_CACHE_DEBUG >= 2 --- 1298,1305 ---- if (!ARP_LOCKED()) { ! entry->next = *arp_table; ! *arp_table = entry; return 0; } #if RT_CACHE_DEBUG >= 2 *************** *** 1339,1345 **** atomic_inc(&hh->hh_refcnt); hh->hh_arp = (void*)entry; } ! entry->timer.expires = jiffies + sysctl_arp_res_time; if (skb != NULL) { --- 1406,1412 ---- atomic_inc(&hh->hh_refcnt); hh->hh_arp = (void*)entry; } ! entry->timer.expires = jiffies + dev_arp_res_time(dev); if (skb != NULL) { *************** *** 1353,1359 **** entry->next = arp_tables[hash]; arp_tables[hash] = entry; add_timer(&entry->timer); ! entry->retries = sysctl_arp_max_tries; #ifdef CONFIG_ARPD if (!arpd_not_running) arpd_lookup(paddr, dev); --- 1420,1426 ---- entry->next = arp_tables[hash]; arp_tables[hash] = entry; add_timer(&entry->timer); ! entry->retries = dev_arp_max_tries(dev); #ifdef CONFIG_ARPD if (!arpd_not_running) arpd_lookup(paddr, dev); *************** *** 1574,1580 **** while ((entry = arp_dequeue(&arp_backlog)) != NULL) { restore_flags(flags); ! if (arp_update(entry->ip, entry->ha, entry->dev, 0, entry, 0)) arp_free_entry(entry); cli(); } --- 1641,1647 ---- while ((entry = arp_dequeue(&arp_backlog)) != NULL) { restore_flags(flags); ! if (arp_update(entry->ip, entry->ha, entry->dev, 0, entry, 0, entry->flags)) arp_free_entry(entry); cli(); } *************** *** 1598,1605 **** entry->next = arp_tables[hash]; arp_tables[hash] = entry; restore_flags(flags); ! entry->timer.expires = jiffies + sysctl_arp_res_time; ! entry->retries = sysctl_arp_max_tries; entry->last_used = jiffies; if (!(entry->flags & ATF_COM)) { --- 1665,1672 ---- entry->next = arp_tables[hash]; arp_tables[hash] = entry; restore_flags(flags); ! entry->timer.expires = jiffies + dev_arp_res_time(dev); ! entry->retries = dev_arp_max_tries(dev); entry->last_used = jiffies; if (!(entry->flags & ATF_COM)) { *************** *** 1689,1694 **** --- 1756,1768 ---- return; /* + * Mustn't send an ARP packet with a zero source address + */ + + if (empty(src_hw, dev->addr_len)) + return; + + /* * Allocate a buffer */ *************** *** 1975,1982 **** memcpy(ha, proxy_entry->ha, dev->addr_len); arp_unlock(); ! rt = ip_rt_route(tip, 0); ! if (rt && rt->rt_dev != dev) arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha,sha); ip_rt_put(rt); --- 2049,2056 ---- memcpy(ha, proxy_entry->ha, dev->addr_len); arp_unlock(); ! rt = ip_rt_route(tip, 0, NULL); ! if ((rt && rt->rt_dev != dev) || dev->type == ARPHRD_METRICOM) arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha,sha); ip_rt_put(rt); *************** *** 1990,1996 **** } arp_fast_lock(); ! arp_update(sip, sha, dev, 0, NULL, ip_chk_addr(tip) != IS_MYADDR && dev->type != ARPHRD_METRICOM); arp_unlock(); kfree_skb(skb, FREE_READ); return 0; --- 2064,2071 ---- } arp_fast_lock(); ! arp_update(sip, sha, dev, 0, NULL, ip_chk_addr(tip) != IS_MYADDR && dev->type != ARPHRD_METRICOM, 0); ! if (dev->type == ARPHRD_METRICOM) arp_update(sip, sha, dev, 0, NULL, 0, ATF_PUBL); arp_unlock(); kfree_skb(skb, FREE_READ); return 0; *************** *** 2048,2054 **** if (!dev) { struct rtable * rt; ! rt = ip_rt_route(ip, 0); if (!rt) return -ENETUNREACH; dev = rt->rt_dev; --- 2123,2129 ---- if (!dev) { struct rtable * rt; ! rt = ip_rt_route(ip, 0, NULL); if (!rt) return -ENETUNREACH; dev = rt->rt_dev; *************** *** 2332,2339 **** /* * Write the contents of the ARP cache to a PROCfs file. */ - - #define HBUFFERLEN 30 int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { --- 2407,2412 ---- Only in linux-2.0.30.strip.iw/net/ipv4: arp.c.orig Only in linux-2.0.30.strip.iw/net/ipv4: arp.c.rej diff -rc linux/net/ipv4/icmp.c linux-2.0.30.strip.iw/net/ipv4/icmp.c *** linux/net/ipv4/icmp.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/icmp.c Sun Jun 29 23:54:16 1997 *************** *** 39,44 **** --- 39,45 ---- * Thomas Quinot : ICMP Dest Unreach codes up to 15 are * valid (RFC 1812). * Alan Cox : Spoofing and junk icmp protections. + * Elliot Poger : Added support for SO_BINDTODEVICE. * * * RFC1122 (Host Requirements -- Comm. Layer) Status: *************** *** 992,999 **** */ /* This should work with the new hashes now. -DaveM */ ! extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport); ! extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport); int icmp_chkaddr(struct sk_buff *skb) { --- 993,1000 ---- */ /* This should work with the new hashes now. -DaveM */ ! extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev); ! extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev); int icmp_chkaddr(struct sk_buff *skb) { *************** *** 1009,1015 **** { struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); ! sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest); if (!sk) return 0; if (sk->saddr != iph->saddr) return 0; if (sk->daddr != iph->daddr) return 0; --- 1010,1017 ---- { struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); ! sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest, ! skb->dev); if (!sk) return 0; if (sk->saddr != iph->saddr) return 0; if (sk->daddr != iph->daddr) return 0; *************** *** 1023,1029 **** { struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); ! sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest); if (!sk) return 0; if (sk->saddr != iph->saddr && ip_chk_addr(iph->saddr) != IS_MYADDR) return 0; --- 1025,1032 ---- { struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); ! sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, ! skb->dev); if (!sk) return 0; if (sk->saddr != iph->saddr && ip_chk_addr(iph->saddr) != IS_MYADDR) return 0; Only in linux-2.0.30.strip.iw/net/ipv4: icmp.c.orig diff -rc linux/net/ipv4/ip_alias.c linux-2.0.30.strip.iw/net/ipv4/ip_alias.c *** linux/net/ipv4/ip_alias.c Mon May 13 02:15:24 1996 --- linux-2.0.30.strip.iw/net/ipv4/ip_alias.c Sun Jun 29 23:54:16 1997 *************** *** 102,108 **** * net_alias module will check if returned device is main_dev's alias */ ! rt = ip_rt_route(addr, 0); if(rt) { dev=rt->rt_dev; --- 102,108 ---- * net_alias module will check if returned device is main_dev's alias */ ! rt = ip_rt_route(addr, 0, NULL); if(rt) { dev=rt->rt_dev; Only in linux-2.0.30.strip.iw/net/ipv4: ip_alias.c.orig diff -rc linux/net/ipv4/ip_forward.c linux-2.0.30.strip.iw/net/ipv4/ip_forward.c *** linux/net/ipv4/ip_forward.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/ip_forward.c Sun Jun 29 23:54:16 1997 *************** *** 177,183 **** * and give it to the IP sender for further processing. */ ! rt = ip_rt_route(target_addr, 0); if (rt == NULL) { --- 177,183 ---- * and give it to the IP sender for further processing. */ ! rt = ip_rt_route(target_addr, 0, NULL); if (rt == NULL) { *************** *** 345,355 **** } #ifdef CONFIG_IP_MROUTE ! if(skb_headroom(skb)-encaphard_header_len) { skb2 = alloc_skb(dev2->hard_header_len + skb->len + encap + 15, GFP_ATOMIC); #else ! if(skb_headroom(skb)hard_header_len) { skb2 = alloc_skb(dev2->hard_header_len + skb->len + 15, GFP_ATOMIC); #endif --- 345,355 ---- } #ifdef CONFIG_IP_MROUTE ! if(skb_headroom(skb)-encaphard_header_len || skb->count > 1) { skb2 = alloc_skb(dev2->hard_header_len + skb->len + encap + 15, GFP_ATOMIC); #else ! if(skb_headroom(skb)hard_header_len || skb->count > 1) { skb2 = alloc_skb(dev2->hard_header_len + skb->len + 15, GFP_ATOMIC); #endif Only in linux-2.0.30.strip.iw/net/ipv4: ip_forward.c.orig diff -rc linux/net/ipv4/ip_output.c linux-2.0.30.strip.iw/net/ipv4/ip_output.c *** linux/net/ipv4/ip_output.c Tue Oct 29 17:42:42 1996 --- linux-2.0.30.strip.iw/net/ipv4/ip_output.c Sun Jun 29 23:54:16 1997 *************** *** 26,31 **** --- 26,32 ---- * Alexander Demenshin: Missing sk/skb free in ip_queue_xmit * (in case if packet not accepted by * output firewall rules) + * Elliot Poger : Added support for SO_BINDTODEVICE. */ #include *************** *** 218,224 **** #endif if (rp) { ! rt = ip_check_route(rp, daddr, skb->localroute); /* * If rp != NULL rt_put following below should not * release route, so that... --- 219,225 ---- #endif if (rp) { ! rt = ip_check_route(rp, daddr, skb->localroute, *dev); /* * If rp != NULL rt_put following below should not * release route, so that... *************** *** 227,233 **** atomic_inc(&rt->rt_refcnt); } else ! rt = ip_rt_route(daddr, skb->localroute); if (*dev == NULL) --- 228,234 ---- atomic_inc(&rt->rt_refcnt); } else ! rt = ip_rt_route(daddr, skb->localroute, *dev); if (*dev == NULL) *************** *** 590,596 **** #endif rt = ip_check_route(&sk->ip_route_cache, daddr, sk->localroute || (flags&MSG_DONTROUTE) || ! (opt && opt->is_strictroute)); if (rt == NULL) { ip_statistics.IpOutNoRoutes++; --- 591,597 ---- #endif rt = ip_check_route(&sk->ip_route_cache, daddr, sk->localroute || (flags&MSG_DONTROUTE) || ! (opt && opt->is_strictroute), sk->bound_device); if (rt == NULL) { ip_statistics.IpOutNoRoutes++; Only in linux-2.0.30.strip.iw/net/ipv4: ip_output.c.orig diff -rc linux/net/ipv4/ip_sockglue.c linux-2.0.30.strip.iw/net/ipv4/ip_sockglue.c *** linux/net/ipv4/ip_sockglue.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/ip_sockglue.c Sun Jun 29 23:54:16 1997 *************** *** 12,17 **** --- 12,18 ---- * Martin Mares : TOS setting fixed. * Alan Cox : Fixed a couple of oopses in Martin's * TOS tweaks. + * Elliot Poger : Added support for SO_BINDTODEVICE. */ #include *************** *** 293,299 **** /* * Not set so scan. */ ! if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL) { dev=rt->rt_dev; atomic_dec(&rt->rt_use); --- 294,300 ---- /* * Not set so scan. */ ! if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0,sk->bound_device))!=NULL) { dev=rt->rt_dev; atomic_dec(&rt->rt_use); *************** *** 345,351 **** if(mreq.imr_interface.s_addr==INADDR_ANY) { ! if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL) { dev=rt->rt_dev; atomic_dec(&rt->rt_use); --- 346,352 ---- if(mreq.imr_interface.s_addr==INADDR_ANY) { ! if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0,sk->bound_device))!=NULL) { dev=rt->rt_dev; atomic_dec(&rt->rt_use); Only in linux-2.0.30.strip.iw/net/ipv4: ip_sockglue.c.orig diff -rc linux/net/ipv4/rarp.c linux-2.0.30.strip.iw/net/ipv4/rarp.c *** linux/net/ipv4/rarp.c Tue Oct 29 17:42:42 1996 --- linux-2.0.30.strip.iw/net/ipv4/rarp.c Sun Jun 29 23:54:16 1997 *************** *** 354,360 **** * Is it reachable directly ? */ ! rt = ip_rt_route(ip, 0); if (rt == NULL) return -ENETUNREACH; dev = rt->rt_dev; --- 354,360 ---- * Is it reachable directly ? */ ! rt = ip_rt_route(ip, 0, NULL); if (rt == NULL) return -ENETUNREACH; dev = rt->rt_dev; Only in linux-2.0.30.strip.iw/net/ipv4: rarp.c.orig diff -rc linux/net/ipv4/route.c linux-2.0.30.strip.iw/net/ipv4/route.c *** linux/net/ipv4/route.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/route.c Sun Jun 29 23:54:16 1997 *************** *** 42,47 **** --- 42,48 ---- * Bjorn Ekwall : Kerneld route support. * Alan Cox : Multicast fixed (I hope) * Pavel Krauz : Limited broadcast fixed + * Elliot Poger : Added support for SO_BINDTODEVICE. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License *************** *** 247,255 **** * Host 193.233.7.129 is locally unreachable, * but old (<=1.3.37) code will send packets destined for it to eth1. * */ ! static struct fib_node * fib_lookup_local(__u32 dst) { struct fib_zone * fz; struct fib_node * f; --- 248,258 ---- * Host 193.233.7.129 is locally unreachable, * but old (<=1.3.37) code will send packets destined for it to eth1. * + * Calling routine can specify a particular interface by setting dev. If dev==NULL, + * any interface will do. */ ! static struct fib_node * fib_lookup_local(__u32 dst, struct device *dev) { struct fib_zone * fz; struct fib_node * f; *************** *** 267,272 **** --- 270,277 ---- { if ((dst ^ f->fib_dst) & fz->fz_mask) continue; + if ( (dev != NULL) && (dev != f->fib_info->fib_dev) ) + continue; if (!(f->fib_info->fib_flags & RTF_GATEWAY)) return f; longest_match_found = 1; *************** *** 289,295 **** * route add -host 193.233.7.255 eth0 */ ! static struct fib_node * fib_lookup(__u32 dst) { struct fib_zone * fz; struct fib_node * f; --- 294,300 ---- * route add -host 193.233.7.255 eth0 */ ! static struct fib_node * fib_lookup(__u32 dst, struct device *dev) { struct fib_zone * fz; struct fib_node * f; *************** *** 305,310 **** --- 310,317 ---- { if ((dst ^ f->fib_dst) & fz->fz_mask) continue; + if ( (dev != NULL) && (dev != f->fib_info->fib_dev) ) + continue; return f; } } *************** *** 1254,1260 **** struct rt_req * rtr; struct rtable * rt; ! rt = ip_rt_route(dst, 0); if (!rt) return; --- 1261,1267 ---- struct rt_req * rtr; struct rtable * rt; ! rt = ip_rt_route(dst, 0, NULL); if (!rt) return; *************** *** 1323,1329 **** if (rth->rt_gateway != daddr) { ip_rt_fast_unlock(); ! rtg = ip_rt_route(rth->rt_gateway, 0); ip_rt_fast_lock(); } --- 1330,1336 ---- if (rth->rt_gateway != daddr) { ip_rt_fast_unlock(); ! rtg = ip_rt_route(rth->rt_gateway, 0, NULL); ip_rt_fast_lock(); } *************** *** 1395,1401 **** */ ! struct rtable * ip_rt_slow_route (__u32 daddr, int local) { unsigned hash = ip_rt_hash_code(daddr)^local; struct rtable * rth; --- 1402,1408 ---- */ ! struct rtable * ip_rt_slow_route (__u32 daddr, int local, struct device *dev) { unsigned hash = ip_rt_hash_code(daddr)^local; struct rtable * rth; *************** *** 1415,1423 **** } if (local) ! f = fib_lookup_local(daddr); else ! f = fib_lookup (daddr); if (f) { --- 1422,1430 ---- } if (local) ! f = fib_lookup_local(daddr, dev); else ! f = fib_lookup (daddr, dev); if (f) { *************** *** 1490,1496 **** rth->rt_gateway = rth->rt_dst; if (ip_rt_lock == 1) ! rt_cache_add(hash, rth); else { rt_free(rth); --- 1497,1511 ---- rth->rt_gateway = rth->rt_dst; if (ip_rt_lock == 1) ! { ! /* Don't add this to the rt_cache if a device was specified, ! * because we might have skipped better routes which didn't ! * point at the right device. */ ! if (dev != NULL) ! rth->rt_flags |= RTF_NOTCACHED; ! else ! rt_cache_add(hash, rth); ! } else { rt_free(rth); *************** *** 1507,1515 **** { if (rt) atomic_dec(&rt->rt_refcnt); } ! struct rtable * ip_rt_route(__u32 daddr, int local) { struct rtable * rth; --- 1522,1535 ---- { if (rt) atomic_dec(&rt->rt_refcnt); + + /* If this rtable entry is not in the cache, we'd better free it once the + * refcnt goes to zero, because nobody else will... */ + if ( rt && (rt->rt_flags & RTF_NOTCACHED) && (!rt->rt_refcnt) ) + rt_free(rt); } ! struct rtable * ip_rt_route(__u32 daddr, int local, struct device *dev) { struct rtable * rth; *************** *** 1517,1523 **** for (rth=ip_rt_hash_table[ip_rt_hash_code(daddr)^local]; rth; rth=rth->rt_next) { ! if (rth->rt_dst == daddr) { rth->rt_lastuse = jiffies; atomic_inc(&rth->rt_use); --- 1537,1544 ---- for (rth=ip_rt_hash_table[ip_rt_hash_code(daddr)^local]; rth; rth=rth->rt_next) { ! /* If a network device is specified, make sure this route points to it. */ ! if ( (rth->rt_dst == daddr) && ((dev==NULL) || (dev==rth->rt_dev)) ) { rth->rt_lastuse = jiffies; atomic_inc(&rth->rt_use); *************** *** 1526,1532 **** return rth; } } ! return ip_rt_slow_route (daddr, local); } /* --- 1547,1553 ---- return rth; } } ! return ip_rt_slow_route (daddr, local, dev); } /* Only in linux-2.0.30.strip.iw/net/ipv4: route.c.orig diff -rc linux/net/ipv4/tcp.c linux-2.0.30.strip.iw/net/ipv4/tcp.c *** linux/net/ipv4/tcp.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/tcp.c Sun Jun 29 23:54:17 1997 *************** *** 205,210 **** --- 205,211 ---- * Theodore Ts'o : Do secure TCP sequence numbers. * David S. Miller : New socket lookup architecture for ISS. * This code is dedicated to John Dyson. + * Elliot Poger : Added support for SO_BINDTODEVICE. * * To Fix: * Fast path the code. Two things here - fix the window calculation *************** *** 471,476 **** --- 472,483 ---- unsigned char state = sk2->state; int sk2_reuse = sk2->reuse; + /* Two sockets can be bound to the same port if they're + * bound to different interfaces... */ + if (sk->bound_device != sk2->bound_device) { + continue; + } + if(!sk2->rcv_saddr || !sk->rcv_saddr) { if((!sk2_reuse) || (!sk_reuse) || *************** *** 2197,2202 **** --- 2204,2212 ---- buff->sk = sk; buff->free = 0; buff->localroute = sk->localroute; + + /* If this socket is bound to a particular device, make sure we use it. */ + dev = sk->bound_device; /* * Put in the IP header and routing stuff. Only in linux-2.0.30.strip.iw/net/ipv4: tcp.c.orig diff -rc linux/net/ipv4/tcp_input.c linux-2.0.30.strip.iw/net/ipv4/tcp_input.c *** linux/net/ipv4/tcp_input.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/tcp_input.c Sun Jun 29 23:54:17 1997 *************** *** 1,3 **** --- 1,4 ---- + #define STUART_NAGLE_FIX 1 /* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket *************** *** 33,38 **** --- 34,40 ---- * : with SYN flooding attacks. * David S. Miller : New socket lookup architecture for ISS. * This code is dedicated to John Dyson. + * Elliot Poger : Added support for SO_BINDTODEVICE. */ #include *************** *** 229,248 **** * XXX hash twice, once for local addresses bound, and once for * XXX the local address wildcarded (because the hash is different). */ ! static struct sock *tcp_v4_lookup_longway(u32 daddr, unsigned short hnum) { struct sock *sk = tcp_listening_hash[tcp_lhashfn(hnum)]; struct sock *result = NULL; for(; sk; sk = sk->next) { if(sk->num == hnum) { __u32 rcv_saddr = sk->rcv_saddr; if(rcv_saddr) { ! if(rcv_saddr == daddr) ! return sk; /* Best possible match. */ ! } else if(!result) result = sk; } } return result; --- 231,272 ---- * XXX hash twice, once for local addresses bound, and once for * XXX the local address wildcarded (because the hash is different). */ ! static struct sock *tcp_v4_lookup_longway(u32 daddr, unsigned short hnum, ! struct device *dev) { struct sock *sk = tcp_listening_hash[tcp_lhashfn(hnum)]; struct sock *result = NULL; + int score, hiscore; + hiscore = 0; for(; sk; sk = sk->next) { if(sk->num == hnum) { __u32 rcv_saddr = sk->rcv_saddr; + score = 1; + /* If this socket is bound to a particular IP address, + * does the dest IPaddr of the packet match it? */ if(rcv_saddr) { ! if(rcv_saddr != daddr) ! continue; ! score++; ! } ! ! /* If this socket is bound to a particular interface, ! * did the packet come in on it? */ ! if (sk->bound_device) { ! if (dev != sk->bound_device) ! continue; ! score++; ! } ! ! /* Check the score--max is 3. */ ! if (score == 3) ! return sk; /* Best possible match. */ ! if (score > hiscore) { ! hiscore = score; result = sk; + } } } return result; *************** *** 252,258 **** * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM */ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th, ! u32 saddr, u16 sport, u32 daddr, u16 dport) { unsigned short hnum = ntohs(dport); struct sock *sk; --- 276,283 ---- * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM */ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th, ! u32 saddr, u16 sport, u32 daddr, ! u16 dport, struct device *dev) { unsigned short hnum = ntohs(dport); struct sock *sk; *************** *** 266,281 **** if(sk->daddr == saddr && /* remote address */ sk->dummy_th.dest == sport && /* remote port */ sk->num == hnum && /* local port */ ! sk->rcv_saddr == daddr) /* local address */ goto hit; /* You sunk my battleship! */ ! sk = tcp_v4_lookup_longway(daddr, hnum); hit: return sk; } ! __inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport) { ! return __tcp_v4_lookup(0, saddr, sport, daddr, dport); } #ifdef CONFIG_IP_TRANSPARENT_PROXY --- 291,308 ---- if(sk->daddr == saddr && /* remote address */ sk->dummy_th.dest == sport && /* remote port */ sk->num == hnum && /* local port */ ! sk->rcv_saddr == daddr && /* local address */ ! ((sk->bound_device==NULL) || (sk->bound_device==dev)) ) goto hit; /* You sunk my battleship! */ ! sk = tcp_v4_lookup_longway(daddr, hnum, dev); hit: return sk; } ! __inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, ! struct device *dev) { ! return __tcp_v4_lookup(0, saddr, sport, daddr, dport, dev); } #ifdef CONFIG_IP_TRANSPARENT_PROXY *************** *** 295,301 **** struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr, unsigned short rnum, unsigned long laddr, ! unsigned long paddr, unsigned short pnum) { struct sock *s, *result = NULL; int badness = -1; --- 322,329 ---- struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr, unsigned short rnum, unsigned long laddr, ! unsigned long paddr, unsigned short pnum, ! struct device *dev) { struct sock *s, *result = NULL; int badness = -1; *************** *** 327,333 **** continue; score++; } ! if(score == 3 && s->num == hnum) { result = s; break; } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) { --- 355,366 ---- continue; score++; } ! if(s->bound_device) { ! if (s->bound_device != dev) ! continue; ! score++; ! } ! if(score == 4 && s->num == hnum) { result = s; break; } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) { *************** *** 758,764 **** * Note use of sk->user_mss, since user has no direct access to newsk */ ! rt = ip_rt_route(newsk->opt && newsk->opt->srr ? newsk->opt->faddr : saddr, 0); newsk->ip_route_cache = rt; if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) --- 791,798 ---- * Note use of sk->user_mss, since user has no direct access to newsk */ ! rt = ip_rt_route(newsk->opt && newsk->opt->srr ? newsk->opt->faddr : saddr, 0, ! sk->bound_device); newsk->ip_route_cache = rt; if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) *************** *** 1001,1007 **** newsk->ip_ttl=sk->ip_ttl; newsk->ip_tos=skb->ip_hdr->tos; ! rt = ip_rt_route(newsk->opt && newsk->opt->srr ? newsk->opt->faddr : saddr, 0); newsk->ip_route_cache = rt; if (rt!=NULL && (rt->rt_flags&RTF_WINDOW)) --- 1035,1042 ---- newsk->ip_ttl=sk->ip_ttl; newsk->ip_tos=skb->ip_hdr->tos; ! rt = ip_rt_route(newsk->opt && newsk->opt->srr ? newsk->opt->faddr : saddr, 0, ! sk->bound_device); newsk->ip_route_cache = rt; if (rt!=NULL && (rt->rt_flags&RTF_WINDOW)) *************** *** 1533,1538 **** --- 1568,1580 ---- break; } + /* + * We don't want to do this particular piece of wizardry here, because we + * haven't yet examined the data in this packet, and if we fire off a packet + * now it's quite likely that we'll immediately find that we just sent it + * with the wrong ack sequence number. + */ + #ifndef STUART_NAGLE_FIX /* * We have nothing queued but space to send. Send any partial * packets immediately (end of Nagle rule application). *************** *** 1545,1550 **** --- 1587,1593 ---- { tcp_send_partial(sk); } + #endif /* * In the LAST_ACK case, the other end FIN'd us. We then FIN'd them, and *************** *** 2196,2202 **** struct tcphdr *th = (struct tcphdr *)(skb->h.raw + iph->ihl*4); struct sock *sk; ! sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest); if (!sk) return 0; /* 0 means accept all LOCAL addresses here, not all the world... */ --- 2239,2245 ---- struct tcphdr *th = (struct tcphdr *)(skb->h.raw + iph->ihl*4); struct sock *sk; ! sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest, skb->dev); if (!sk) return 0; /* 0 means accept all LOCAL addresses here, not all the world... */ *************** *** 2262,2268 **** #ifdef CONFIG_SYN_COOKIES retry_search: #endif ! sk = __tcp_v4_lookup(th, saddr, th->source, daddr, th->dest); if (!sk) goto no_tcp_socket; skb->sk = sk; --- 2305,2311 ---- #ifdef CONFIG_SYN_COOKIES retry_search: #endif ! sk = __tcp_v4_lookup(th, saddr, th->source, daddr, th->dest, dev); if (!sk) goto no_tcp_socket; skb->sk = sk; *************** *** 2572,2578 **** sk->shutdown = SHUTDOWN_MASK; #ifdef CONFIG_IP_TRANSPARENT_PROXY sk = tcp_v4_proxy_lookup(th->dest, saddr, th->source, daddr, ! dev->pa_addr, skb->redirport); #else sk = NULL; #endif --- 2615,2621 ---- sk->shutdown = SHUTDOWN_MASK; #ifdef CONFIG_IP_TRANSPARENT_PROXY sk = tcp_v4_proxy_lookup(th->dest, saddr, th->source, daddr, ! dev->pa_addr, skb->redirport, dev); #else sk = NULL; #endif *************** *** 2671,2676 **** --- 2714,2734 ---- if(tcp_data(skb,sk, saddr, len)) kfree_skb(skb, FREE_READ); + + #ifdef STUART_NAGLE_FIX + /* + * If we had a partial packet being help up due to + * application of Nagle's rule we are now free to send it. + */ + if (th->ack + && sk->packets_out == 0 + && sk->partial != NULL + && skb_queue_empty(&sk->write_queue) + && sk->send_head == NULL) + { + tcp_send_partial(sk); + } + #endif /* * If our receive queue has grown past its limits, Only in linux-2.0.30.strip.iw/net/ipv4: tcp_input.c.orig diff -rc linux/net/ipv4/tcp_output.c linux-2.0.30.strip.iw/net/ipv4/tcp_output.c *** linux/net/ipv4/tcp_output.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/tcp_output.c Sun Jun 29 23:54:17 1997 *************** *** 32,37 **** --- 32,38 ---- * thus the outgoing device does as well, when * skb's are on the retransmit queue which still * refer to the old obsolete destination. + * Elliot Poger : Added support for SO_BINDTODEVICE. */ #include *************** *** 491,497 **** /* ANK: UGLY, but the bug, that was here, should be fixed. */ struct options * opt = (struct options*)skb->proto_priv; ! rt = ip_check_route(&sk->ip_route_cache, opt->srr?opt->faddr:iph->daddr, skb->localroute); } iph->id = htons(ip_id_count++); --- 492,499 ---- /* ANK: UGLY, but the bug, that was here, should be fixed. */ struct options * opt = (struct options*)skb->proto_priv; ! rt = ip_check_route(&sk->ip_route_cache, opt->srr?opt->faddr:iph->daddr, ! skb->localroute, sk->bound_device); } iph->id = htons(ip_id_count++); Only in linux-2.0.30.strip.iw/net/ipv4: tcp_output.c.orig diff -rc linux/net/ipv4/udp.c linux-2.0.30.strip.iw/net/ipv4/udp.c *** linux/net/ipv4/udp.c Tue Apr 8 08:47:47 1997 --- linux-2.0.30.strip.iw/net/ipv4/udp.c Sun Jun 29 23:54:17 1997 *************** *** 52,57 **** --- 52,58 ---- * David S. Miller : New socket lookup architecture for ISS. * Last socket cache retained as it * does have a high hit rate. + * Elliot Poger : Added support for SO_BINDTODEVICE. * * * This program is free software; you can redistribute it and/or *************** *** 130,135 **** --- 131,142 ---- if((sk2->num == snum) && (sk2 != sk)) { int sk2_reuse = sk2->reuse; + /* Two sockets can be bound to the same port if they're + * bound to different interfaces... */ + if (sk->bound_device != sk2->bound_device) { + continue; + } + if(!sk2->rcv_saddr || !sk->rcv_saddr) { if((!sk2_reuse) || (!sk_reuse)) { retval = 1; *************** *** 255,261 **** /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ ! __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport) { struct sock *sk, *result = NULL; unsigned short hnum = ntohs(dport); --- 262,269 ---- /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ ! __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, ! struct device *dev) { struct sock *sk, *result = NULL; unsigned short hnum = ntohs(dport); *************** *** 279,285 **** continue; score++; } ! if(score == 3) { result = sk; break; } else if(score > badness) { --- 287,301 ---- continue; score++; } ! /* If this socket is bound to a particular interface, ! * did the packet come in on it? */ ! if (sk->bound_device) { ! if (dev == sk->bound_device) ! score++; ! else ! continue; /* mismatch--not this sock */ ! } ! if(score == 4) { result = sk; break; } else if(score > badness) { *************** *** 308,314 **** struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr, unsigned short rnum, unsigned long laddr, ! unsigned long paddr, unsigned short pnum) { struct sock *s, *result = NULL; int badness = -1; --- 324,331 ---- struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr, unsigned short rnum, unsigned long laddr, ! unsigned long paddr, unsigned short pnum, ! struct device *dev) { struct sock *s, *result = NULL; int badness = -1; *************** *** 340,346 **** continue; score++; } ! if(score == 3 && s->num == hnum) { result = s; break; } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) { --- 357,370 ---- continue; score++; } ! /* If this socket is bound to a particular interface, ! * did the packet come in on it? */ ! if(s->bound_device) { ! if (s->bound_device != dev) ! continue; ! score++; ! } ! if(score == 4 && s->num == hnum) { result = s; break; } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) { *************** *** 363,369 **** unsigned short num, unsigned long raddr, unsigned short rnum, ! unsigned long laddr) { struct sock *s = sk; unsigned short hnum = ntohs(num); --- 387,394 ---- unsigned short num, unsigned long raddr, unsigned short rnum, ! unsigned long laddr, ! struct device *dev) { struct sock *s = sk; unsigned short hnum = ntohs(num); *************** *** 372,377 **** --- 397,403 ---- (s->dead && (s->state == TCP_CLOSE)) || (s->daddr && s->daddr!=raddr) || (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) || + ((s->bound_device) && (s->bound_device!=dev)) || (s->rcv_saddr && s->rcv_saddr != laddr)) continue; break; *************** *** 408,414 **** uh = (struct udphdr *)header; ! sk = udp_v4_lookup(daddr, uh->dest, saddr, uh->source); if (sk == NULL) return; /* No socket for error */ --- 434,440 ---- uh = (struct udphdr *)header; ! sk = udp_v4_lookup(daddr, uh->dest, saddr, uh->source, NULL); if (sk == NULL) return; /* No socket for error */ *************** *** 850,856 **** if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) return -EACCES; /* Must turn broadcast on first */ ! rt=ip_rt_route((__u32)usin->sin_addr.s_addr, sk->localroute); if (rt==NULL) return -ENETUNREACH; if(!sk->saddr) --- 876,882 ---- if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) return -EACCES; /* Must turn broadcast on first */ ! rt=ip_rt_route((__u32)usin->sin_addr.s_addr, sk->localroute, sk->bound_device); if (rt==NULL) return -ENETUNREACH; if(!sk->saddr) *************** *** 918,924 **** struct udphdr *uh = (struct udphdr *)(skb->h.raw + iph->ihl*4); struct sock *sk; ! sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest); if (!sk) return 0; /* 0 means accept all LOCAL addresses here, not all the world... */ --- 944,950 ---- struct udphdr *uh = (struct udphdr *)(skb->h.raw + iph->ihl*4); struct sock *sk; ! sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev); if (!sk) return 0; /* 0 means accept all LOCAL addresses here, not all the world... */ *************** *** 940,946 **** SOCKHASH_LOCK(); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; ! sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr); if(sk) { struct sock *sknext = NULL; --- 966,972 ---- SOCKHASH_LOCK(); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; ! sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr, skb->dev); if(sk) { struct sock *sknext = NULL; *************** *** 948,954 **** struct sk_buff *skb1 = skb; sknext = udp_v4_mcast_next(sk->next, uh->dest, saddr, ! uh->source, daddr); if(sknext) skb1 = skb_clone(skb, GFP_ATOMIC); --- 974,980 ---- struct sk_buff *skb1 = skb; sknext = udp_v4_mcast_next(sk->next, uh->dest, saddr, ! uh->source, daddr, skb->dev); if(sknext) skb1 = skb_clone(skb, GFP_ATOMIC); *************** *** 1066,1075 **** #ifdef CONFIG_IP_TRANSPARENT_PROXY if(skb->redirport) sk = udp_v4_proxy_lookup(uh->dest, saddr, uh->source, ! daddr, dev->pa_addr, skb->redirport); else #endif ! sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest); if (sk == NULL) { --- 1092,1101 ---- #ifdef CONFIG_IP_TRANSPARENT_PROXY if(skb->redirport) sk = udp_v4_proxy_lookup(uh->dest, saddr, uh->source, ! daddr, dev->pa_addr, skb->redirport, dev); else #endif ! sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, dev); if (sk == NULL) { Only in linux-2.0.30.strip.iw/net/ipv4: udp.c.orig