Name: skb_walk Function Status: Untested Signed-off-by: Rusty Russell There's no convenient function to walk the data of an skbuff; provide one. Netfilter extensions in particular can use this to examine packet contents. diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .18220-linux-2.6.7-rc3-bk7/net/core/skbuff.c .18220-linux-2.6.7-rc3-bk7.updated/net/core/skbuff.c --- .18220-linux-2.6.7-rc3-bk7/net/core/skbuff.c 2004-05-10 15:14:04.000000000 +1000 +++ .18220-linux-2.6.7-rc3-bk7.updated/net/core/skbuff.c 2004-06-16 09:59:46.000000000 +1000 @@ -1210,6 +1210,54 @@ void skb_unlink(struct sk_buff *skb) } } +static int __skb_walk(struct sk_buff *skb, + struct sk_buff *master, + int (*fn)(struct sk_buff *, void *, int, void *), + void *arg) +{ + struct sk_buff *list; + int i, ret; + + ret = fn(master, skb->data, skb_headlen(skb), arg); + if (ret) + return ret; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + vaddr = kmap_skb_frag(frag); + ret = fn(master, vaddr + frag->page_offset, frag->size, arg); + kunmap_skb_frag(vaddr); + if (ret) + return ret; + } + + for (list = skb_shinfo(skb)->frag_list; list; list = list->next) { + ret = __skb_walk(list, master, fn, arg); + if (ret) + return ret; + } + return 0; +} + +/** + * skb_walk - interate through a buffer + * @skb: buffer to iterate over + * @fn: function which takes skb, ptr, length and @arg + * @arg: final argument to pass through to @fn + * + * Iterates fairly efficiently through a (possibly nonlinear) + * @skb; returns the value of @fn, and stops if @fn returns + * non-zero. + */ +int skb_walk(struct sk_buff *skb, + int (*fn)(struct sk_buff *, void *, int, void *), + void *arg) +{ + return __skb_walk(skb, skb, fn, arg); +} + /** * skb_append - append a buffer