Signed-off-by: Sven Eckelmann sven@narfation.org --- main.c | 34 ++++++++++++++++++++++++++++++++++ main.h | 1 + 2 files changed, 35 insertions(+)
diff --git a/main.c b/main.c index 70797de..122c675 100644 --- a/main.c +++ b/main.c @@ -33,6 +33,7 @@ #include "vis.h" #include "hash.h" #include "bat_algo.h" +#include <linux/crc32c.h>
/* List manipulations on hardif_list have to be rtnl_lock()'ed, @@ -432,6 +433,39 @@ int batadv_compat_seq_print_text(struct seq_file *seq, void *offset) return 0; }
+/** + * batadv_crc32 - calculate CRC32 of the whole packet and skip bytes in header + * @skb: skb pointing to fragmented socket buffers + * @payload_ptr: Pointer to position inside the head buffer of the skb + * marking the start of the data to be CRC'ed + * + * payload_ptr must always point to the point in the skb head buffer and not to + * a fragment. + */ +__be32 batadv_crc32(const struct sk_buff *skb, u8 *payload_ptr) +{ + u32 crc = 0; + struct sk_buff *iter; + size_t skip_len, read_len; + const skb_frag_t *f; + int i; + + skip_len = payload_ptr - skb->data; + read_len = skb_headlen(skb) - skip_len; + if (read_len) + crc = crc32c(crc, payload_ptr, read_len); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + f = &skb_shinfo(skb)->frags[i]; + crc = crc32c(crc, skb_frag_address(f), skb_frag_size(f)); + } + + skb_walk_frags(skb, iter) + crc = crc32c(crc, iter->data, skb_headlen(iter)); + + return htonl(crc); +} + static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) { struct batadv_algo_ops *bat_algo_ops; diff --git a/main.h b/main.h index 2dfcf8c..bb0a710 100644 --- a/main.h +++ b/main.h @@ -177,6 +177,7 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); int batadv_algo_select(struct batadv_priv *bat_priv, char *name); int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); int batadv_compat_seq_print_text(struct seq_file *seq, void *offset); +__be32 batadv_crc32(const struct sk_buff *skb, u8 *payload_ptr);
/** * enum batadv_dbg_level - available log levels
On 2012-10-17 17:59, Sven Eckelmann wrote:
+__be32 batadv_crc32(const struct sk_buff *skb, u8 *payload_ptr) +{
- u32 crc = 0;
- struct sk_buff *iter;
- size_t skip_len, read_len;
- const skb_frag_t *f;
- int i;
- skip_len = payload_ptr - skb->data;
- read_len = skb_headlen(skb) - skip_len;
- if (read_len)
crc = crc32c(crc, payload_ptr, read_len);
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
f = &skb_shinfo(skb)->frags[i];
crc = crc32c(crc, skb_frag_address(f), skb_frag_size(f));
- }
- skb_walk_frags(skb, iter)
crc = crc32c(crc, iter->data, skb_headlen(iter));
- return htonl(crc);
+}
I tested the crc'ing of non-linear skb buffers and can confirm that it works as expected, so:
Tested-by: Martin Hundebøll martin@hundeboll.net
... at least for batadv_crc32() :)
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - Added compat code for kernel like 2.6.39 - Use kmap_atomic to get the page
compat.h | 20 ++++++++++++++++++++ main.c | 38 ++++++++++++++++++++++++++++++++++++++ main.h | 1 + 3 files changed, 59 insertions(+)
diff --git a/compat.h b/compat.h index 0caf43b..4e059e8 100644 --- a/compat.h +++ b/compat.h @@ -146,6 +146,26 @@ static inline void skb_reset_mac_len(struct sk_buff *skb) #endif /* < KERNEL_VERSION(3, 0, 0) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) + +static inline struct page *skb_frag_page(const skb_frag_t *frag) +{ + return frag->page; +} + +static inline void *skb_frag_address(const skb_frag_t *frag) +{ + return page_address(skb_frag_page(frag)) + frag->page_offset; +} + +static inline unsigned int skb_frag_size(const skb_frag_t *frag) +{ + return frag->size; +} + +#endif /* < KERNEL_VERSION(3, 2, 0) */ + + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
static inline void eth_hw_addr_random(struct net_device *dev) diff --git a/main.c b/main.c index 70797de..009c9b0 100644 --- a/main.c +++ b/main.c @@ -33,6 +33,8 @@ #include "vis.h" #include "hash.h" #include "bat_algo.h" +#include <linux/crc32c.h> +#include <linux/highmem.h>
/* List manipulations on hardif_list have to be rtnl_lock()'ed, @@ -432,6 +434,42 @@ int batadv_compat_seq_print_text(struct seq_file *seq, void *offset) return 0; }
+/** + * batadv_crc32 - calculate CRC32 of the whole packet and skip bytes in header + * @skb: skb pointing to fragmented socket buffers + * @payload_ptr: Pointer to position inside the head buffer of the skb + * marking the start of the data to be CRC'ed + * + * payload_ptr must always point to the point in the skb head buffer and not to + * a fragment. + */ +__be32 batadv_crc32(const struct sk_buff *skb, u8 *payload_ptr) +{ + u32 crc = 0; + struct sk_buff *iter; + size_t skip_len, read_len; + const skb_frag_t *f; + u8 *vaddr; + int i; + + skip_len = payload_ptr - skb->data; + read_len = skb_headlen(skb) - skip_len; + if (read_len) + crc = crc32c(crc, payload_ptr, read_len); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + f = &skb_shinfo(skb)->frags[i]; + vaddr = kmap_atomic(skb_frag_page(f)); + crc = crc32c(crc, vaddr + f->page_offset, skb_frag_size(f)); + kunmap_atomic(vaddr); + } + + skb_walk_frags(skb, iter) + crc = crc32c(crc, iter->data, skb_headlen(iter)); + + return htonl(crc); +} + static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) { struct batadv_algo_ops *bat_algo_ops; diff --git a/main.h b/main.h index 2dfcf8c..bb0a710 100644 --- a/main.h +++ b/main.h @@ -177,6 +177,7 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); int batadv_algo_select(struct batadv_priv *bat_priv, char *name); int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); int batadv_compat_seq_print_text(struct seq_file *seq, void *offset); +__be32 batadv_crc32(const struct sk_buff *skb, u8 *payload_ptr);
/** * enum batadv_dbg_level - available log levels
Signed-off-by: Sven Eckelmann sven@narfation.org --- v3: Now with support for kernels till 2.6.29
compat.h | 34 ++++++++++++++++++++++++++++++++++ main.c | 38 ++++++++++++++++++++++++++++++++++++++ main.h | 1 + 3 files changed, 73 insertions(+)
diff --git a/compat.h b/compat.h index 0caf43b..83befd1 100644 --- a/compat.h +++ b/compat.h @@ -37,6 +37,9 @@
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+#define skb_walk_frags(skb, iter) \ + for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) + #define __compat__module_param_call(p1, p2, p3, p4, p5, p6, p7) \ __module_param_call(p1, p2, p3, p4, p5, p7)
@@ -78,6 +81,17 @@ #endif /* < KERNEL_VERSION(2, 6, 35) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) + +#define kmap_atomic(p) kmap_atomic(p, KM_SKB_DATA_SOFTIRQ) + +#ifdef kunmap_atomic +#undef kunmap_atomic +#endif +#define kunmap_atomic(x, arg...) do { pagefault_enable(); } while (0) + +#endif /* < KERNEL_VERSION(2, 6, 37) */ +
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
@@ -146,6 +160,26 @@ static inline void skb_reset_mac_len(struct sk_buff *skb) #endif /* < KERNEL_VERSION(3, 0, 0) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) + +static inline struct page *skb_frag_page(const skb_frag_t *frag) +{ + return frag->page; +} + +static inline void *skb_frag_address(const skb_frag_t *frag) +{ + return page_address(skb_frag_page(frag)) + frag->page_offset; +} + +static inline unsigned int skb_frag_size(const skb_frag_t *frag) +{ + return frag->size; +} + +#endif /* < KERNEL_VERSION(3, 2, 0) */ + + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
static inline void eth_hw_addr_random(struct net_device *dev) diff --git a/main.c b/main.c index 70797de..df5f7d6 100644 --- a/main.c +++ b/main.c @@ -17,6 +17,8 @@ * 02110-1301, USA */
+#include <linux/crc32c.h> +#include <linux/highmem.h> #include "main.h" #include "sysfs.h" #include "debugfs.h" @@ -432,6 +434,42 @@ int batadv_compat_seq_print_text(struct seq_file *seq, void *offset) return 0; }
+/** + * batadv_crc32 - calculate CRC32 of the whole packet and skip bytes in header + * @skb: skb pointing to fragmented socket buffers + * @payload_ptr: Pointer to position inside the head buffer of the skb + * marking the start of the data to be CRC'ed + * + * payload_ptr must always point to the point in the skb head buffer and not to + * a fragment. + */ +__be32 batadv_crc32(const struct sk_buff *skb, u8 *payload_ptr) +{ + u32 crc = 0; + struct sk_buff *iter; + size_t skip_len, read_len; + const skb_frag_t *f; + u8 *vaddr; + int i; + + skip_len = payload_ptr - skb->data; + read_len = skb_headlen(skb) - skip_len; + if (read_len) + crc = crc32c(crc, payload_ptr, read_len); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + f = &skb_shinfo(skb)->frags[i]; + vaddr = kmap_atomic(skb_frag_page(f)); + crc = crc32c(crc, vaddr + f->page_offset, skb_frag_size(f)); + kunmap_atomic(vaddr); + } + + skb_walk_frags(skb, iter) + crc = crc32c(crc, iter->data, skb_headlen(iter)); + + return htonl(crc); +} + static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) { struct batadv_algo_ops *bat_algo_ops; diff --git a/main.h b/main.h index 2dfcf8c..bb0a710 100644 --- a/main.h +++ b/main.h @@ -177,6 +177,7 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); int batadv_algo_select(struct batadv_priv *bat_priv, char *name); int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); int batadv_compat_seq_print_text(struct seq_file *seq, void *offset); +__be32 batadv_crc32(const struct sk_buff *skb, u8 *payload_ptr);
/** * enum batadv_dbg_level - available log levels
On Thursday, October 18, 2012 03:10:39 Sven Eckelmann wrote:
Signed-off-by: Sven Eckelmann sven@narfation.org
v3: Now with support for kernels till 2.6.29
compat.h | 34 ++++++++++++++++++++++++++++++++++ main.c | 38 ++++++++++++++++++++++++++++++++++++++ main.h | 1 + 3 files changed, 73 insertions(+)
Applied in revision a7fe307.
Thanks, Marek
b.a.t.m.a.n@lists.open-mesh.org