📄 ppp.c
字号:
* If this procedure returns 0, ppp_output_wakeup will be called * exactly once. */static intppp_async_send(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); ppp_tty_push(ppp); if (ppp->tpkt != NULL) return -1; ppp->tpkt = skb; ppp->tpkt_pos = 0; return ppp_tty_push(ppp);}/* * Push as much data as possible out to the tty. * Returns 1 if we finished encoding the current frame, 0 otherwise. */static intppp_tty_push(struct ppp *ppp){ int avail, sent, done = 0; struct tty_struct *tty = ppp2tty(ppp); if (ppp->flags & SC_SYNC) return ppp_tty_sync_push(ppp); CHECK_PPP(0); if (ppp->tty_pushing) { ppp->woke_up = 1; return 0; } if (tty == NULL || tty->disc_data != (void *) ppp) goto flush; while (ppp->optr < ppp->olim || ppp->tpkt != 0) { ppp->tty_pushing = 1; mb(); ppp->woke_up = 0; avail = ppp->olim - ppp->optr; if (avail > 0) { tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); sent = tty->driver.write(tty, 0, ppp->optr, avail); if (sent < 0) goto flush; /* error, e.g. loss of CD */ ppp->stats.ppp_obytes += sent; ppp->optr += sent; if (sent < avail) { wmb(); ppp->tty_pushing = 0; mb(); if (ppp->woke_up) continue; return done; } } if (ppp->tpkt != 0) done = ppp_async_encode(ppp); wmb(); ppp->tty_pushing = 0; } return done;flush: ppp->tty_pushing = 1; mb(); ppp->stats.ppp_oerrors++; if (ppp->tpkt != 0) { KFREE_SKB(ppp->tpkt); ppp->tpkt = 0; done = 1; } ppp->optr = ppp->olim; wmb(); ppp->tty_pushing = 0; return done;}/* * Procedure to encode the data for async serial transmission. * Does octet stuffing (escaping) and address/control * and protocol compression. * Assumes ppp->opkt != 0 on entry. * Returns 1 if we finished the current frame, 0 otherwise. */static intppp_async_encode(struct ppp *ppp){ int fcs, i, count, c; unsigned char *buf, *buflim; unsigned char *data; int islcp; CHECK_PPP(0); buf = ppp->obuf; ppp->olim = buf; ppp->optr = buf; i = ppp->tpkt_pos; data = ppp->tpkt->data; count = ppp->tpkt->len; fcs = ppp->tfcs; /* * LCP packets with code values between 1 (configure-reqest) * and 7 (code-reject) must be sent as though no options * had been negotiated. */ islcp = PPP_PROTOCOL(data) == PPP_LCP && 1 <= data[PPP_HDRLEN] && data[PPP_HDRLEN] <= 7; if (i == 0) { /* * Start of a new packet - insert the leading FLAG * character if necessary. */ if (islcp || flag_time == 0 || jiffies - ppp->last_xmit >= flag_time) *buf++ = PPP_FLAG; /* only reset idle time for data packets */ if (PPP_PROTOCOL(data) < 0x8000) ppp->last_xmit = jiffies; fcs = PPP_INITFCS; ++ppp->stats.ppp_opackets; ppp->stats.ppp_ooctects += count; /* * Do address/control compression */ if ((ppp->flags & SC_COMP_AC) != 0 && !islcp && PPP_ADDRESS(data) == PPP_ALLSTATIONS && PPP_CONTROL(data) == PPP_UI) i += 2; } /* * Once we put in the last byte, we need to put in the FCS * and closing flag, so make sure there is at least 7 bytes * of free space in the output buffer. */ buflim = buf + OBUFSIZE - 6; while (i < count && buf < buflim) { c = data[i++]; if (i == 3 && c == 0 && (ppp->flags & SC_COMP_PROT)) continue; /* compress protocol field */ fcs = PPP_FCS(fcs, c); if (in_xmap(ppp, c) || (islcp && c < 0x20)) { *buf++ = PPP_ESCAPE; c ^= 0x20; } *buf++ = c; } if (i == count) { /* * We have finished the packet. Add the FCS and flag. */ fcs = ~fcs; c = fcs & 0xff; if (in_xmap(ppp, c) || (islcp && c < 0x20)) { *buf++ = PPP_ESCAPE; c ^= 0x20; } *buf++ = c; c = (fcs >> 8) & 0xff; if (in_xmap(ppp, c) || (islcp && c < 0x20)) { *buf++ = PPP_ESCAPE; c ^= 0x20; } *buf++ = c; *buf++ = PPP_FLAG; ppp->olim = buf; KFREE_SKB(ppp->tpkt); ppp->tpkt = 0; return 1; } /* * Remember where we are up to in this packet. */ ppp->olim = buf; ppp->tpkt_pos = i; ppp->tfcs = fcs; return 0;}/* * Flush output from our internal buffers. * Called for the TCFLSH ioctl. */static voidppp_tty_flush_output(struct ppp *ppp){ struct sk_buff *skb; int done = 0; while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL) KFREE_SKB(skb); ppp->tty_pushing = 1; mb(); ppp->optr = ppp->olim; if (ppp->tpkt != NULL) { KFREE_SKB(ppp->tpkt); ppp->tpkt = 0; done = 1; } wmb(); ppp->tty_pushing = 0; if (done) ppp_output_wakeup(ppp);}/* * Callback function from tty driver. Return the amount of space left * in the receiver's buffer to decide if remote transmitter is to be * throttled. */static intppp_tty_room (struct tty_struct *tty){ return 65536; /* We can handle an infinite amount of data. :-) */}/* * Callback function when data is available at the tty driver. */static voidppp_tty_receive (struct tty_struct *tty, const __u8 * data, char *flags, int count){ register struct ppp *ppp = tty2ppp (tty); struct sk_buff *skb; int chr, flg; unsigned char *p; if (ppp != 0) CHECK_PPP_VOID(); /* * This can happen if stuff comes in on the backup tty. */ if (ppp == 0 || tty != ppp->tty) return; /* * Verify the table pointer and ensure that the line is * still in PPP discipline. */ if (ppp->magic != PPP_MAGIC) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "PPP: tty_receive called but couldn't find " "PPP struct.\n"); return; } /* * Print the buffer if desired */ if (ppp->flags & SC_LOG_RAWIN) ppp_print_buffer ("receive buffer", data, count); ppp->stats.ppp_ibytes += count; skb = ppp->rpkt; if ( ppp->flags & SC_SYNC ) { /* synchronous mode */ if (ppp->toss==0xE0) { /* this is the 1st frame, reset vj comp */ ppp_receive_error(ppp); ppp->toss = 0; } /* * Allocate an skbuff for frame. * The 128 is room for VJ header expansion. */ if (skb == NULL) skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN); if (skb == NULL) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "couldn't " "alloc skb for recv\n"); } else { LIBERATE_SKB(skb); /* * Decompress A/C and protocol compression here. */ p = skb_put(skb, 2); p[0] = PPP_ALLSTATIONS; p[1] = PPP_UI; if (*data == PPP_ALLSTATIONS) { data += 2; count -= 2; } if ((*data & 1) != 0) { p = skb_put(skb, 1); p[0] = 0; } /* copy frame to socket buffer */ p = skb_put(skb, count); memcpy(p,data,count); /* * Check if we've overflowed the MRU */ if (skb->len >= ppp->mru + PPP_HDRLEN + 2 || skb_tailroom(skb) <= 0) { ++ppp->estats.rx_length_errors; if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "rcv frame too long: " "len=%d mru=%d hroom=%d troom=%d\n", skb->len, ppp->mru, skb_headroom(skb), skb_tailroom(skb)); } else { if (!ppp_receive_frame(ppp, skb)) { KFREE_SKB(skb); ppp_receive_error(ppp); } } /* Reset for the next frame */ skb = NULL; } ppp->rpkt = skb; return; } while (count-- > 0) { /* * Collect the character and error condition for the character. * Set the toss flag for the first character error. */ chr = *data++; if (flags) { flg = *flags++; if (flg) { if (ppp->toss == 0) ppp->toss = flg; switch (flg) { case TTY_OVERRUN: ++ppp->estats.rx_fifo_errors; break; case TTY_FRAME: case TTY_BREAK: ++ppp->estats.rx_frame_errors; break; } continue; } } /* * Set the flags for d7 being 0/1 and parity being * even/odd so that the normal processing would have * all flags set at the end of the session. A * missing flag bit indicates an error condition. */#ifdef CHECK_CHARACTERS if (chr & 0x80) ppp->flags |= SC_RCV_B7_1; else ppp->flags |= SC_RCV_B7_0; if (paritytab[chr >> 5] & (1 << (chr & 0x1F))) ppp->flags |= SC_RCV_ODDP; else ppp->flags |= SC_RCV_EVNP;#endif if (chr == PPP_FLAG) { /* * FLAG. This is the end of the block. If the block * ends with ESC FLAG, then the block is to be ignored. */ if (ppp->escape) ppp->toss |= 0x80; /* * Process the frame if it was received correctly. * If there was an error, let the VJ decompressor know. * There are 4 cases here: * skb != NULL, toss != 0: error in frame * skb != NULL, toss == 0: frame ok * skb == NULL, toss != 0: very first frame, * error on 1st char, or alloc_skb failed * skb == NULL, toss == 0: empty frame (~~) */ if (ppp->toss || !ppp_receive_frame(ppp, skb)) { if (ppp->toss && (ppp->flags & SC_DEBUG)) printk(KERN_DEBUG "ppp: tossing frame (%x)\n", ppp->toss); if (skb != NULL) KFREE_SKB(skb); if (!(ppp->toss == 0xE0 || ppp->toss == 0x80)) ++ppp->stats.ppp_ierrors; ppp_receive_error(ppp); } /* * Reset for the next frame. */ skb = NULL; ppp->rfcs = PPP_INITFCS; ppp->escape = 0; ppp->toss = 0; continue; } /* If we're tossing, look no further. */ if (ppp->toss != 0) continue; /* If this is a control char to be ignored, do so */ if (in_rmap(ppp, chr)) continue; /* * Modify the next character if preceded by escape. * The escape character (0x7d) could be an escaped * 0x5d, if it follows an escape :-) */ if (ppp->escape) { chr ^= PPP_TRANS; ppp->escape = 0; } else if (chr == PPP_ESCAPE) { ppp->escape = PPP_TRANS; continue; } /* * Allocate an skbuff on the first character received. * The 128 is room for VJ header expansion and FCS. */ if (skb == NULL) { skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN); if (skb == NULL) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "couldn't " "alloc skb for recv\n"); ppp->toss = 1; continue; } LIBERATE_SKB(skb); } /* * Decompress A/C and protocol compression here. */ if (skb->len == 0 && chr != PPP_ALLSTATIONS) { p = skb_put(skb, 2); p[0] = PPP_ALLSTATIONS; p[1] = PPP_UI; } if (skb->len == 2 && (chr & 1) != 0) { p = skb_put(skb, 1); p[0] = 0; } /* * Check if we've overflowed the MRU */ if (skb->len >= ppp->mru + PPP_HDRLEN + 2 || skb_tailroom(skb) <= 0) { ++ppp->estats.rx_length_errors; ppp->toss = 0xC0; if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "rcv frame too long: " "len=%d mru=%d hroom=%d troom=%d\n", skb->len, ppp->mru, skb_headroom(skb), skb_tailroom(skb)); continue; } /* * Store the character and update the FCS. */ p = skb_put(skb, 1); *p = chr; ppp->rfcs = PPP_FCS(ppp->rfcs, chr); } ppp->rpkt = skb;}/************************************************************* * PPP NETWORK INTERFACE SUPPORT * The following code implements the PPP network * interface device and handles those parts of * the PPP processing which are independent of the * type of hardware link being used, including * VJ and packet compression. *************************************************************//* * Network device driver callback routines */static int ppp_init_dev(struct device *dev);static int ppp_dev_open(struct device *);static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd);static int ppp_dev_close(struct device *);static int ppp_dev_xmit(struct sk_buff *, struct device *);static struct net_device_stats *ppp_dev_stats (struct device *);#if LINUX_VERSION_CODE < VERSION(2,1,15)static int ppp_dev_header(struct sk_buff *, struct device *, __u16, void *, void *, unsigned int);static int ppp_dev_rebuild(void *eth, struct device *dev, unsigned long raddr, struct sk_buff *skb);#endif/* * Information for the protocol decoder */typedef int (*pfn_proto) (struct ppp *, struct sk_buff *);typedef struct ppp_proto_struct { int proto; pfn_proto func;} ppp_proto_type;static int rcv_proto_ip (struct ppp *, struct sk_buff *);static int rcv_proto_ipv6 (struct ppp *, struct sk_buff *);static int rcv_proto_ipx (struct ppp *, struct sk_buff *);static int rcv_proto_at (struct ppp *, struct sk_buff *);static int rcv_proto_vjc_comp (struct ppp *, struct sk_buff *);static int rcv_proto_vjc_uncomp (struct ppp *, struct sk_buff *);static int rcv_proto_ccp (struct ppp *, struct sk_buff *);static int rcv_proto_unknown (struct ppp *, struct sk_buff *);staticppp_proto_type proto_list[] = { { PPP_IP, rcv_proto_ip }, { PPP_IPV6, rcv_proto_ipv6 }, { PPP_IPX, rcv_proto_ipx }, { PPP_AT, rcv_proto_at }, { PPP_VJC_COMP, rcv_proto_vjc_comp }, { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp }, { PPP_CCP, rcv_proto_ccp }, { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */};/* * Called when the PPP network interface device is actually created. */static intppp_init_dev (struct device *dev){ dev->hard_header_len = PPP_HDRLEN;#if LINUX_VERSION_CODE < VERSION(2,1,15) dev->hard_header = ppp_dev_header;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -