--- linux-2.4.1-orig/drivers/net/strip.c Tue Jul 11 11:12:24 2000 +++ linux/drivers/net/strip.c Sun Feb 11 16:21:51 2001 @@ -14,7 +14,7 @@ * 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.3 July 1997 + * Version: @(#)strip.c 1.4.2 February 2001 * * Author: Stuart Cheshire * @@ -66,15 +66,28 @@ * It is no longer necessarily to manually set the radio's * rate permanently to 115200 -- the driver handles setting * the rate automatically. + * + * Alex Belits: v1.4 September 2000 (AB) + * Added support for long serial numbers. + * + * v1.4.1 December 2000 (AB) + * Added tx_bytes and rx_bytes reporting in strip_get_stats(), + * removed packets rate warnings unless STRIP_VERBOSE_MESSAGES + * is enablled. + * + * v1.4.2 February 2001 (AB) + * Added support for longer (000-0000-0000) serial numbers. + * */ #ifdef MODULE -static const char StripVersion[] = "1.3-STUART.CHESHIRE-MODULAR"; +static const char StripVersion[] = "1.4.2-STUART.CHESHIRE-MODULAR"; #else -static const char StripVersion[] = "1.3-STUART.CHESHIRE"; +static const char StripVersion[] = "1.4.2-STUART.CHESHIRE"; #endif #define TICKLE_TIMERS 0 +#define STRIP_VERBOSE_MESSAGES 0 #define EXT_COUNTERS 1 @@ -288,6 +301,8 @@ struct strip *next; /* The next struct in the list */ struct strip **referrer; /* The pointer that points to us*/ + int pushing; /* Set when data is being pushed*/ + int woke_up; /* Set if woken up while pushing*/ int discard; /* Set if serial error */ int working; /* Is radio working correctly? */ int firmware_level; /* Message structuring level */ @@ -517,8 +532,10 @@ if (neighbor_entry->nud_state & NUD_VALID) { memcpy(haddr, neighbor_entry->ha, dev->addr_len); + neigh_release(neighbor_entry); return 1; } + neigh_release(neighbor_entry); } return 0; } @@ -897,20 +914,56 @@ * Convert a string to a Metricom Address. */ -#define IS_RADIO_ADDRESS(p) ( \ +#define IS_RADIO_ADDRESS_1(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 IS_RADIO_ADDRESS_2(p) ( \ + isdigit((p)[0]) && isdigit((p)[1]) && \ + (p)[2] == '-' && \ + isdigit((p)[3]) && isdigit((p)[4]) && isdigit((p)[5]) && isdigit((p)[6]) && \ + (p)[7] == '-' && \ + isdigit((p)[8]) && isdigit((p)[9]) && isdigit((p)[10]) && isdigit((p)[11]) ) + +#define IS_RADIO_ADDRESS_3(p) ( \ + isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && \ + (p)[3] == '-' && \ + isdigit((p)[4]) && isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && \ + (p)[8] == '-' && \ + isdigit((p)[9]) && isdigit((p)[10]) && isdigit((p)[11]) && isdigit((p)[12]) ) + static int string_to_radio_address(MetricomAddress *addr, __u8 *p) { - if (!IS_RADIO_ADDRESS(p)) return(1); + + if (IS_RADIO_ADDRESS_3(p)) + { + addr->c[0] = (READHEX(p[0]))^0xF; + addr->c[1] = (READHEX(p[1]) << 4 | READHEX(p[2])) ^ 0xFF; + addr->c[2] = READHEX(p[4]) << 4 | READHEX(p[5]); + addr->c[3] = READHEX(p[6]) << 4 | READHEX(p[7]); + addr->c[4] = READHEX(p[9]) << 4 | READHEX(p[10]); + addr->c[5] = READHEX(p[11]) << 4 | READHEX(p[12]); + }else{ + + if (IS_RADIO_ADDRESS_2(p)) + { + addr->c[0] = 0; + addr->c[1] = (READHEX(p[0]) << 4 | READHEX(p[1])) ^ 0xFF; + addr->c[2] = READHEX(p[3]) << 4 | READHEX(p[4]); + addr->c[3] = READHEX(p[5]) << 4 | READHEX(p[6]); + addr->c[4] = READHEX(p[8]) << 4 | READHEX(p[9]); + addr->c[5] = READHEX(p[10]) << 4 | READHEX(p[11]); + }else{ + if(!IS_RADIO_ADDRESS_1(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); } @@ -920,7 +973,17 @@ static __u8 *radio_address_to_string(const MetricomAddress *addr, MetricomAddressString *p) { + if(addr->c[0]) + { + sprintf(p->c, "%01X%02X-%02X%02X-%02X%02X", (addr->c[0] & 0xF)^ 0xF, addr->c[1] ^ 0xFF, addr->c[2], addr->c[3], addr->c[4], addr->c[5]); + }else{ + if(addr->c[1]) + { + sprintf(p->c, "%02X-%02X%02X-%02X%02X", addr->c[1] ^ 0xFF, addr->c[2], addr->c[3], addr->c[4], addr->c[5]); + }else{ sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], addr->c[4], addr->c[5]); + } + } return(p->c); } @@ -1343,6 +1406,45 @@ } /* + * Called to send the data through the tty driver + * + */ + +static void strip_push(struct strip *strip_info, struct tty_struct *tty) +{ + InterruptStatus intstat; + int num_written; + + if(strip_info->pushing) + { + printk(KERN_ERR + "%s: strip_push: pushing recursively -- should not happen\n", + strip_info->dev.name); + } + + intstat = DisableInterrupts(); + strip_info->pushing = 1; + do + { + strip_info->woke_up = 0; + RestoreInterrupts(intstat); + num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left); + intstat = DisableInterrupts(); + strip_info->tx_left -= num_written; + strip_info->tx_head += num_written; +#ifdef EXT_COUNTERS + strip_info->tx_sbytes += num_written; +#endif + } + while (strip_info->woke_up && strip_info->tx_left > 0); + /* Repeat if wakeup happened while pushing */ + + strip_info->pushing = 0; + RestoreInterrupts(intstat); +} + + +/* * Called by the driver when there's room for more data. If we have * more packets to send, we send them here. */ @@ -1356,6 +1458,16 @@ !netif_running(&strip_info->dev)) return; + /* Then check if we aren't already pushing something */ + + if (strip_info->pushing) + { + /* And if we are, we should set the flag and get out */ + strip_info->woke_up = 1; + return; + } + + if (strip_info->tx_left > 0) { /* @@ -1372,6 +1484,14 @@ * I disable interrupts around the call to tty->driver.write, although even * this might not work on a symmetric multi-processor system. */ + + /* + * Bug is in the eye of the beholder. In this case the original author + * severely misunderstood the techniques of dealing with this kind of + * kernel design. + */ + + /* InterruptStatus intstat = DisableInterrupts(); int num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left); strip_info->tx_left -= num_written; @@ -1380,6 +1500,10 @@ strip_info->tx_sbytes += num_written; #endif RestoreInterrupts(intstat); + */ + + strip_push(strip_info, tty); + } else /* Else start transmission of another packet */ { @@ -1439,9 +1563,10 @@ /* * If this is a broadcast packet, send it to our designated Metricom - * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) + * 'broadcast hub' radio (First byte of address being 0xF + * means broadcast) */ - if (haddr.c[0] == 0xFF) + if ((haddr.c[0] & 0xF0) == 0xF0) { u32 brd = 0; struct in_device *in_dev = in_dev_get(&strip_info->dev); @@ -1469,6 +1594,16 @@ *ptr++ = 0x0D; *ptr++ = '*'; + if(haddr.c[0]) + { + *ptr++ = hextable[(haddr.c[0] & 0xF) ^ 0xF]; + } + if(haddr.c[1]) + { + *ptr++ = hextable[(haddr.c[1] >> 4) ^ 0xF]; + *ptr++ = hextable[(haddr.c[1] & 0xF) ^ 0xF]; + *ptr++ = '-'; + } *ptr++ = hextable[haddr.c[2] >> 4]; *ptr++ = hextable[haddr.c[2] & 0xF]; *ptr++ = hextable[haddr.c[3] >> 4]; @@ -1494,6 +1629,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) { + InterruptStatus intstat; MetricomAddress haddr; unsigned char *ptr = strip_info->tx_buff; int doreset = (long)jiffies - strip_info->watchdog_doreset >= 0; @@ -1565,6 +1701,7 @@ /* * 3. Set up the strip_info ready to send the data (if any). */ + intstat = DisableInterrupts(); 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); @@ -1575,6 +1712,7 @@ 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); + RestoreInterrupts(intstat); /* * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in @@ -1673,6 +1811,7 @@ 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 STRIP_VERBOSE_MESSAGES 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); @@ -1682,6 +1821,7 @@ 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); +#endif } strip_send(strip_info, skb); @@ -2439,6 +2579,12 @@ stats.rx_packets = strip_info->rx_packets; stats.tx_packets = strip_info->tx_packets; + +#ifdef EXT_COUNTERS + stats.rx_bytes = strip_info->rx_bytes; + stats.tx_bytes = strip_info->tx_bytes; +#endif + stats.rx_dropped = strip_info->rx_dropped; stats.tx_dropped = strip_info->tx_dropped; stats.tx_errors = strip_info->tx_errors; @@ -2490,6 +2636,9 @@ strip_info->sx_count = 0; strip_info->tx_left = 0; + + strip_info->pushing = 0; + strip_info->woke_up = 0; strip_info->discard = 0; strip_info->working = FALSE;