📄 strip.c
字号:
*dst++ = *src ^ Stuff_Magic; count++; } src++; /* Consume the byte */ break; } if (count == Stuff_MaxCount) { StuffData_FinishBlock(code + count); } } if (code == Stuff_NoCode) { *code_ptr_ptr = NULL; } else { *code_ptr_ptr = code_ptr; StuffData_FinishBlock(code + count); } return(dst);}/* * UnStuffData decodes the data at "src", up to (but not including) "end". * It writes the decoded data into the buffer pointed to by "dst", up to a * maximum of "dst_length", and returns the new value of "src" so that a * follow-on call can read more data, continuing from where the first left off. * * There are three types of results: * 1. The source data runs out before extracting "dst_length" bytes: * UnStuffData returns NULL to indicate failure. * 2. The source data produces exactly "dst_length" bytes: * UnStuffData returns new_src = end to indicate that all bytes were consumed. * 3. "dst_length" bytes are extracted, with more remaining. * UnStuffData returns new_src < end to indicate that there are more bytes * to be read. * * Note: The decoding may be destructive, in that it may alter the source * data in the process of decoding it (this is necessary to allow a follow-on * call to resume correctly). */static __u8 *UnStuffData(__u8 *src, __u8 *end, __u8 *dst, __u32 dst_length){ __u8 *dst_end = dst + dst_length; /* Sanity check */ if (!src || !end || !dst || !dst_length) return(NULL); while (src < end && dst < dst_end) { int count = (*src ^ Stuff_Magic) & Stuff_CountMask; switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) { case Stuff_Diff: if (src+1+count >= end) return(NULL); do { *dst++ = *++src ^ Stuff_Magic; } while(--count >= 0 && dst < dst_end); if (count < 0) src += 1; else { if (count == 0) *src = Stuff_Same ^ Stuff_Magic; else *src = (Stuff_Diff + count) ^ Stuff_Magic; } break; case Stuff_DiffZero: if (src+1+count >= end) return(NULL); do { *dst++ = *++src ^ Stuff_Magic; } while(--count >= 0 && dst < dst_end); if (count < 0) *src = Stuff_Zero ^ Stuff_Magic; else *src = (Stuff_DiffZero + count) ^ Stuff_Magic; break; case Stuff_Same: if (src+1 >= end) return(NULL); do { *dst++ = src[1] ^ Stuff_Magic; } while(--count >= 0 && dst < dst_end); if (count < 0) src += 2; else *src = (Stuff_Same + count) ^ Stuff_Magic; break; case Stuff_Zero: do { *dst++ = 0; } while(--count >= 0 && dst < dst_end); if (count < 0) src += 1; else *src = (Stuff_Zero + count) ^ Stuff_Magic; break; } } if (dst < dst_end) return(NULL); else return(src);}/************************************************************************//* General routines for STRIP *//* * get_baud returns the current baud rate, as one of the constants defined in * termbits.h * If the user has issued a baud rate override using the 'setserial' command * and the logical current rate is set to 38.4, then the true baud rate * currently in effect (57.6 or 115.2) is returned. */static unsigned int get_baud(struct tty_struct *tty) { if (!tty || !tty->termios) return(0); if ((tty->termios->c_cflag & CBAUD) == B38400 && tty->driver_data) { struct async_struct *info = (struct async_struct *)tty->driver_data; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI ) return(B57600); if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) return(B115200); } return(tty->termios->c_cflag & CBAUD); }/* * set_baud sets the baud rate to the rate defined by baudcode * Note: The rate B38400 should be avoided, because the user may have * issued a 'setserial' speed override to map that to a different speed. * We could achieve a true rate of 38400 if we needed to by cancelling * any user speed override that is in place, but that might annoy the * user, so it is simplest to just avoid using 38400. */static void set_baud(struct tty_struct *tty, unsigned int baudcode) { struct termios old_termios = *(tty->termios); tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */ tty->termios->c_cflag |= baudcode; /* Set the new baud setting */ tty->driver.set_termios(tty, &old_termios); }/* * Convert a string to a Metricom Address. */#define IS_RADIO_ADDRESS(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]) )static int string_to_radio_address(MetricomAddress *addr, __u8 *p){ if (!IS_RADIO_ADDRESS(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);}/* * Convert a Metricom Address to a string. */static __u8 *radio_address_to_string(const MetricomAddress *addr, MetricomAddressString *p){ sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], addr->c[4], addr->c[5]); return(p->c);}/* * Note: Must make sure sx_size is big enough to receive a stuffed * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's * big enough to receive a large radio neighbour list (currently 4K). */static int allocate_buffers(struct strip *strip_info){ struct net_device *dev = &strip_info->dev; int sx_size = MAX(STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096); int tx_size = STRIP_ENCAP_SIZE(dev->mtu) + MaxCommandStringLength; __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC); __u8 *s = kmalloc(sx_size, GFP_ATOMIC); __u8 *t = kmalloc(tx_size, GFP_ATOMIC); if (r && s && t) { strip_info->rx_buff = r; strip_info->sx_buff = s; strip_info->tx_buff = t; strip_info->sx_size = sx_size; strip_info->tx_size = tx_size; strip_info->mtu = dev->mtu; return(1); } if (r) kfree(r); if (s) kfree(s); if (t) kfree(t); return(0);}/* * MTU has been changed by the IP layer. Unfortunately we are not told * about this, but we spot it ourselves and fix things up. We could be in * an upcall from the tty driver, or in an ip packet queue. */static void strip_changedmtu(struct strip *strip_info){ int old_mtu = strip_info->mtu; struct net_device *dev = &strip_info->dev; unsigned char *orbuff = strip_info->rx_buff; unsigned char *osbuff = strip_info->sx_buff; unsigned char *otbuff = strip_info->tx_buff; InterruptStatus intstat; if (dev->mtu > MAX_SEND_MTU) { printk(KERN_ERR "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", strip_info->dev.name, MAX_SEND_MTU); dev->mtu = old_mtu; return; } /* * Have to disable interrupts here because we're reallocating and resizing * the serial buffers, and we can't have data arriving in them while we're * moving them around in memory. This may cause data to be lost on the serial * port, but hopefully people won't change MTU that often. * Also note, this may not work on a symmetric multi-processor system. */ intstat = DisableInterrupts(); if (!allocate_buffers(strip_info)) { RestoreInterrupts(intstat); printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", strip_info->dev.name); dev->mtu = old_mtu; return; } if (strip_info->sx_count) { if (strip_info->sx_count <= strip_info->sx_size) memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count); else { strip_info->discard = strip_info->sx_count; strip_info->rx_over_errors++; } } if (strip_info->tx_left) { if (strip_info->tx_left <= strip_info->tx_size) memcpy(strip_info->tx_buff, strip_info->tx_head, strip_info->tx_left); else { strip_info->tx_left = 0; strip_info->tx_dropped++; } } strip_info->tx_head = strip_info->tx_buff; RestoreInterrupts(intstat); printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", strip_info->dev.name, old_mtu, strip_info->mtu); if (orbuff) kfree(orbuff); if (osbuff) kfree(osbuff); if (otbuff) kfree(otbuff);}static void strip_unlock(struct strip *strip_info){ /* * Set the timer to go off in one second. */ strip_info->idle_timer.expires = jiffies + 1*HZ; add_timer(&strip_info->idle_timer); netif_wake_queue(&strip_info->dev);}/************************************************************************//* Callback routines for exporting information through /proc *//* * This function updates the total amount of data printed so far. It then * determines if the amount of data printed into a buffer has reached the * offset requested. If it hasn't, then the buffer is shifted over so that * the next bit of data can be printed over the old bit. If the total * amount printed so far exceeds the total amount requested, then this * function returns 1, otherwise 0. */static int shift_buffer(char *buffer, int requested_offset, int requested_len, int *total, int *slop, char **buf){ int printed; /* printk(KERN_DEBUG "shift: buffer: %d o: %d l: %d t: %d buf: %d\n", (int) buffer, requested_offset, requested_len, *total, (int) *buf); */ printed = *buf - buffer; if (*total + printed <= requested_offset) { *total += printed; *buf = buffer; } else { if (*total < requested_offset) { *slop = requested_offset - *total; } *total = requested_offset + printed - *slop; } if (*total > requested_offset + requested_len) { return 1; } else { return 0; }}/* * This function calculates the actual start of the requested data * in the buffer. It also calculates actual length of data returned, * which could be less that the amount of data requested. */static intcalc_start_len(char *buffer, char **start, int requested_offset, int requested_len, int total, char *buf){ int return_len, buffer_len; buffer_len = buf - buffer; if (buffer_len >= 4095) { printk(KERN_ERR "STRIP: exceeded /proc buffer size\n"); } /* * There may be bytes before and after the * chunk that was actually requested. */ return_len = total - requested_offset; if (return_len < 0) { return_len = 0; } *start = buf - return_len; if (return_len > requested_len) { return_len = requested_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -