Loading drivers/net/ppp_generic.c +110 −67 Original line number Original line Diff line number Diff line Loading @@ -1217,36 +1217,43 @@ ppp_push(struct ppp *ppp) */ */ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) { { int nch, len, fragsize; int len, fragsize; int i, bits, hdrlen, mtu; int i, bits, hdrlen, mtu; int flen, fnb; int flen; int navail, nfree; int nbigger; unsigned char *p, *q; unsigned char *p, *q; struct list_head *list; struct list_head *list; struct channel *pch; struct channel *pch; struct sk_buff *frag; struct sk_buff *frag; struct ppp_channel *chan; struct ppp_channel *chan; nch = 0; nfree = 0; /* # channels which have no packet already queued */ navail = 0; /* total # of usable channels (not deregistered) */ hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; i = 0; list = &ppp->channels; list = &ppp->channels; while ((list = list->next) != &ppp->channels) { while ((list = list->next) != &ppp->channels) { pch = list_entry(list, struct channel, clist); pch = list_entry(list, struct channel, clist); nch += pch->avail = (skb_queue_len(&pch->file.xq) == 0); navail += pch->avail = (pch->chan != NULL); /* if (pch->avail) { * If a channel hasn't had a fragment yet, it has to get if (skb_queue_len(&pch->file.xq) == 0 * one before we send any fragments on later channels. || !pch->had_frag) { * If it can't take a fragment now, don't give any pch->avail = 2; * to subsequent channels. ++nfree; */ } if (!pch->had_frag && !pch->avail) { if (!pch->had_frag && i < ppp->nxchan) while ((list = list->next) != &ppp->channels) { ppp->nxchan = i; pch = list_entry(list, struct channel, clist); pch->avail = 0; } break; } } ++i; } } if (nch == 0) /* * Don't start sending this packet unless at least half of * the channels are free. This gives much better TCP * performance if we have a lot of channels. */ if (nfree == 0 || nfree < navail / 2) return 0; /* can't take now, leave it in xmit_pending */ return 0; /* can't take now, leave it in xmit_pending */ /* Do protocol field compression (XXX this should be optional) */ /* Do protocol field compression (XXX this should be optional) */ Loading @@ -1257,14 +1264,19 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) --len; --len; } } /* decide on fragment size */ /* * Decide on fragment size. * We create a fragment for each free channel regardless of * how small they are (i.e. even 0 length) in order to minimize * the time that it will take to detect when a channel drops * a fragment. */ fragsize = len; fragsize = len; if (nch > 1) { if (nfree > 1) int maxch = ROUNDUP(len, MIN_FRAG_SIZE); fragsize = ROUNDUP(fragsize, nfree); if (nch > maxch) /* nbigger channels get fragsize bytes, the rest get fragsize-1, nch = maxch; except if nbigger==0, then they all get fragsize. */ fragsize = ROUNDUP(fragsize, nch); nbigger = len % nfree; } /* skip to the channel after the one we last used /* skip to the channel after the one we last used and start at that one */ and start at that one */ Loading @@ -1278,7 +1290,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* create a fragment for each channel */ /* create a fragment for each channel */ bits = B; bits = B; do { while (nfree > 0 || len > 0) { list = list->next; list = list->next; if (list == &ppp->channels) { if (list == &ppp->channels) { i = 0; i = 0; Loading @@ -1289,33 +1301,50 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) if (!pch->avail) if (!pch->avail) continue; continue; /* * Skip this channel if it has a fragment pending already and * we haven't given a fragment to all of the free channels. */ if (pch->avail == 1) { if (nfree > 0) continue; } else { --nfree; pch->avail = 1; } /* check the channel's mtu and whether it is still attached. */ /* check the channel's mtu and whether it is still attached. */ spin_lock_bh(&pch->downl); spin_lock_bh(&pch->downl); if (pch->chan == 0 || (mtu = pch->chan->mtu) < hdrlen) { if (pch->chan == NULL) { /* can't use this channel */ /* can't use this channel, it's being deregistered */ spin_unlock_bh(&pch->downl); spin_unlock_bh(&pch->downl); pch->avail = 0; pch->avail = 0; if (--nch == 0) if (--navail == 0) break; break; continue; continue; } } /* /* * We have to create multiple fragments for this channel * Create a fragment for this channel of * if fragsize is greater than the channel's mtu. * min(max(mtu+2-hdrlen, 4), fragsize, len) bytes. * If mtu+2-hdrlen < 4, that is a ridiculously small * MTU, so we use mtu = 2 + hdrlen. */ */ if (fragsize > len) if (fragsize > len) fragsize = len; fragsize = len; for (flen = fragsize; flen > 0; flen -= fnb) { flen = fragsize; fnb = flen; mtu = pch->chan->mtu + 2 - hdrlen; if (fnb > mtu + 2 - hdrlen) if (mtu < 4) fnb = mtu + 2 - hdrlen; mtu = 4; if (fnb >= len) if (flen > mtu) flen = mtu; if (flen == len && nfree == 0) bits |= E; bits |= E; frag = alloc_skb(fnb + hdrlen, GFP_ATOMIC); frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC); if (frag == 0) if (frag == 0) goto noskb; goto noskb; q = skb_put(frag, fnb + hdrlen); q = skb_put(frag, flen + hdrlen); /* make the MP header */ /* make the MP header */ q[0] = PPP_MP >> 8; q[0] = PPP_MP >> 8; q[1] = PPP_MP; q[1] = PPP_MP; Loading @@ -1329,21 +1358,35 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) q[5] = ppp->nxseq; q[5] = ppp->nxseq; } } /* copy the data in */ /* memcpy(q + hdrlen, p, fnb); * Copy the data in. * Unfortunately there is a bug in older versions of * the Linux PPP multilink reconstruction code where it * drops 0-length fragments. Therefore we make sure the * fragment has at least one byte of data. Any bytes * we add in this situation will end up as padding on the * end of the reconstructed packet. */ if (flen == 0) *skb_put(frag, 1) = 0; else memcpy(q + hdrlen, p, flen); /* try to send it down the channel */ /* try to send it down the channel */ chan = pch->chan; chan = pch->chan; if (!chan->ops->start_xmit(chan, frag)) if (skb_queue_len(&pch->file.xq) || !chan->ops->start_xmit(chan, frag)) skb_queue_tail(&pch->file.xq, frag); skb_queue_tail(&pch->file.xq, frag); pch->had_frag = 1; pch->had_frag = 1; p += fnb; p += flen; len -= fnb; len -= flen; ++ppp->nxseq; ++ppp->nxseq; bits = 0; bits = 0; } spin_unlock_bh(&pch->downl); spin_unlock_bh(&pch->downl); } while (len > 0); if (--nbigger == 0 && fragsize > 0) --fragsize; } ppp->nxchan = i; ppp->nxchan = i; return 1; return 1; Loading Loading @@ -1691,7 +1734,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) struct list_head *l; struct list_head *l; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0) goto err; /* no good, throw it away */ goto err; /* no good, throw it away */ /* Decode sequence number and begin/end bits */ /* Decode sequence number and begin/end bits */ Loading Loading
drivers/net/ppp_generic.c +110 −67 Original line number Original line Diff line number Diff line Loading @@ -1217,36 +1217,43 @@ ppp_push(struct ppp *ppp) */ */ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) { { int nch, len, fragsize; int len, fragsize; int i, bits, hdrlen, mtu; int i, bits, hdrlen, mtu; int flen, fnb; int flen; int navail, nfree; int nbigger; unsigned char *p, *q; unsigned char *p, *q; struct list_head *list; struct list_head *list; struct channel *pch; struct channel *pch; struct sk_buff *frag; struct sk_buff *frag; struct ppp_channel *chan; struct ppp_channel *chan; nch = 0; nfree = 0; /* # channels which have no packet already queued */ navail = 0; /* total # of usable channels (not deregistered) */ hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; i = 0; list = &ppp->channels; list = &ppp->channels; while ((list = list->next) != &ppp->channels) { while ((list = list->next) != &ppp->channels) { pch = list_entry(list, struct channel, clist); pch = list_entry(list, struct channel, clist); nch += pch->avail = (skb_queue_len(&pch->file.xq) == 0); navail += pch->avail = (pch->chan != NULL); /* if (pch->avail) { * If a channel hasn't had a fragment yet, it has to get if (skb_queue_len(&pch->file.xq) == 0 * one before we send any fragments on later channels. || !pch->had_frag) { * If it can't take a fragment now, don't give any pch->avail = 2; * to subsequent channels. ++nfree; */ } if (!pch->had_frag && !pch->avail) { if (!pch->had_frag && i < ppp->nxchan) while ((list = list->next) != &ppp->channels) { ppp->nxchan = i; pch = list_entry(list, struct channel, clist); pch->avail = 0; } break; } } ++i; } } if (nch == 0) /* * Don't start sending this packet unless at least half of * the channels are free. This gives much better TCP * performance if we have a lot of channels. */ if (nfree == 0 || nfree < navail / 2) return 0; /* can't take now, leave it in xmit_pending */ return 0; /* can't take now, leave it in xmit_pending */ /* Do protocol field compression (XXX this should be optional) */ /* Do protocol field compression (XXX this should be optional) */ Loading @@ -1257,14 +1264,19 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) --len; --len; } } /* decide on fragment size */ /* * Decide on fragment size. * We create a fragment for each free channel regardless of * how small they are (i.e. even 0 length) in order to minimize * the time that it will take to detect when a channel drops * a fragment. */ fragsize = len; fragsize = len; if (nch > 1) { if (nfree > 1) int maxch = ROUNDUP(len, MIN_FRAG_SIZE); fragsize = ROUNDUP(fragsize, nfree); if (nch > maxch) /* nbigger channels get fragsize bytes, the rest get fragsize-1, nch = maxch; except if nbigger==0, then they all get fragsize. */ fragsize = ROUNDUP(fragsize, nch); nbigger = len % nfree; } /* skip to the channel after the one we last used /* skip to the channel after the one we last used and start at that one */ and start at that one */ Loading @@ -1278,7 +1290,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* create a fragment for each channel */ /* create a fragment for each channel */ bits = B; bits = B; do { while (nfree > 0 || len > 0) { list = list->next; list = list->next; if (list == &ppp->channels) { if (list == &ppp->channels) { i = 0; i = 0; Loading @@ -1289,33 +1301,50 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) if (!pch->avail) if (!pch->avail) continue; continue; /* * Skip this channel if it has a fragment pending already and * we haven't given a fragment to all of the free channels. */ if (pch->avail == 1) { if (nfree > 0) continue; } else { --nfree; pch->avail = 1; } /* check the channel's mtu and whether it is still attached. */ /* check the channel's mtu and whether it is still attached. */ spin_lock_bh(&pch->downl); spin_lock_bh(&pch->downl); if (pch->chan == 0 || (mtu = pch->chan->mtu) < hdrlen) { if (pch->chan == NULL) { /* can't use this channel */ /* can't use this channel, it's being deregistered */ spin_unlock_bh(&pch->downl); spin_unlock_bh(&pch->downl); pch->avail = 0; pch->avail = 0; if (--nch == 0) if (--navail == 0) break; break; continue; continue; } } /* /* * We have to create multiple fragments for this channel * Create a fragment for this channel of * if fragsize is greater than the channel's mtu. * min(max(mtu+2-hdrlen, 4), fragsize, len) bytes. * If mtu+2-hdrlen < 4, that is a ridiculously small * MTU, so we use mtu = 2 + hdrlen. */ */ if (fragsize > len) if (fragsize > len) fragsize = len; fragsize = len; for (flen = fragsize; flen > 0; flen -= fnb) { flen = fragsize; fnb = flen; mtu = pch->chan->mtu + 2 - hdrlen; if (fnb > mtu + 2 - hdrlen) if (mtu < 4) fnb = mtu + 2 - hdrlen; mtu = 4; if (fnb >= len) if (flen > mtu) flen = mtu; if (flen == len && nfree == 0) bits |= E; bits |= E; frag = alloc_skb(fnb + hdrlen, GFP_ATOMIC); frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC); if (frag == 0) if (frag == 0) goto noskb; goto noskb; q = skb_put(frag, fnb + hdrlen); q = skb_put(frag, flen + hdrlen); /* make the MP header */ /* make the MP header */ q[0] = PPP_MP >> 8; q[0] = PPP_MP >> 8; q[1] = PPP_MP; q[1] = PPP_MP; Loading @@ -1329,21 +1358,35 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) q[5] = ppp->nxseq; q[5] = ppp->nxseq; } } /* copy the data in */ /* memcpy(q + hdrlen, p, fnb); * Copy the data in. * Unfortunately there is a bug in older versions of * the Linux PPP multilink reconstruction code where it * drops 0-length fragments. Therefore we make sure the * fragment has at least one byte of data. Any bytes * we add in this situation will end up as padding on the * end of the reconstructed packet. */ if (flen == 0) *skb_put(frag, 1) = 0; else memcpy(q + hdrlen, p, flen); /* try to send it down the channel */ /* try to send it down the channel */ chan = pch->chan; chan = pch->chan; if (!chan->ops->start_xmit(chan, frag)) if (skb_queue_len(&pch->file.xq) || !chan->ops->start_xmit(chan, frag)) skb_queue_tail(&pch->file.xq, frag); skb_queue_tail(&pch->file.xq, frag); pch->had_frag = 1; pch->had_frag = 1; p += fnb; p += flen; len -= fnb; len -= flen; ++ppp->nxseq; ++ppp->nxseq; bits = 0; bits = 0; } spin_unlock_bh(&pch->downl); spin_unlock_bh(&pch->downl); } while (len > 0); if (--nbigger == 0 && fragsize > 0) --fragsize; } ppp->nxchan = i; ppp->nxchan = i; return 1; return 1; Loading Loading @@ -1691,7 +1734,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) struct list_head *l; struct list_head *l; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0) goto err; /* no good, throw it away */ goto err; /* no good, throw it away */ /* Decode sequence number and begin/end bits */ /* Decode sequence number and begin/end bits */ Loading