📄 strip.c
字号:
/* * Copyright 1996 The Board of Trustees of The Leland Stanford * Junior University. All Rights Reserved. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. Stanford University * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * * strip.c This module implements Starmode Radio IP (STRIP) * 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 * * Author: Stuart Cheshire <cheshire@cs.stanford.edu> * * 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 * * v1.3 July 1997 (SC) * Made STRIP driver set the radio's baud rate automatically. * It is no longer necessarily to manually set the radio's * rate permanently to 115200 -- the driver handles setting * the rate automatically. */#ifdef MODULEstatic const char StripVersion[] = "1.3A-STUART.CHESHIRE-MODULAR";#elsestatic const char StripVersion[] = "1.3A-STUART.CHESHIRE";#endif#define TICKLE_TIMERS 0#define EXT_COUNTERS 1/************************************************************************//* Header files */#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/uaccess.h># include <linux/ctype.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/tty.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/inetdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/if_strip.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/serial.h>#include <linux/serialP.h>#include <linux/rcupdate.h>#include <net/arp.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/time.h>/************************************************************************//* Useful structures and definitions *//* * A MetricomKey identifies the protocol being carried inside a Metricom * Starmode packet. */typedef union { __u8 c[4]; __u32 l;} MetricomKey;/* * An IP address can be viewed as four bytes in memory (which is what it is) or as * a single 32-bit long (which is convenient for assignment, equality testing etc.) */typedef union { __u8 b[4]; __u32 l;} IPaddr;/* * A MetricomAddressString is used to hold a printable representation of * a Metricom address. */typedef struct { __u8 c[24];} MetricomAddressString;/* Encapsulation can expand packet of size x to 65/64x + 1 * Sent packet looks like "<CR>*<address>*<key><encaps payload><CR>" * 1 1 1-18 1 4 ? 1 * eg. <CR>*0000-1234*SIP0<encaps payload><CR> * We allow 31 bytes for the stars, the key, the address and the <CR>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 { MetricomAddress dst_addr; /* Destination address, e.g. "0000-1234" */ MetricomAddress src_addr; /* Source address, e.g. "0000-5678" */ unsigned short protocol; /* The protocol type, using Ethernet codes */} STRIP_Header;typedef struct { char c[60];} MetricomNode;#define NODE_TABLE_SIZE 32typedef struct { struct timeval timestamp; int num_nodes; MetricomNode node[NODE_TABLE_SIZE];} MetricomNodeTable;enum { FALSE = 0, TRUE = 1 };/* * Holds the radio's firmware version. */typedef struct { char c[50];} FirmwareVersion;/* * Holds the radio's serial number. */typedef struct { char c[18];} SerialNumber;/* * Holds the radio's battery voltage. */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 */};struct strip { int magic; /* * These are pointers to the malloc()ed frame buffers. */ unsigned char *rx_buff; /* buffer for received IP packet */ unsigned char *sx_buff; /* buffer for received serial data */ int sx_count; /* received serial data counter */ int sx_size; /* Serial buffer size */ unsigned char *tx_buff; /* transmitter buffer */ unsigned char *tx_head; /* pointer to next byte to XMIT */ int tx_left; /* bytes left in XMIT queue */ int tx_size; /* Serial buffer size */ /* * STRIP interface statistics. */ unsigned long rx_packets; /* inbound frames counter */ unsigned long tx_packets; /* outbound frames counter */ unsigned long rx_errors; /* Parity, etc. errors */ unsigned long tx_errors; /* Planned stuff */ unsigned long rx_dropped; /* No memory for skb */ 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. */ struct list_head list; /* Linked list of devices */ int discard; /* Set if serial error */ int working; /* Is radio working correctly? */ int firmware_level; /* Message structuring level */ int next_command; /* Next periodic command */ unsigned int user_baud; /* The user-selected baud rate */ 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 */ struct net_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";static const MetricomAddress zero_address;static const MetricomAddress broadcast_address = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} };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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -