📄 ppp.c
字号:
{ 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; } if ( !(ppp->flags & SC_SYNC) ) { /* * 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 { LIBERATE_SKB(new_skb); 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; } LIBERATE_SKB(new_skb); /* 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 */ if ( ppp->flags & SC_SYNC ) ret = ppp_sync_send(ppp, skb); else 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){ __u8 *orig_data, *data; struct sk_buff *new_skb; int len, proto; new_skb = alloc_skb(skb->len, GFP_ATOMIC); if (new_skb == NULL) { printk(KERN_ERR "ppp: no memory for vj compression\n"); return skb; } LIBERATE_SKB(new_skb); orig_data = data = skb->data + PPP_HDRLEN; len = slhc_compress(ppp->slcomp, data, skb->len - PPP_HDRLEN, new_skb->data + PPP_HDRLEN, &data, (ppp->flags & SC_NO_TCP_CCID) == 0); if (data == orig_data) { /* Couldn't compress the data */ KFREE_SKB(new_skb); return skb; } /* The data has been changed */ if (data[0] & SL_TYPE_COMPRESSED_TCP) { proto = PPP_VJC_COMP; data[0] ^= SL_TYPE_COMPRESSED_TCP; } else { if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP) proto = PPP_VJC_UNCOMP; else proto = PPP_IP; data[0] = orig_data[0]; } data = skb_put(new_skb, len + PPP_HDRLEN); data[0] = PPP_ALLSTATIONS; data[1] = PPP_UI; data[2] = 0; data[3] = proto; KFREE_SKB(skb); return new_skb;}static inline voidppp_send_frames(struct ppp *ppp){ struct sk_buff *skb; while (!test_and_set_bit(0, &ppp->xmit_busy)) { skb = skb_dequeue(&ppp->xmt_q); if (skb == NULL) { ppp->xmit_busy = 0; break; } ppp_send_frame(ppp, skb); } if (!ppp->xmit_busy && ppp->dev.tbusy) { ppp->dev.tbusy = 0; mark_bh(NET_BH); }}/* * Called from the hardware (tty) layer when it can accept * another packet. */static voidppp_output_wakeup(struct ppp *ppp){ CHECK_PPP_VOID(); if (!ppp->xmit_busy) { printk(KERN_ERR "ppp_output_wakeup called but xmit_busy==0\n"); return; } ppp->xmit_busy = 0; ppp_send_frames(ppp);}/* * Send a control frame (from pppd). */static voidppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -