|
@@ -3508,24 +3508,18 @@ void __init skb_init(void)
|
|
NULL);
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * skb_to_sgvec - Fill a scatter-gather list from a socket buffer
|
|
|
|
- * @skb: Socket buffer containing the buffers to be mapped
|
|
|
|
- * @sg: The scatter-gather list to map into
|
|
|
|
- * @offset: The offset into the buffer's contents to start mapping
|
|
|
|
- * @len: Length of buffer space to be mapped
|
|
|
|
- *
|
|
|
|
- * Fill the specified scatter-gather list with mappings/pointers into a
|
|
|
|
- * region of the buffer space attached to a socket buffer.
|
|
|
|
- */
|
|
|
|
static int
|
|
static int
|
|
-__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
|
|
|
|
|
+__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,
|
|
|
|
+ unsigned int recursion_level)
|
|
{
|
|
{
|
|
int start = skb_headlen(skb);
|
|
int start = skb_headlen(skb);
|
|
int i, copy = start - offset;
|
|
int i, copy = start - offset;
|
|
struct sk_buff *frag_iter;
|
|
struct sk_buff *frag_iter;
|
|
int elt = 0;
|
|
int elt = 0;
|
|
|
|
|
|
|
|
+ if (unlikely(recursion_level >= 24))
|
|
|
|
+ return -EMSGSIZE;
|
|
|
|
+
|
|
if (copy > 0) {
|
|
if (copy > 0) {
|
|
if (copy > len)
|
|
if (copy > len)
|
|
copy = len;
|
|
copy = len;
|
|
@@ -3544,6 +3538,8 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
|
end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
|
|
end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
|
|
if ((copy = end - offset) > 0) {
|
|
if ((copy = end - offset) > 0) {
|
|
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
|
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
|
|
|
+ if (unlikely(elt && sg_is_last(&sg[elt - 1])))
|
|
|
|
+ return -EMSGSIZE;
|
|
|
|
|
|
if (copy > len)
|
|
if (copy > len)
|
|
copy = len;
|
|
copy = len;
|
|
@@ -3558,16 +3554,22 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
|
}
|
|
}
|
|
|
|
|
|
skb_walk_frags(skb, frag_iter) {
|
|
skb_walk_frags(skb, frag_iter) {
|
|
- int end;
|
|
|
|
|
|
+ int end, ret;
|
|
|
|
|
|
WARN_ON(start > offset + len);
|
|
WARN_ON(start > offset + len);
|
|
|
|
|
|
end = start + frag_iter->len;
|
|
end = start + frag_iter->len;
|
|
if ((copy = end - offset) > 0) {
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
+ if (unlikely(elt && sg_is_last(&sg[elt - 1])))
|
|
|
|
+ return -EMSGSIZE;
|
|
|
|
+
|
|
if (copy > len)
|
|
if (copy > len)
|
|
copy = len;
|
|
copy = len;
|
|
- elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start,
|
|
|
|
- copy);
|
|
|
|
|
|
+ ret = __skb_to_sgvec(frag_iter, sg+elt, offset - start,
|
|
|
|
+ copy, recursion_level + 1);
|
|
|
|
+ if (unlikely(ret < 0))
|
|
|
|
+ return ret;
|
|
|
|
+ elt += ret;
|
|
if ((len -= copy) == 0)
|
|
if ((len -= copy) == 0)
|
|
return elt;
|
|
return elt;
|
|
offset += copy;
|
|
offset += copy;
|
|
@@ -3578,6 +3580,31 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
|
return elt;
|
|
return elt;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * skb_to_sgvec - Fill a scatter-gather list from a socket buffer
|
|
|
|
+ * @skb: Socket buffer containing the buffers to be mapped
|
|
|
|
+ * @sg: The scatter-gather list to map into
|
|
|
|
+ * @offset: The offset into the buffer's contents to start mapping
|
|
|
|
+ * @len: Length of buffer space to be mapped
|
|
|
|
+ *
|
|
|
|
+ * Fill the specified scatter-gather list with mappings/pointers into a
|
|
|
|
+ * region of the buffer space attached to a socket buffer. Returns either
|
|
|
|
+ * the number of scatterlist items used, or -EMSGSIZE if the contents
|
|
|
|
+ * could not fit.
|
|
|
|
+ */
|
|
|
|
+int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
|
|
|
+{
|
|
|
|
+ int nsg = __skb_to_sgvec(skb, sg, offset, len, 0);
|
|
|
|
+
|
|
|
|
+ if (nsg <= 0)
|
|
|
|
+ return nsg;
|
|
|
|
+
|
|
|
|
+ sg_mark_end(&sg[nsg - 1]);
|
|
|
|
+
|
|
|
|
+ return nsg;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(skb_to_sgvec);
|
|
|
|
+
|
|
/* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given
|
|
/* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given
|
|
* sglist without mark the sg which contain last skb data as the end.
|
|
* sglist without mark the sg which contain last skb data as the end.
|
|
* So the caller can mannipulate sg list as will when padding new data after
|
|
* So the caller can mannipulate sg list as will when padding new data after
|
|
@@ -3600,19 +3627,11 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
|
int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
|
|
int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
|
|
int offset, int len)
|
|
int offset, int len)
|
|
{
|
|
{
|
|
- return __skb_to_sgvec(skb, sg, offset, len);
|
|
|
|
|
|
+ return __skb_to_sgvec(skb, sg, offset, len, 0);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark);
|
|
EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark);
|
|
|
|
|
|
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
|
|
|
|
-{
|
|
|
|
- int nsg = __skb_to_sgvec(skb, sg, offset, len);
|
|
|
|
|
|
|
|
- sg_mark_end(&sg[nsg - 1]);
|
|
|
|
-
|
|
|
|
- return nsg;
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(skb_to_sgvec);
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* skb_cow_data - Check that a socket buffer's data buffers are writable
|
|
* skb_cow_data - Check that a socket buffer's data buffers are writable
|