📄 ppp.c
字号:
rcvd, CCP_CODE(dp), ppp->flags); save_flags(flags); switch (CCP_CODE(dp)) { case CCP_CONFREQ: case CCP_TERMREQ: case CCP_TERMACK: /* * CCP must be going down - disable compression */ if (ppp->flags & SC_CCP_UP) { cli(); ppp->flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); } break; case CCP_CONFACK: if ((ppp->flags & SC_CCP_OPEN) == 0) break; if (ppp->flags & SC_CCP_UP) break; if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN)) break; if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN)) break; if (!rcvd) { /* * we're agreeing to send compressed packets. */ if (ppp->sc_xc_state == NULL) break; if ((*ppp->sc_xcomp->comp_init) (ppp->sc_xc_state, opt, opt_len, ppp->line, 0, ppp->flags & SC_DEBUG)) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: comp running\n", ppp->name); cli(); ppp->flags |= SC_COMP_RUN; } break; } /* * peer is agreeing to send compressed packets. */ if (ppp->sc_rc_state == NULL) break; if ((*ppp->sc_rcomp->decomp_init) (ppp->sc_rc_state, opt, opt_len, ppp->line, 0, ppp->mru, ppp->flags & SC_DEBUG)) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: decomp running\n", ppp->name); cli(); ppp->flags |= SC_DECOMP_RUN; ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); } break; case CCP_RESETACK: /* * CCP Reset-ack resets compressors and decompressors * as it passes through. */ if ((ppp->flags & SC_CCP_UP) == 0) break; if (!rcvd) { if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN)) { (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state); if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: comp reset\n", ppp->name); } } else { if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) { (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state); if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: decomp reset\n", ppp->name); cli(); ppp->flags &= ~SC_DC_ERROR; } } break; } restore_flags(flags);}/* * CCP is down; free (de)compressor state if necessary. */static voidppp_ccp_closed(struct ppp *ppp){ unsigned long flags; save_flags(flags); cli(); ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); restore_flags(flags); if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: ccp closed\n", ppp->name); if (ppp->sc_xc_state) { (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state); ppp->sc_xc_state = NULL; } if (ppp->sc_rc_state) { (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state); ppp->sc_rc_state = NULL; }}/************************************************************* * RECEIVE-SIDE ROUTINES *************************************************************//* * On entry, a received frame is in skb. * Check it and dispose as appropriate. */static intppp_receive_frame(struct ppp *ppp, struct sk_buff *skb){ __u8 *data; int count; int proto; int new_count; struct sk_buff *new_skb; ppp_proto_type *proto_ptr; /* * An empty frame is ignored. This occurs if the FLAG sequence * precedes and follows each frame. */ if (skb == NULL) return 1; if (skb->len == 0) { kfree_skb(skb); return 1; } data = skb->data; count = skb->len; /* * Generate an error if the frame is too small. */ if (count < PPP_HDRLEN + 2) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "ppp: got runt ppp frame, %d chars\n", count); ++ppp->estats.rx_length_errors; return 0; } /* * Verify the FCS of the frame and discard the FCS characters * from the end of the buffer. */ if (ppp->rfcs != PPP_GOODFCS) { if (ppp->flags & SC_DEBUG) { printk(KERN_DEBUG "ppp: frame with bad fcs, length = %d\n", count); ppp_print_buffer("bad frame", data, count); } ++ppp->estats.rx_crc_errors; return 0; } count -= 2; /* ignore the fcs characters */ skb_trim(skb, count); /* * Process the active decompressor. */ if (ppp->sc_rc_state != NULL && (ppp->flags & SC_DECOMP_RUN) && ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) { if (PPP_PROTOCOL(data) == PPP_COMP) { /* * If the frame is compressed then decompress it. */ new_skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN); if (new_skb == NULL) { printk(KERN_ERR "ppp_recv_frame: no memory\n"); new_count = DECOMP_ERROR; } else { new_count = (*ppp->sc_rcomp->decompress) (ppp->sc_rc_state, data, count, new_skb->data, ppp->mru + PPP_HDRLEN); } if (new_count > 0) { /* Frame was decompressed OK */ kfree_skb(skb); skb = new_skb; count = new_count; data = skb_put(skb, count); } else { /* * On a decompression error, we pass the * compressed frame up to pppd as an * error indication. */ if (ppp->flags & SC_DEBUG) printk(KERN_INFO "%s: decomp err %d\n", ppp->name, new_count); if (new_skb != 0) kfree_skb(new_skb); if (ppp->slcomp != 0) slhc_toss(ppp->slcomp); ++ppp->stats.ppp_ierrors; if (new_count == DECOMP_FATALERROR) { ppp->flags |= SC_DC_FERROR; } else { ppp->flags |= SC_DC_ERROR; } } } else { /* * The frame is not compressed. Pass it to the * decompression code so it can update its * dictionary if necessary. */ (*ppp->sc_rcomp->incomp)(ppp->sc_rc_state, data, count); } } else if (PPP_PROTOCOL(data) == PPP_COMP && (ppp->flags & SC_DEBUG)) printk(KERN_INFO "%s: not decomp, rc_state=%p flags=%x\n", ppp->name, ppp->sc_rc_state, ppp->flags); /* * Count the frame and print it */ ++ppp->stats.ppp_ipackets; ppp->stats.ppp_ioctects += count; if (ppp->flags & SC_LOG_INPKT) ppp_print_buffer ("receive frame", data, count); /* * Find the procedure to handle this protocol. * The last one is marked as protocol 0 which is the 'catch-all' * to feed it to the pppd daemon. */ proto = PPP_PROTOCOL(data); proto_ptr = proto_list; while (proto_ptr->proto != 0 && proto_ptr->proto != proto) ++proto_ptr; /* * Update the appropriate statistic counter. */ if (!(*proto_ptr->func)(ppp, skb)) { kfree_skb(skb); ++ppp->stats.ppp_discards; } return 1;}/* * An input error has been detected, so we need to inform * the VJ decompressor. */static voidppp_receive_error(struct ppp *ppp){ CHECK_PPP_VOID(); if (ppp->slcomp != 0) slhc_toss(ppp->slcomp);}/* * Put the input frame into the networking system for the indicated protocol */static intppp_rcv_rx(struct ppp *ppp, __u16 proto, struct sk_buff *skb){ /* * Fill in a few fields of the skb and give it to netif_rx(). */ skb->dev = ppp2dev(ppp); /* We are the device */ skb->protocol = htons(proto); skb_pull(skb, PPP_HDRLEN); /* pull off ppp header */ skb->mac.raw = skb->data; ppp->last_recv = jiffies; netif_rx (skb); return 1;}/* * Process the receipt of an IP frame */static intrcv_proto_ip(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0) && ppp->sc_npmode[NP_IP] == NPMODE_PASS) return ppp_rcv_rx(ppp, ETH_P_IP, skb); return 0;}/* * Process the receipt of an IPv6 frame */static intrcv_proto_ipv6(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0) && ppp->sc_npmode[NP_IPV6] == NPMODE_PASS) return ppp_rcv_rx(ppp, ETH_P_IPV6, skb); return 0;}/* * Process the receipt of an IPX frame */static intrcv_proto_ipx(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); if (((ppp2dev(ppp)->flags & IFF_UP) != 0) && (skb->len > 0) && ppp->sc_npmode[NP_IPX] == NPMODE_PASS) return ppp_rcv_rx(ppp, ETH_P_IPX, skb); return 0;}/* * Process the receipt of an Appletalk frame */static intrcv_proto_at(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0) && ppp->sc_npmode[NP_AT] == NPMODE_PASS) return ppp_rcv_rx(ppp, ETH_P_PPPTALK, skb); return 0;}/* * Process the receipt of an VJ Compressed frame */static intrcv_proto_vjc_comp(struct ppp *ppp, struct sk_buff *skb){ int new_count; CHECK_PPP(0); if ((ppp->flags & SC_REJ_COMP_TCP) || ppp->slcomp == NULL) return 0; new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN, skb->len - PPP_HDRLEN); if (new_count<=0) { if (ppp->flags & SC_DEBUG) printk(KERN_NOTICE "ppp: error in VJ decompression\n"); return 0; } new_count += PPP_HDRLEN; if (new_count > skb->len) skb_put(skb, new_count - skb->len); else skb_trim(skb, new_count); return rcv_proto_ip(ppp, skb);}/* * Process the receipt of an VJ Un-compressed frame */static intrcv_proto_vjc_uncomp(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); if ((ppp->flags & SC_REJ_COMP_TCP) || ppp->slcomp == NULL) return 0; if (slhc_remember(ppp->slcomp, skb->data + PPP_HDRLEN, skb->len - PPP_HDRLEN) <= 0) { if (ppp->flags & SC_DEBUG) printk(KERN_NOTICE "ppp: error in VJ memorizing\n"); return 0; } return rcv_proto_ip(ppp, skb);}static intrcv_proto_ccp(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); ppp_proto_ccp (ppp, skb->data + PPP_HDRLEN, skb->len - PPP_HDRLEN, 1); return rcv_proto_unknown(ppp, skb);}/* * Receive all unclassified protocols. */static intrcv_proto_unknown(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP(0); /* * Limit queue length by dropping old frames. */ skb_queue_tail(&ppp->rcv_q, skb); while (ppp->rcv_q.qlen > PPP_MAX_RCV_QLEN) { struct sk_buff *skb = skb_dequeue(&ppp->rcv_q); if (skb) kfree_skb(skb); } wake_up_interruptible (&ppp->read_wait); if (ppp->tty->fasync != NULL) kill_fasync (ppp->tty->fasync, SIGIO); return 1;}/************************************************************* * TRANSMIT-SIDE ROUTINES *************************************************************//* local function to store a value into the LQR frame */extern inline __u8 * store_long (register __u8 *p, register int value) { *p++ = (__u8) (value >> 24); *p++ = (__u8) (value >> 16); *p++ = (__u8) (value >> 8); *p++ = (__u8) value; return p;}/* * Compress and send an frame to the peer. * Should be called with xmit_busy == 1, having been set by the caller. * That is, we use xmit_busy as a lock to prevent reentry of this * procedure. */static voidppp_send_frame(struct ppp *ppp, struct sk_buff *skb){ int proto; __u8 *data; int count; __u8 *p; int ret; CHECK_PPP_VOID(); data = skb->data; count = skb->len; /* dump the buffer */ if (ppp->flags & SC_LOG_OUTPKT) ppp_print_buffer ("write frame", data, count); /* * Handle various types of protocol-specific compression * and other processing, including: * - VJ TCP header compression * - updating LQR packets * - updating CCP state on CCP packets */ proto = PPP_PROTOCOL(data); switch (proto) { case PPP_IP: if ((ppp->flags & SC_COMP_TCP) && ppp->slcomp != NULL) skb = ppp_vj_compress(ppp, skb); break; case PPP_LQR: /* * Update the LQR frame with the current MIB information. * This way the information is accurate and up-to-date. */ if (count < 48) break; p = data + 40; /* Point to last two items. */ p = store_long(p, ppp->stats.ppp_opackets + 1); p = store_long(p, ppp->stats.ppp_ooctects + count); ++ppp->stats.ppp_olqrs; break; case PPP_CCP: /* * Outbound compression control frames */ ppp_proto_ccp(ppp, data + PPP_HDRLEN, count - PPP_HDRLEN, 0); break; } data = skb->data; count = skb->len; /* * Compress the whole frame if possible. */ if (((ppp->flags & SC_COMP_RUN) != 0) && (ppp->sc_xc_state != (void *) 0) && (proto != PPP_LCP) && (proto != PPP_CCP)) { struct sk_buff *new_skb; int new_count; /* Allocate an skb for the compressed frame. */ new_skb = alloc_skb(ppp->mtu + PPP_HDRLEN, GFP_ATOMIC); if (new_skb == NULL) { printk(KERN_ERR "ppp_send_frame: no memory\n"); kfree_skb(skb); ppp->xmit_busy = 0; return; } /* Compress the frame. */ new_count = (*ppp->sc_xcomp->compress) (ppp->sc_xc_state, data, new_skb->data, count, ppp->mtu + PPP_HDRLEN); /* Did it compress? */ if (new_count > 0 && (ppp->flags & SC_CCP_UP)) { skb_put(new_skb, new_count); kfree_skb(skb); skb = new_skb; } else { /* * The frame could not be compressed, or it could not * be sent in compressed form because CCP is down. */ kfree_skb(new_skb); } } /* * Send the frame */ ret = ppp_async_send(ppp, skb); if (ret > 0) { /* we can release the lock */ ppp->xmit_busy = 0; } else if (ret < 0) { /* can't happen, since the caller got the xmit_busy lock */ printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n"); }}/* * Apply VJ TCP header compression to a packet. */static struct sk_buff *ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -