diff options
author | David S. Miller <davem@davemloft.net> | 2011-01-21 01:46:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-01-21 01:46:07 -0500 |
commit | 212bfb9e94e86b40684076f642b089b0565455d2 (patch) | |
tree | 3fef8a449d5c6b665beebaacb6d4398143b4106c /drivers/net/ppp_generic.c | |
parent | b48f8c23c336d82c1af9a53187568bdb6e86b8a8 (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.c | 39 |
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); |