| From c5b89d56629098cfdd9ae024a434fd781564c50e Mon Sep 17 00:00:00 2001 |
| From: Ben McKeegan <ben@netservers.co.uk> |
| Date: Tue, 28 Jul 2009 07:43:57 +0000 |
| Subject: ppp: fix lost fragments in ppp_mp_explode() (resubmit) |
| |
| From: Ben McKeegan <ben@netservers.co.uk> |
| |
| [ Upstream commit a53a8b56827cc429c6d9f861ad558beeb5f6103f ] |
| |
| This patch fixes the corner cases where the sum of MTU of the free |
| channels (adjusted for fragmentation overheads) is less than the MTU |
| of PPP link. There are at least 3 situations where this case might |
| arise: |
| |
| - some of the channels are busy |
| |
| - the multilink session is running in a degraded state (i.e. with less |
| than its full complement of active channels) |
| |
| - by design, where multilink protocol is being used to artificially |
| increase the effective link MTU of a single link. |
| |
| Without this patch, at most 1 fragment is ever sent per free channel |
| for a given PPP frame and any remaining part of the PPP frame that |
| does not fit into those fragments is silently discarded. |
| |
| This patch restores the original behaviour which was broken by commit |
| 9c705260feea6ae329bc6b6d5f6d2ef0227eda0a 'ppp:ppp_mp_explode() |
| redesign'. Once all 'free' channels have been given a fragment, an |
| additional fragment is queued to each available channel in turn, as many |
| times as necessary, until the entire PPP frame has been consumed. |
| |
| Signed-off-by: Ben McKeegan <ben@netservers.co.uk> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| drivers/net/ppp_generic.c | 34 ++++++++++++++++++---------------- |
| 1 file changed, 18 insertions(+), 16 deletions(-) |
| |
| --- a/drivers/net/ppp_generic.c |
| +++ b/drivers/net/ppp_generic.c |
| @@ -1383,7 +1383,7 @@ static int ppp_mp_explode(struct ppp *pp |
| |
| /* create a fragment for each channel */ |
| bits = B; |
| - while (nfree > 0 && len > 0) { |
| + while (len > 0) { |
| list = list->next; |
| if (list == &ppp->channels) { |
| i = 0; |
| @@ -1430,29 +1430,31 @@ static int ppp_mp_explode(struct ppp *pp |
| *otherwise divide it according to the speed |
| *of the channel we are going to transmit on |
| */ |
| - if (pch->speed == 0) { |
| - flen = totlen/nfree ; |
| - if (nbigger > 0) { |
| - flen++; |
| - nbigger--; |
| - } |
| - } else { |
| - flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) / |
| - ((totspeed*totfree)/pch->speed)) - hdrlen; |
| - if (nbigger > 0) { |
| - flen += ((totfree - nzero)*pch->speed)/totspeed; |
| - nbigger -= ((totfree - nzero)*pch->speed)/ |
| + if (nfree > 0) { |
| + if (pch->speed == 0) { |
| + flen = totlen/nfree ; |
| + if (nbigger > 0) { |
| + flen++; |
| + nbigger--; |
| + } |
| + } else { |
| + flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) / |
| + ((totspeed*totfree)/pch->speed)) - hdrlen; |
| + if (nbigger > 0) { |
| + flen += ((totfree - nzero)*pch->speed)/totspeed; |
| + nbigger -= ((totfree - nzero)*pch->speed)/ |
| totspeed; |
| + } |
| } |
| + nfree--; |
| } |
| - nfree--; |
| |
| /* |
| *check if we are on the last channel or |
| *we exceded the lenght of the data to |
| *fragment |
| */ |
| - if ((nfree == 0) || (flen > len)) |
| + if ((nfree <= 0) || (flen > len)) |
| flen = len; |
| /* |
| *it is not worth to tx on slow channels: |
| @@ -1466,7 +1468,7 @@ static int ppp_mp_explode(struct ppp *pp |
| continue; |
| } |
| |
| - mtu = pch->chan->mtu + 2 - hdrlen; |
| + mtu = pch->chan->mtu - hdrlen; |
| if (mtu < 4) |
| mtu = 4; |
| if (flen > mtu) |