aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ppp_generic.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-01-21 01:46:07 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-21 01:46:07 -0500
commit212bfb9e94e86b40684076f642b089b0565455d2 (patch)
tree3fef8a449d5c6b665beebaacb6d4398143b4106c /drivers/net/ppp_generic.c
parentb48f8c23c336d82c1af9a53187568bdb6e86b8a8 (diff)
ppp: Reconstruct fragmented packets using frag lists instead of copying.
[paulus@samba.org: fixed a couple of bugs] Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers/net/ppp_generic.c')
-rw-r--r--drivers/net/ppp_generic.c39
1 files changed, 23 insertions, 16 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 3d7a38eeacda..1d4fb348488f 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -2055,16 +2055,6 @@ ppp_mp_reconstruct(struct ppp *ppp)
2055 netdev_printk(KERN_DEBUG, ppp->dev, 2055 netdev_printk(KERN_DEBUG, ppp->dev,
2056 "PPP: reconstructed packet" 2056 "PPP: reconstructed packet"
2057 " is too long (%d)\n", len); 2057 " is too long (%d)\n", len);
2058 } else if (p == head) {
2059 /* fragment is complete packet - reuse skb */
2060 tail = p;
2061 skb = skb_get(p);
2062 break;
2063 } else if ((skb = dev_alloc_skb(len)) == NULL) {
2064 ++ppp->dev->stats.rx_missed_errors;
2065 netdev_printk(KERN_DEBUG, ppp->dev,
2066 "PPP: no memory for "
2067 "reconstructed packet");
2068 } else { 2058 } else {
2069 tail = p; 2059 tail = p;
2070 break; 2060 break;
@@ -2097,16 +2087,33 @@ ppp_mp_reconstruct(struct ppp *ppp)
2097 ppp_receive_error(ppp); 2087 ppp_receive_error(ppp);
2098 } 2088 }
2099 2089
2100 if (head != tail) 2090 skb = head;
2101 /* copy to a single skb */ 2091 if (head != tail) {
2102 for (p = head; p != tail->next; p = p->next) 2092 struct sk_buff **fragpp = &skb_shinfo(skb)->frag_list;
2103 skb_copy_bits(p, 0, skb_put(skb, p->len), p->len); 2093 p = skb_queue_next(list, head);
2094 __skb_unlink(skb, list);
2095 skb_queue_walk_from_safe(list, p, tmp) {
2096 __skb_unlink(p, list);
2097 *fragpp = p;
2098 p->next = NULL;
2099 fragpp = &p->next;
2100
2101 skb->len += p->len;
2102 skb->data_len += p->len;
2103 skb->truesize += p->len;
2104
2105 if (p == tail)
2106 break;
2107 }
2108 } else {
2109 __skb_unlink(skb, list);
2110 }
2111
2104 ppp->nextseq = PPP_MP_CB(tail)->sequence + 1; 2112 ppp->nextseq = PPP_MP_CB(tail)->sequence + 1;
2105 head = tail->next; 2113 head = tail->next;
2106 } 2114 }
2107 2115
2108 /* Discard all the skbuffs that we have copied the data out of 2116 /* Discard all the skbuffs that we can't use. */
2109 or that we can't use. */
2110 while ((p = list->next) != head) { 2117 while ((p = list->next) != head) {
2111 __skb_unlink(p, list); 2118 __skb_unlink(p, list);
2112 kfree_skb(p); 2119 kfree_skb(p);