📄 strip.c
字号:
} /* 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. * If the time is not in the near future, it returns the address of the * string "Not scheduled" The buffer must be long enough to contain the * ascii representation of the number plus 9 charactes for the " seconds" * and the null character. */static char *time_delta(char buffer[], long time){ time -= jiffies; if (time > LongTime / 2) return("Not scheduled"); if(time < 0) time = 0; /* Don't print negative times */ sprintf(buffer, "%ld seconds", time / HZ); 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; i<table->num_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 intsprintf_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; char* if_name = strip_info->dev.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); 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 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));}/************************************************************************//* Sending routines */static void ResetRadio(struct strip *strip_info){ struct tty_struct *tty = strip_info->tty; static const char init[] = "ate0q1dt**starmode\r**"; StringDescriptor s = { init, sizeof(init)-1 }; /* * If the radio isn't working anymore, * we should clear the old status information. */ if (strip_info->working) { printk(KERN_INFO "%s: No response: Resetting radio.\n", strip_info->dev.name); 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; /* If the user has selected a baud rate above 38.4 see what magic we have to do */ if (strip_info->user_baud > B38400) { /* * Subtle stuff: Pay attention :-) * If the serial port is currently at the user's selected (>38.4) rate, * then we temporarily switch to 19.2 and issue the ATS304 command * to tell the radio to switch to the user's selected rate. * If the serial port is not currently at that rate, that means we just * issued the ATS304 command last time through, so this time we restore * the user's selected rate and issue the normal starmode reset string. */ if (strip_info->user_baud == get_baud(tty)) { static const char b0[] = "ate0q1s304=57600\r"; static const char b1[] = "ate0q1s304=115200\r"; static const StringDescriptor baudstring[2] = { { b0, sizeof(b0)-1 }, { b1, sizeof(b1)-1 } }; set_baud(tty, B19200); if (strip_info->user_baud == B57600 ) s = baudstring[0]; else if (strip_info->user_baud == B115200) s = baudstring[1]; else s = baudstring[1]; /* For now */ } else set_baud(tty, strip_info->user_baud); } tty->driver.write(tty, 0, s.string, s.length);#ifdef EXT_COUNTERS strip_info->tx_ebytes += s.length;#endif}/* * Called by the driver when there's room for more data. If we have * more packets to send, we send them here. */static void strip_write_some_more(struct tty_struct *tty){ struct strip *strip_info = (struct strip *) tty->disc_data; /* First make sure we're connected. */ if (!strip_info || strip_info->magic != STRIP_MAGIC || !netif_running(&strip_info->dev)) return; if (strip_info->tx_left > 0) { /* * If some data left, send it * Note: There's a kernel design bug here. The write_wakeup routine has to * know how many bytes were written in the previous call, but the number of * bytes written is returned as the result of the tty->driver.write call, * and there's no guarantee that the tty->driver.write routine will have * returned before the write_wakeup routine is invoked. If the PC has fast * Serial DMA hardware, then it's quite possible that the write could complete * almost instantaneously, meaning that my write_wakeup routine could be * called immediately, before tty->driver.write has had a chance to return * the number of bytes that it wrote. In an attempt to guard against this, * I disable interrupts around the call to tty->driver.write, although even * this might not work on a symmetric multi-processor system. */ 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; 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 */ { tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); strip_unlock(strip_info); }}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; int len = skb->len - sizeof(STRIP_Header); MetricomKey key; /*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len);*/ if (header->protocol == htons(ETH_P_IP)) key = SIP0Key; else if (header->protocol == htons(ETH_P_ARP)) key = ARP0Key; else { printk(KERN_ERR "%s: strip_make_packet: Unknown packet type 0x%04X\n", strip_info->dev.name, ntohs(header->protocol)); return(NULL); } if (len > strip_info->mtu) { printk(KERN_ERR "%s: Dropping oversized transmit packet: %d bytes\n", strip_info->dev.name, len); 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))) { printk(KERN_ERR "%s: Dropping packet addressed to self\n", strip_info->dev.name); return(NULL); } /* * If this is a broadcast packet, send it to our designated Metricom * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) */ if (haddr.c[0] == 0xFF) { u32 brd = 0; struct in_device *in_dev = in_dev_get(&strip_info->dev); if (in_dev == NULL) return NULL; read_lock(&in_dev->lock); if (in_dev->ifa_list) brd = in_dev->ifa_list->ifa_broadcast; read_unlock(&in_dev->lock); in_dev_put(in_dev); /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ if (!arp_query(haddr.c, brd, &strip_info->dev)) { printk(KERN_ERR "%s: Unable to send packet (no broadcast hub configured)\n", strip_info->dev.name); return(NULL); } /* * If we are the broadcast hub, don't bother sending to ourselves. * (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]; *ptr++ = hextable[haddr.c[3] >> 4]; *ptr++ = hextable[haddr.c[3] & 0xF];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -