📄 strip.c
字号:
/* 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) { int num_written = tty->driver->write(tty, 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 } 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; rcu_read_lock(); in_dev = __in_dev_get_rcu(strip_info->dev); if (in_dev == NULL) { rcu_read_unlock(); return NULL; } if (in_dev->ifa_list) brd = in_dev->ifa_list->ifa_broadcast; rcu_read_unlock(); /* 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]; *ptr++ = '-'; *ptr++ = hextable[haddr.c[4] >> 4]; *ptr++ = hextable[haddr.c[4] & 0xF]; *ptr++ = hextable[haddr.c[5] >> 4]; *ptr++ = hextable[haddr.c[5] & 0xF]; *ptr++ = '*'; *ptr++ = key.c[0]; *ptr++ = key.c[1]; *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);}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; u32 addr, brd; /* * 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 <CR> */ /* Cycle to next periodic command? */ if (strip_info->firmware_level >= StructuredMessages) if (++strip_info->next_command >= ARRAY_SIZE(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; } if (1) { struct in_device *in_dev; brd = addr = 0; rcu_read_lock(); in_dev = __in_dev_get_rcu(strip_info->dev); if (in_dev) { if (in_dev->ifa_list) { brd = in_dev->ifa_list->ifa_broadcast; addr = in_dev->ifa_list->ifa_local; } } rcu_read_unlock(); } /* * 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, brd, strip_info->dev)) { /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", strip_info->dev->name, strip_info->arp_interval / HZ); */ strip_info->gratuitous_arp = jiffies + strip_info->arp_interval; strip_info->arp_interval *= 2; if (strip_info->arp_interval > MaxARPInterval) strip_info->arp_interval = MaxARPInterval; if (addr) arp_send(ARPOP_REPLY, ETH_P_ARP, addr, /* Target address of ARP packet is our address */ strip_info->dev, /* Device to send packet on */ 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);}/* Encapsulate a datagram and kick it into a TTY queue. */static int strip_xmit(struct sk_buff *skb, struct net_device *dev){ struct strip *strip_info = netdev_priv(dev); if (!netif_running(dev)) { printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); return (1); } netif_stop_queue(dev); del_timer(&strip_info->idle_timer); 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); } spin_lock_bh(&strip_lock); strip_send(strip_info, skb); spin_unlock_bh(&strip_lock); if (skb) dev_kfree_skb(skb); return 0;}/* * 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 net_device *) parameter);}/* * Create the MAC header for an arbitrary protocol layer * * saddr!=NULL means use this specific address (n/a for Metricom) * saddr==NULL means use default device source address * daddr!=NULL means use this destination address * daddr==NULL means leave destination address alone * (e.g. unresolved arp -- kernel will call * rebuild_header later to fill in the address) */static int strip_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len){ struct strip *strip_info = netdev_priv(dev); 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", netdev_priv(dev), skb->data, skb->data + skb->len); */ if (!daddr) return (-dev->hard_header_len); header->dst_addr = *(MetricomAddress *) daddr; return (dev->hard_header_len);}/* * Rebuild the MAC header. This is called after an ARP * (or in future other address resolution) has completed on this * sk_buff. We now let ARP fill in the other fields. * I think this should return zero if packet is ready to send, * or non-zero if it needs more time to do an address lookup */static int strip_rebuild_header(struct sk_buff *skb){#ifdef CONFIG_INET STRIP_Header *header = (STRIP_Header *) skb->data; /* Arp find returns zero if if knows the address, */ /* or if it doesn't know the address it sends an ARP packet and returns non-zero */ return arp_find(header->dst_addr.c, skb) ? 1 : 0;#else return 0;#endif}/************************************************************************//* Receiving routines */static int strip_receive_room(struct tty_struct *tty){ return 0x10000; /* We can handle an infinite amount of data. :-) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -