]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: add copy from skb_seq_state to buffer function
authorChristian Hopps <chopps@labn.net>
Thu, 15 Aug 2024 17:21:14 +0000 (13:21 -0400)
committerSteffen Klassert <steffen.klassert@secunet.com>
Tue, 20 Aug 2024 06:11:48 +0000 (08:11 +0200)
Add an skb helper function to copy a range of bytes from within
an existing skb_seq_state.

Signed-off-by: Christian Hopps <chopps@labn.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
include/linux/skbuff.h
net/core/skbuff.c

index 29c3ea5b6e930ef3e856a1f6887873b967fec354..a871533b85687d891fc6b561117339dc36ebc6da 100644 (file)
@@ -1433,6 +1433,7 @@ void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
 unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
                          struct skb_seq_state *st);
 void skb_abort_seq_read(struct skb_seq_state *st);
+int skb_copy_seq_read(struct skb_seq_state *st, int offset, void *to, int len);
 
 unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
                           unsigned int to, struct ts_config *config);
index 83f8cd8aa2d16a56b383e1042fcc0df6b51fe8c2..fe4b2dc5c19b2412348e13c8513f36f2bbbff9e8 100644 (file)
@@ -4409,6 +4409,41 @@ void skb_abort_seq_read(struct skb_seq_state *st)
 }
 EXPORT_SYMBOL(skb_abort_seq_read);
 
+/**
+ * skb_copy_seq_read() - copy from a skb_seq_state to a buffer
+ * @st: source skb_seq_state
+ * @offset: offset in source
+ * @to: destination buffer
+ * @len: number of bytes to copy
+ *
+ * Copy @len bytes from @offset bytes into the source @st to the destination
+ * buffer @to. `offset` should increase (or be unchanged) with each subsequent
+ * call to this function. If offset needs to decrease from the previous use `st`
+ * should be reset first.
+ *
+ * Return: 0 on success or -EINVAL if the copy ended early
+ */
+int skb_copy_seq_read(struct skb_seq_state *st, int offset, void *to, int len)
+{
+       const u8 *data;
+       u32 sqlen;
+
+       for (;;) {
+               sqlen = skb_seq_read(offset, &data, st);
+               if (sqlen == 0)
+                       return -EINVAL;
+               if (sqlen >= len) {
+                       memcpy(to, data, len);
+                       return 0;
+               }
+               memcpy(to, data, sqlen);
+               to += sqlen;
+               offset += sqlen;
+               len -= sqlen;
+       }
+}
+EXPORT_SYMBOL(skb_copy_seq_read);
+
 #define TS_SKB_CB(state)       ((struct skb_seq_state *) &((state)->cb))
 
 static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text,