📄 ppp_generic.c
字号:
read_unlock_bh(&pch->upl); }}/* * Receive-side routines. *//* misuse a few fields of the skb for MP reconstruction */#define sequence priority#define BEbits cb[0]static inline voidppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch){ ppp_recv_lock(ppp); /* ppp->dev == 0 means interface is closing down */ if (ppp->dev != 0) ppp_receive_frame(ppp, skb, pch); else kfree_skb(skb); ppp_recv_unlock(ppp);}voidppp_input(struct ppp_channel *chan, struct sk_buff *skb){ struct channel *pch = chan->ppp; int proto; if (pch == 0 || skb->len == 0) { kfree_skb(skb); return; } proto = PPP_PROTO(skb); read_lock_bh(&pch->upl); if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) { /* put it on the channel queue */ skb_queue_tail(&pch->file.rq, skb); /* drop old frames if queue too long */ while (pch->file.rq.qlen > PPP_MAX_RQLEN && (skb = skb_dequeue(&pch->file.rq)) != 0) kfree_skb(skb); wake_up_interruptible(&pch->file.rwait); } else { ppp_do_recv(pch->ppp, skb, pch); } read_unlock_bh(&pch->upl);}/* Put a 0-length skb in the receive queue as an error indication */voidppp_input_error(struct ppp_channel *chan, int code){ struct channel *pch = chan->ppp; struct sk_buff *skb; if (pch == 0) return; read_lock_bh(&pch->upl); if (pch->ppp != 0) { skb = alloc_skb(0, GFP_ATOMIC); if (skb != 0) { skb->len = 0; /* probably unnecessary */ skb->cb[0] = code; ppp_do_recv(pch->ppp, skb, pch); } } read_unlock_bh(&pch->upl);}/* * We come in here to process a received frame. * The receive side of the ppp unit is locked. */static voidppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch){ if (skb->len >= 2) {#ifdef CONFIG_PPP_MULTILINK /* XXX do channel-level decompression here */ if (PPP_PROTO(skb) == PPP_MP) ppp_receive_mp_frame(ppp, skb, pch); else#endif /* CONFIG_PPP_MULTILINK */ ppp_receive_nonmp_frame(ppp, skb); return; } if (skb->len > 0) /* note: a 0-length skb is used as an error indication */ ++ppp->stats.rx_length_errors; kfree_skb(skb); ppp_receive_error(ppp);}static voidppp_receive_error(struct ppp *ppp){ ++ppp->stats.rx_errors; if (ppp->vj != 0) slhc_toss(ppp->vj);}static voidppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb){ struct sk_buff *ns; int proto, len, npi; /* * Decompress the frame, if compressed. * Note that some decompressors need to see uncompressed frames * that come in as well as compressed frames. */ if (ppp->rc_state != 0 && (ppp->rstate & SC_DECOMP_RUN) && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) skb = ppp_decompress_frame(ppp, skb); proto = PPP_PROTO(skb); switch (proto) { case PPP_VJC_COMP: /* decompress VJ compressed packets */ if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) goto err; if (skb_tailroom(skb) < 124) { /* copy to a new sk_buff with more tailroom */ ns = dev_alloc_skb(skb->len + 128); if (ns == 0) { printk(KERN_ERR"PPP: no memory (VJ decomp)\n"); goto err; } skb_reserve(ns, 2); memcpy(skb_put(ns, skb->len), skb->data, skb->len); kfree_skb(skb); skb = ns; } len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2); if (len <= 0) { printk(KERN_DEBUG "PPP: VJ decompression error\n"); goto err; } len += 2; if (len > skb->len) skb_put(skb, len - skb->len); else if (len < skb->len) skb_trim(skb, len); proto = PPP_IP; break; case PPP_VJC_UNCOMP: if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) goto err; if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) { printk(KERN_ERR "PPP: VJ uncompressed error\n"); goto err; } proto = PPP_IP; break; case PPP_CCP: ppp_ccp_peek(ppp, skb, 1); break; } ++ppp->stats.rx_packets; ppp->stats.rx_bytes += skb->len - 2; npi = proto_to_npindex(proto); if (npi < 0) { /* control or unknown frame - pass it to pppd */ skb_queue_tail(&ppp->file.rq, skb); /* limit queue length by dropping old frames */ while (ppp->file.rq.qlen > PPP_MAX_RQLEN && (skb = skb_dequeue(&ppp->file.rq)) != 0) kfree_skb(skb); /* wake up any process polling or blocking on read */ wake_up_interruptible(&ppp->file.rwait); } else { /* network protocol frame - give it to the kernel */ ppp->last_recv = jiffies; if ((ppp->dev->flags & IFF_UP) == 0 || ppp->npmode[npi] != NPMODE_PASS) { kfree_skb(skb); } else { skb_pull(skb, 2); /* chop off protocol */ skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb->mac.raw = skb->data; netif_rx(skb); } } return; err: kfree_skb(skb); ppp_receive_error(ppp);}static struct sk_buff *ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb){ int proto = PPP_PROTO(skb); struct sk_buff *ns; int len; if (proto == PPP_COMP) { ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN); if (ns == 0) { printk(KERN_ERR "ppp_decompress_frame: no memory\n"); goto err; } /* the decompressor still expects the A/C bytes in the hdr */ len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2, skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN); if (len < 0) { /* Pass the compressed frame to pppd as an error indication. */ if (len == DECOMP_FATALERROR) ppp->rstate |= SC_DC_FERROR; goto err; } kfree_skb(skb); skb = ns; skb_put(skb, len); skb_pull(skb, 2); /* pull off the A/C bytes */ } else { /* Uncompressed frame - pass to decompressor so it can update its dictionary if necessary. */ if (ppp->rcomp->incomp) ppp->rcomp->incomp(ppp->rc_state, skb->data - 2, skb->len + 2); } return skb; err: ppp->rstate |= SC_DC_ERROR; ppp_receive_error(ppp); return skb;}#ifdef CONFIG_PPP_MULTILINK/* * Receive a multilink frame. * We put it on the reconstruction queue and then pull off * as many completed frames as we can. */static voidppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch){ u32 mask, seq; struct list_head *l; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; if (skb->len < mphdrlen + 1 || ppp->mrru == 0) goto err; /* no good, throw it away */ /* Decode sequence number and begin/end bits */ if (ppp->flags & SC_MP_SHORTSEQ) { seq = ((skb->data[2] & 0x0f) << 8) | skb->data[3]; mask = 0xfff; } else { seq = (skb->data[3] << 16) | (skb->data[4] << 8)| skb->data[5]; mask = 0xffffff; } skb->BEbits = skb->data[2]; skb_pull(skb, mphdrlen); /* pull off PPP and MP headers */ /* * Do protocol ID decompression on the first fragment of each packet. */ if ((skb->BEbits & B) && (skb->data[0] & 1)) *skb_push(skb, 1) = 0; /* * Expand sequence number to 32 bits, making it as close * as possible to ppp->minseq. */ seq |= ppp->minseq & ~mask; if ((int)(ppp->minseq - seq) > (int)(mask >> 1)) seq += mask + 1; else if ((int)(seq - ppp->minseq) > (int)(mask >> 1)) seq -= mask + 1; /* should never happen */ skb->sequence = seq; pch->lastseq = seq; /* * If this packet comes before the next one we were expecting, * drop it. */ if (seq_before(seq, ppp->nextseq)) { kfree_skb(skb); ++ppp->stats.rx_dropped; ppp_receive_error(ppp); return; } /* * Reevaluate minseq, the minimum over all channels of the * last sequence number received on each channel. Because of * the increasing sequence number rule, we know that any fragment * before `minseq' which hasn't arrived is never going to arrive. * The list of channels can't change because we have the receive * side of the ppp unit locked. */ for (l = ppp->channels.next; l != &ppp->channels; l = l->next) { struct channel *ch = list_entry(l, struct channel, clist); if (seq_before(ch->lastseq, seq)) seq = ch->lastseq; } if (seq_before(ppp->minseq, seq)) ppp->minseq = seq; /* Put the fragment on the reconstruction queue */ ppp_mp_insert(ppp, skb); /* If the queue is getting long, don't wait any longer for packets before the start of the queue. */ if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN && seq_before(ppp->minseq, ppp->mrq.next->sequence)) ppp->minseq = ppp->mrq.next->sequence; /* Pull completed packets off the queue and receive them. */ while ((skb = ppp_mp_reconstruct(ppp)) != 0) ppp_receive_nonmp_frame(ppp, skb); return; err: kfree_skb(skb); ppp_receive_error(ppp);}/* * Insert a fragment on the MP reconstruction queue. * The queue is ordered by increasing sequence number. */static voidppp_mp_insert(struct ppp *ppp, struct sk_buff *skb){ struct sk_buff *p; struct sk_buff_head *list = &ppp->mrq; u32 seq = skb->sequence; /* N.B. we don't need to lock the list lock because we have the ppp unit receive-side lock. */ for (p = list->next; p != (struct sk_buff *)list; p = p->next) if (seq_before(seq, p->sequence)) break; __skb_insert(skb, p->prev, p, list);}/* * Reconstruct a packet from the MP fragment queue. * We go through increasing sequence numbers until we find a * complete packet, or we get to the sequence number for a fragment * which hasn't arrived but might still do so. */struct sk_buff *ppp_mp_reconstruct(struct ppp *ppp){ u32 seq = ppp->nextseq; u32 minseq = ppp->minseq; struct sk_buff_head *list = &ppp->mrq; struct sk_buff *p, *next; struct sk_buff *head, *tail; struct sk_buff *skb = NULL; int lost = 0, len = 0; if (ppp->mrru == 0) /* do nothing until mrru is set */ return NULL; head = list->next; tail = NULL; for (p = head; p != (struct sk_buff *) list; p = next) { next = p->next; if (seq_before(p->sequence, seq)) { /* this can't happen, anyway ignore the skb */ printk(KERN_ERR "ppp_mp_reconstruct bad seq %u < %u\n", p->sequence, seq); head = next; continue; } if (p->sequence != seq) { /* Fragment `seq' is missing. If it is after minseq, it might arrive later, so stop here. */ if (seq_after(seq, minseq)) break; /* Fragment `seq' is lost, keep going. */ lost = 1; seq = seq_before(minseq, p->sequence)? minseq + 1: p->sequence; next = p; continue; } /* * At this point we know that all the fragments from * ppp->nextseq to seq are either present or lost. * Also, there are no complete packets in the queue * that have no missing fragments and end before this * fragment. */ /* B bit set indicates this fragment starts a packet */ if (p->BEbits & B) { head = p; lost = 0; len = 0; } len += p->len; /* Got a complete packet yet? */ if (lost == 0 && (p->BEbits & E) && (head->BEbits & B)) { if (len > ppp->mrru + 2) { ++ppp->stats.rx_length_errors; printk(KERN_DEBUG "PPP: reconstructed packet" " is too long (%d)\n", len); } else if (p == head) { /* fragment is complete packet - reuse skb */ tail = p; skb = skb_get(p); break; } else if ((skb = dev_alloc_skb(len)) == NULL) { ++ppp->stats.rx_missed_errors; printk(KERN_DEBUG "PPP: no memory for " "reconstructed packet"); } else { tail = p; break; } ppp->nextseq = seq + 1; } /* * If this is the ending fragment of a packet, * and we haven't found a complete valid packet yet, * we can discard up to and including this fragment. */ if (p->BEbits & E) head = next; ++seq; } /* If we have a complete packet, copy it all into one skb. */ if (tail != NULL) { /* If we have discarded any fragments, signal a receive error. */ if (head->sequence != ppp->nextseq) { if (ppp->debug & 1) printk(KERN_DEBUG " missed pkts %u..%u\n", ppp->nextseq, head->sequence-1); ++ppp->stats.rx_dropped; ppp_receive_error(ppp); } if (head != tail) /* copy to a single skb */ for (p = head; p != tail->next; p = p->next) memcpy(skb_put(skb, p->len), p->data, p->len); ppp->nextseq = tail->sequence + 1; head = tail->next; } /* Discard all the skbuffs that we have copied the data out of or that we can't use. */ while ((p = list->next) != head) { __skb_unlink(p, list); kfree_skb(p); } return skb;}#endif /* CONFIG_PPP_MULTILINK *//* * Channel interface. *//* * Create a new, unattached ppp channel. */intppp_register_channel(struct ppp_channel *chan){ struct channel *pch; pch = kmalloc(sizeof(struct channel), GFP_ATOMIC); if (pch == 0) return -ENOMEM; memset(pch, 0, sizeof(struct channel)); pch->ppp = NULL; pch->chan = chan; chan->ppp = pch; init_ppp_file(&pch->file, CHANNEL); pch->file.hdrlen = chan->hdrlen;#ifdef CONFIG_PPP_MULTILINK pch->lastseq = -1;#endif /* CONFIG_PPP_MULTILINK */ spin_lock_init(&pch->downl); pch->upl = RW_LOCK_UNLOCKED; spin_lock_bh(&all_channels_lock); pch->file.index = ++last_channel_index; list_add(&pch->file.list, &all_channels); spin_unlock_bh(&all_channels_lock); MOD_INC_USE_COUNT; return 0;}/* * Return the index of a channel. */int ppp_channel_index(struct ppp_channel *chan){ struct channel *pch = chan->ppp; return pch->file.index;}/* * Return the PPP unit number to which a channel is connected. */int ppp_unit_number(struct ppp_channel *chan){ struct channel *pch = chan->ppp; int unit = -1; if (pch != 0) { read_lock_bh(&pch->upl); if (pch->ppp != 0) unit = pch->ppp->file.index; read_unlock_bh(&pch->upl); } return unit;}/* * Disconnect a channel from the generic layer. * This can be called from mainline or BH/softirq level. */voidppp_unregister_channel(struct ppp_channel *chan){ struct channel *pch = chan->ppp; if (pch == 0) return; /* should never happen */ chan->ppp = 0; /* * This ensures that we have returned from any calls into the * the channel's start_xmit or ioctl routine before we proceed. */ spin_lock_bh(&pch->downl); pch->chan = 0; spin_unlock_bh(&pch->downl); ppp_disconnect_channel(pch); wake_up_interruptible(&pch->file.rwait); spin_lock_bh(&all_channels_lock); list_del(&pch->file.list); spin_unlock_bh(&all_channels_lock); if (atomic_dec_and_test(&pch->file.refcnt)) ppp_destroy_channel(pch); MOD_DEC_USE_COUNT;}/* * Callback from a channel when it can accept more to transmit. * This should be called at BH/softirq level, not interrupt level. */voidppp_output_wakeup(struct ppp_channel *chan){ struct channel *pch = chan->ppp; if (pch == 0) return; ppp_channel_push(pch);}/* * This is basically temporary compatibility stuff. */ssize_tppp_channel_read(struct ppp_channel *chan, struct file *file, char *buf, size_t count){ struct channel *pch = chan->ppp; if (pch == 0) return -ENXIO; return ppp_file_read(&pch->file, file, buf, count);}ssize_tppp_channel_write(struct ppp_channel *chan, const char *buf, size_t count){ struct channel *pch = chan->ppp; if (pch == 0) return -ENXIO; return ppp_file_write(&pch->file, buf, count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -