📄 strip.c
字号:
}/* * 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_t(int, 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 (%zd) 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 (%zd) 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){ __u8 *ptr = strip_info->sx_buff; __u8 *end = strip_info->sx_buff + strip_info->sx_count; DumpData(msg, strip_info, ptr, end); strip_info->rx_errors++;}static void RecvErr_Message(struct strip *strip_info, __u8 * sendername, const __u8 * msg, u_long len){ if (has_prefix(msg, len, "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, len, "002")) { /* Remap handle */ /* We ignore "Remap handle" messages for now */ } else if (has_prefix(msg, len, "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, len, "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) { /* * If this message has a valid checksum on the end, then the call to verify_checksum * will elevate the firmware_level to ChecksummedMessages for us. (The actual return * code from verify_checksum is ignored here.) */ 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, len, "005")) /* Bad count specification */ RecvErr("Error Msg:", strip_info); else if (has_prefix(msg, len, "006")) /* Header too big */ RecvErr("Error Msg:", strip_info); else if (has_prefix(msg, len, "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, len, "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, len, "009")) /* No count or line terminator */ RecvErr("Error Msg:", strip_info); else if (has_prefix(msg, len, "010")) /* Invalid checksum */ RecvErr("Error Msg:", strip_info); else if (has_prefix(msg, len, "011")) /* Checksum didn't match */ RecvErr("Error Msg:", strip_info); else if (has_prefix(msg, len, "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){ u_long len; __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. */ len = p - ptr;#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, len, "ATS300?")) get_radio_version(strip_info, p, end); else if (has_prefix(ptr, len, "ATS305?")) get_radio_address(strip_info, p); else if (has_prefix(ptr, len, "ATS311?")) get_radio_neighbours(&strip_info->poletops, p, end); else if (has_prefix(ptr, len, "ATS319=7")) verify_checksum(strip_info); else if (has_prefix(ptr, len, "ATS325?")) get_radio_voltage(strip_info, p, end); else if (has_prefix(ptr, len, "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 net_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 net_device *dev; read_lock_bh(&dev_base_lock); 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); read_unlock_bh(&dev_base_lock); return (dev); } dev = dev->next; } read_unlock_bh(&dev_base_lock); } return (strip_info->dev);}/* * Send one completely decapsulated datagram to the next layer. */static void deliver_packet(struct strip *strip_info, STRIP_Header * header, __u16 packetlen){ 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; /* Having put a fake header on the front of the sk_buff for the */ /* benefit of tools like tcpdump, skb_pull now 'consumes' that */ /* fake header before we hand the packet up to the next layer. */ skb_pull(skb, sizeof(STRIP_Header)); /* 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 skb->dev->last_rx = jiffies; netif_rx(skb); }}static void process_IP_packet(struct strip *strip_info, STRIP_Header * header, __u8 * ptr, __u8 * end){ __u16 packetlen; /* Decode start of the IP packet header */ ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); if (!ptr) { RecvErr("IP Packet too short", strip_info); return; } 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; } /*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev->name, packetlen); */ /* Decode remainder of the IP packet */ ptr = UnStuffData(ptr, end, strip_info->rx_buff + 4, packetlen - 4); if (!ptr) { RecvErr("IP Packet too short", strip_info); return; } if (ptr < end) { RecvErr("IP Packet too long", strip_info); return; } header->protocol = htons(ETH_P_IP); deliver_packet(strip_info, header, packetlen);}static void process_ARP_packet(struct strip *strip_info, STRIP_Header * header, __u8 * ptr, __u8 * end){ __u16 packetlen; struct arphdr *arphdr = (struct arphdr *) strip_info->rx_buff; /* Decode start of the ARP packet */ ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8); if (!ptr) { RecvErr("ARP Packet too short", strip_info); return; } 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+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -