···127127#define TCP_WINDOW_CLAMP 10 /* Bound advertised window */128128#define TCP_INFO 11 /* Information about this connection. */129129#define TCP_QUICKACK 12 /* Block/reenable quick acks */130130+#define TCP_CONGESTION 13 /* Congestion control algorithm */130131131132#define TCPI_OPT_TIMESTAMPS 1132133#define TCPI_OPT_SACK 2
+180
include/linux/textsearch.h
···11+#ifndef __LINUX_TEXTSEARCH_H22+#define __LINUX_TEXTSEARCH_H33+44+#ifdef __KERNEL__55+66+#include <linux/types.h>77+#include <linux/list.h>88+#include <linux/kernel.h>99+#include <linux/module.h>1010+#include <linux/err.h>1111+1212+struct ts_config;1313+1414+/**1515+ * TS_AUTOLOAD - Automatically load textsearch modules when needed1616+ */1717+#define TS_AUTOLOAD 11818+1919+/**2020+ * struct ts_state - search state2121+ * @offset: offset for next match2222+ * @cb: control buffer, for persistant variables of get_next_block()2323+ */2424+struct ts_state2525+{2626+ unsigned int offset;2727+ char cb[40];2828+};2929+3030+/**3131+ * struct ts_ops - search module operations3232+ * @name: name of search algorithm3333+ * @init: initialization function to prepare a search3434+ * @find: find the next occurrence of the pattern3535+ * @destroy: destroy algorithm specific parts of a search configuration3636+ * @get_pattern: return head of pattern3737+ * @get_pattern_len: return length of pattern3838+ * @owner: module reference to algorithm3939+ */4040+struct ts_ops4141+{4242+ const char *name;4343+ struct ts_config * (*init)(const void *, unsigned int, int);4444+ unsigned int (*find)(struct ts_config *,4545+ struct ts_state *);4646+ void (*destroy)(struct ts_config *);4747+ void * (*get_pattern)(struct ts_config *);4848+ unsigned int (*get_pattern_len)(struct ts_config *);4949+ struct module *owner;5050+ struct list_head list;5151+};5252+5353+/**5454+ * struct ts_config - search configuration5555+ * @ops: operations of chosen algorithm5656+ * @get_next_block: callback to fetch the next block to search in5757+ * @finish: callback to finalize a search5858+ */5959+struct ts_config6060+{6161+ struct ts_ops *ops;6262+6363+ /**6464+ * get_next_block - fetch next block of data6565+ * @consumed: number of bytes consumed by the caller6666+ * @dst: destination buffer6767+ * @conf: search configuration6868+ * @state: search state6969+ *7070+ * Called repeatedly until 0 is returned. Must assign the7171+ * head of the next block of data to &*dst and return the length7272+ * of the block or 0 if at the end. consumed == 0 indicates7373+ * a new search. May store/read persistant values in state->cb.7474+ */7575+ unsigned int (*get_next_block)(unsigned int consumed,7676+ const u8 **dst,7777+ struct ts_config *conf,7878+ struct ts_state *state);7979+8080+ /**8181+ * finish - finalize/clean a series of get_next_block() calls8282+ * @conf: search configuration8383+ * @state: search state8484+ *8585+ * Called after the last use of get_next_block(), may be used8686+ * to cleanup any leftovers.8787+ */8888+ void (*finish)(struct ts_config *conf,8989+ struct ts_state *state);9090+};9191+9292+/**9393+ * textsearch_next - continue searching for a pattern9494+ * @conf: search configuration9595+ * @state: search state9696+ *9797+ * Continues a search looking for more occurrences of the pattern.9898+ * textsearch_find() must be called to find the first occurrence9999+ * in order to reset the state.100100+ *101101+ * Returns the position of the next occurrence of the pattern or102102+ * UINT_MAX if not match was found.103103+ */ 104104+static inline unsigned int textsearch_next(struct ts_config *conf,105105+ struct ts_state *state)106106+{107107+ unsigned int ret = conf->ops->find(conf, state);108108+109109+ if (conf->finish)110110+ conf->finish(conf, state);111111+112112+ return ret;113113+}114114+115115+/**116116+ * textsearch_find - start searching for a pattern117117+ * @conf: search configuration118118+ * @state: search state119119+ *120120+ * Returns the position of first occurrence of the pattern or121121+ * UINT_MAX if no match was found.122122+ */ 123123+static inline unsigned int textsearch_find(struct ts_config *conf,124124+ struct ts_state *state)125125+{126126+ state->offset = 0;127127+ return textsearch_next(conf, state);128128+}129129+130130+/**131131+ * textsearch_get_pattern - return head of the pattern132132+ * @conf: search configuration133133+ */134134+static inline void *textsearch_get_pattern(struct ts_config *conf)135135+{136136+ return conf->ops->get_pattern(conf);137137+}138138+139139+/**140140+ * textsearch_get_pattern_len - return length of the pattern141141+ * @conf: search configuration142142+ */143143+static inline unsigned int textsearch_get_pattern_len(struct ts_config *conf)144144+{145145+ return conf->ops->get_pattern_len(conf);146146+}147147+148148+extern int textsearch_register(struct ts_ops *);149149+extern int textsearch_unregister(struct ts_ops *);150150+extern struct ts_config *textsearch_prepare(const char *, const void *,151151+ unsigned int, int, int);152152+extern void textsearch_destroy(struct ts_config *conf);153153+extern unsigned int textsearch_find_continuous(struct ts_config *,154154+ struct ts_state *,155155+ const void *, unsigned int);156156+157157+158158+#define TS_PRIV_ALIGNTO 8159159+#define TS_PRIV_ALIGN(len) (((len) + TS_PRIV_ALIGNTO-1) & ~(TS_PRIV_ALIGNTO-1))160160+161161+static inline struct ts_config *alloc_ts_config(size_t payload, int gfp_mask)162162+{163163+ struct ts_config *conf;164164+165165+ conf = kmalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask);166166+ if (conf == NULL)167167+ return ERR_PTR(-ENOMEM);168168+169169+ memset(conf, 0, TS_PRIV_ALIGN(sizeof(*conf)) + payload);170170+ return conf;171171+}172172+173173+static inline void *ts_config_priv(struct ts_config *conf)174174+{175175+ return ((u8 *) conf + TS_PRIV_ALIGN(sizeof(struct ts_config)));176176+}177177+178178+#endif /* __KERNEL__ */179179+180180+#endif
+48
include/linux/textsearch_fsm.h
···11+#ifndef __LINUX_TEXTSEARCH_FSM_H22+#define __LINUX_TEXTSEARCH_FSM_H33+44+#include <linux/types.h>55+66+enum {77+ TS_FSM_SPECIFIC, /* specific character */88+ TS_FSM_WILDCARD, /* any character */99+ TS_FSM_DIGIT, /* isdigit() */1010+ TS_FSM_XDIGIT, /* isxdigit() */1111+ TS_FSM_PRINT, /* isprint() */1212+ TS_FSM_ALPHA, /* isalpha() */1313+ TS_FSM_ALNUM, /* isalnum() */1414+ TS_FSM_ASCII, /* isascii() */1515+ TS_FSM_CNTRL, /* iscntrl() */1616+ TS_FSM_GRAPH, /* isgraph() */1717+ TS_FSM_LOWER, /* islower() */1818+ TS_FSM_UPPER, /* isupper() */1919+ TS_FSM_PUNCT, /* ispunct() */2020+ TS_FSM_SPACE, /* isspace() */2121+ __TS_FSM_TYPE_MAX,2222+};2323+#define TS_FSM_TYPE_MAX (__TS_FSM_TYPE_MAX - 1)2424+2525+enum {2626+ TS_FSM_SINGLE, /* 1 occurrence */2727+ TS_FSM_PERHAPS, /* 1 or 0 occurrence */2828+ TS_FSM_ANY, /* 0..n occurrences */2929+ TS_FSM_MULTI, /* 1..n occurrences */3030+ TS_FSM_HEAD_IGNORE, /* 0..n ignored occurrences at head */3131+ __TS_FSM_RECUR_MAX,3232+};3333+#define TS_FSM_RECUR_MAX (__TS_FSM_RECUR_MAX - 1)3434+3535+/**3636+ * struct ts_fsm_token - state machine token (state)3737+ * @type: type of token3838+ * @recur: number of recurrences3939+ * @value: character value for TS_FSM_SPECIFIC4040+ */4141+struct ts_fsm_token4242+{4343+ __u16 type;4444+ __u8 recur;4545+ __u8 value;4646+};4747+4848+#endif
···6363config REED_SOLOMON_DEC166464 boolean65656666-endmenu6666+config TEXTSEARCH6767+ boolean "Textsearch infrastructure"6868+ default y6969+ help7070+ Say Y here if you want to provide a textsearch infrastructure7171+ to other subsystems.67727373+config TEXTSEARCH_KMP7474+ depends on TEXTSEARCH7575+ tristate "Knuth-Morris-Pratt"7676+ help7777+ Say Y here if you want to be able to search text using the7878+ Knuth-Morris-Pratt textsearch algorithm.7979+8080+ To compile this code as a module, choose M here: the8181+ module will be called ts_kmp.8282+8383+config TEXTSEARCH_FSM8484+ depends on TEXTSEARCH8585+ tristate "Finite state machine"8686+ help8787+ Say Y here if you want to be able to search text using a8888+ naive finite state machine approach implementing a subset8989+ of regular expressions.9090+9191+ To compile this code as a module, choose M here: the9292+ module will be called ts_fsm.9393+9494+endmenu
···11+/*22+ * lib/textsearch.c Generic text search interface33+ *44+ * This program is free software; you can redistribute it and/or55+ * modify it under the terms of the GNU General Public License66+ * as published by the Free Software Foundation; either version77+ * 2 of the License, or (at your option) any later version.88+ *99+ * Authors: Thomas Graf <tgraf@suug.ch>1010+ * Pablo Neira Ayuso <pablo@eurodev.net>1111+ *1212+ * ==========================================================================1313+ *1414+ * INTRODUCTION1515+ *1616+ * The textsearch infrastructure provides text searching facitilies for1717+ * both linear and non-linear data. Individual search algorithms are1818+ * implemented in modules and chosen by the user.1919+ *2020+ * ARCHITECTURE2121+ *2222+ * User2323+ * +----------------+2424+ * | finish()|<--------------(6)-----------------+2525+ * |get_next_block()|<--------------(5)---------------+ |2626+ * | | Algorithm | |2727+ * | | +------------------------------+2828+ * | | | init() find() destroy() |2929+ * | | +------------------------------+3030+ * | | Core API ^ ^ ^3131+ * | | +---------------+ (2) (4) (8)3232+ * | (1)|----->| prepare() |---+ | |3333+ * | (3)|----->| find()/next() |-----------+ |3434+ * | (7)|----->| destroy() |----------------------+3535+ * +----------------+ +---------------+3636+ * 3737+ * (1) User configures a search by calling _prepare() specifying the3838+ * search parameters such as the pattern and algorithm name.3939+ * (2) Core requests the algorithm to allocate and initialize a search4040+ * configuration according to the specified parameters.4141+ * (3) User starts the search(es) by calling _find() or _next() to4242+ * fetch subsequent occurrences. A state variable is provided4343+ * to the algorihtm to store persistant variables.4444+ * (4) Core eventually resets the search offset and forwards the find()4545+ * request to the algorithm.4646+ * (5) Algorithm calls get_next_block() provided by the user continously4747+ * to fetch the data to be searched in block by block.4848+ * (6) Algorithm invokes finish() after the last call to get_next_block4949+ * to clean up any leftovers from get_next_block. (Optional)5050+ * (7) User destroys the configuration by calling _destroy().5151+ * (8) Core notifies the algorithm to destroy algorithm specific5252+ * allocations. (Optional)5353+ *5454+ * USAGE5555+ *5656+ * Before a search can be performed, a configuration must be created5757+ * by calling textsearch_prepare() specyfing the searching algorithm and5858+ * the pattern to look for. The returned configuration may then be used5959+ * for an arbitary amount of times and even in parallel as long as a6060+ * separate struct ts_state variable is provided to every instance.6161+ *6262+ * The actual search is performed by either calling textsearch_find_-6363+ * continuous() for linear data or by providing an own get_next_block()6464+ * implementation and calling textsearch_find(). Both functions return6565+ * the position of the first occurrence of the patern or UINT_MAX if6666+ * no match was found. Subsequent occurences can be found by calling6767+ * textsearch_next() regardless of the linearity of the data.6868+ *6969+ * Once you're done using a configuration it must be given back via7070+ * textsearch_destroy.7171+ *7272+ * EXAMPLE7373+ *7474+ * int pos;7575+ * struct ts_config *conf;7676+ * struct ts_state state;7777+ * const char *pattern = "chicken";7878+ * const char *example = "We dance the funky chicken";7979+ *8080+ * conf = textsearch_prepare("kmp", pattern, strlen(pattern),8181+ * GFP_KERNEL, TS_AUTOLOAD);8282+ * if (IS_ERR(conf)) {8383+ * err = PTR_ERR(conf);8484+ * goto errout;8585+ * }8686+ *8787+ * pos = textsearch_find_continuous(conf, &state, example, strlen(example));8888+ * if (pos != UINT_MAX)8989+ * panic("Oh my god, dancing chickens at %d\n", pos);9090+ *9191+ * textsearch_destroy(conf);9292+ *9393+ * ==========================================================================9494+ */9595+9696+#include <linux/config.h>9797+#include <linux/module.h>9898+#include <linux/types.h>9999+#include <linux/string.h>100100+#include <linux/init.h>101101+#include <linux/rcupdate.h>102102+#include <linux/err.h>103103+#include <linux/textsearch.h>104104+105105+static LIST_HEAD(ts_ops);106106+static DEFINE_SPINLOCK(ts_mod_lock);107107+108108+static inline struct ts_ops *lookup_ts_algo(const char *name)109109+{110110+ struct ts_ops *o;111111+112112+ rcu_read_lock();113113+ list_for_each_entry_rcu(o, &ts_ops, list) {114114+ if (!strcmp(name, o->name)) {115115+ if (!try_module_get(o->owner))116116+ o = NULL;117117+ rcu_read_unlock();118118+ return o;119119+ }120120+ }121121+ rcu_read_unlock();122122+123123+ return NULL;124124+}125125+126126+/**127127+ * textsearch_register - register a textsearch module128128+ * @ops: operations lookup table129129+ *130130+ * This function must be called by textsearch modules to announce131131+ * their presence. The specified &@ops must have %name set to a132132+ * unique identifier and the callbacks find(), init(), get_pattern(),133133+ * and get_pattern_len() must be implemented.134134+ *135135+ * Returns 0 or -EEXISTS if another module has already registered136136+ * with same name.137137+ */138138+int textsearch_register(struct ts_ops *ops)139139+{140140+ int err = -EEXIST;141141+ struct ts_ops *o;142142+143143+ if (ops->name == NULL || ops->find == NULL || ops->init == NULL ||144144+ ops->get_pattern == NULL || ops->get_pattern_len == NULL)145145+ return -EINVAL;146146+147147+ spin_lock(&ts_mod_lock);148148+ list_for_each_entry(o, &ts_ops, list) {149149+ if (!strcmp(ops->name, o->name))150150+ goto errout;151151+ }152152+153153+ list_add_tail_rcu(&ops->list, &ts_ops);154154+ err = 0;155155+errout:156156+ spin_unlock(&ts_mod_lock);157157+ return err;158158+}159159+160160+/**161161+ * textsearch_unregister - unregister a textsearch module162162+ * @ops: operations lookup table163163+ *164164+ * This function must be called by textsearch modules to announce165165+ * their disappearance for examples when the module gets unloaded.166166+ * The &ops parameter must be the same as the one during the167167+ * registration.168168+ *169169+ * Returns 0 on success or -ENOENT if no matching textsearch170170+ * registration was found.171171+ */172172+int textsearch_unregister(struct ts_ops *ops)173173+{174174+ int err = 0;175175+ struct ts_ops *o;176176+177177+ spin_lock(&ts_mod_lock);178178+ list_for_each_entry(o, &ts_ops, list) {179179+ if (o == ops) {180180+ list_del_rcu(&o->list);181181+ goto out;182182+ }183183+ }184184+185185+ err = -ENOENT;186186+out:187187+ spin_unlock(&ts_mod_lock);188188+ return err;189189+}190190+191191+struct ts_linear_state192192+{193193+ unsigned int len;194194+ const void *data;195195+};196196+197197+static unsigned int get_linear_data(unsigned int consumed, const u8 **dst,198198+ struct ts_config *conf,199199+ struct ts_state *state)200200+{201201+ struct ts_linear_state *st = (struct ts_linear_state *) state->cb;202202+203203+ if (likely(consumed < st->len)) {204204+ *dst = st->data + consumed;205205+ return st->len - consumed;206206+ }207207+208208+ return 0;209209+}210210+211211+/**212212+ * textsearch_find_continuous - search a pattern in continuous/linear data213213+ * @conf: search configuration214214+ * @state: search state215215+ * @data: data to search in216216+ * @len: length of data217217+ *218218+ * A simplified version of textsearch_find() for continuous/linear data.219219+ * Call textsearch_next() to retrieve subsequent matches.220220+ *221221+ * Returns the position of first occurrence of the pattern or222222+ * UINT_MAX if no occurrence was found.223223+ */ 224224+unsigned int textsearch_find_continuous(struct ts_config *conf,225225+ struct ts_state *state,226226+ const void *data, unsigned int len)227227+{228228+ struct ts_linear_state *st = (struct ts_linear_state *) state->cb;229229+230230+ conf->get_next_block = get_linear_data;231231+ st->data = data;232232+ st->len = len;233233+234234+ return textsearch_find(conf, state);235235+}236236+237237+/**238238+ * textsearch_prepare - Prepare a search239239+ * @algo: name of search algorithm240240+ * @pattern: pattern data241241+ * @len: length of pattern242242+ * @gfp_mask: allocation mask243243+ * @flags: search flags244244+ *245245+ * Looks up the search algorithm module and creates a new textsearch246246+ * configuration for the specified pattern. Upon completion all247247+ * necessary refcnts are held and the configuration must be put back248248+ * using textsearch_put() after usage.249249+ *250250+ * Note: The format of the pattern may not be compatible between251251+ * the various search algorithms.252252+ *253253+ * Returns a new textsearch configuration according to the specified254254+ * parameters or a ERR_PTR().255255+ */256256+struct ts_config *textsearch_prepare(const char *algo, const void *pattern,257257+ unsigned int len, int gfp_mask, int flags)258258+{259259+ int err = -ENOENT;260260+ struct ts_config *conf;261261+ struct ts_ops *ops;262262+263263+ ops = lookup_ts_algo(algo);264264+#ifdef CONFIG_KMOD265265+ /*266266+ * Why not always autoload you may ask. Some users are267267+ * in a situation where requesting a module may deadlock,268268+ * especially when the module is located on a NFS mount.269269+ */270270+ if (ops == NULL && flags & TS_AUTOLOAD) {271271+ request_module("ts_%s", algo);272272+ ops = lookup_ts_algo(algo);273273+ }274274+#endif275275+276276+ if (ops == NULL)277277+ goto errout;278278+279279+ conf = ops->init(pattern, len, gfp_mask);280280+ if (IS_ERR(conf)) {281281+ err = PTR_ERR(conf);282282+ goto errout;283283+ }284284+285285+ conf->ops = ops;286286+ return conf;287287+288288+errout:289289+ if (ops)290290+ module_put(ops->owner);291291+292292+ return ERR_PTR(err);293293+}294294+295295+/**296296+ * textsearch_destroy - destroy a search configuration297297+ * @conf: search configuration298298+ *299299+ * Releases all references of the configuration and frees300300+ * up the memory.301301+ */302302+void textsearch_destroy(struct ts_config *conf)303303+{304304+ if (conf->ops) {305305+ if (conf->ops->destroy)306306+ conf->ops->destroy(conf);307307+ module_put(conf->ops->owner);308308+ }309309+310310+ kfree(conf);311311+}312312+313313+EXPORT_SYMBOL(textsearch_register);314314+EXPORT_SYMBOL(textsearch_unregister);315315+EXPORT_SYMBOL(textsearch_prepare);316316+EXPORT_SYMBOL(textsearch_find_continuous);317317+EXPORT_SYMBOL(textsearch_destroy);
+338
lib/ts_fsm.c
···11+/*22+ * lib/ts_fsm.c A naive finite state machine text search approach33+ *44+ * This program is free software; you can redistribute it and/or55+ * modify it under the terms of the GNU General Public License66+ * as published by the Free Software Foundation; either version77+ * 2 of the License, or (at your option) any later version.88+ *99+ * Authors: Thomas Graf <tgraf@suug.ch>1010+ *1111+ * ==========================================================================1212+ *1313+ * A finite state machine consists of n states (struct ts_fsm_token)1414+ * representing the pattern as a finite automation. The data is read1515+ * sequentially on a octet basis. Every state token specifies the number1616+ * of recurrences and the type of value accepted which can be either a1717+ * specific character or ctype based set of characters. The available1818+ * type of recurrences include 1, (0|1), [0 n], and [1 n].1919+ *2020+ * The algorithm differs between strict/non-strict mode specyfing2121+ * whether the pattern has to start at the first octect. Strict mode2222+ * is enabled by default and can be disabled by inserting2323+ * TS_FSM_HEAD_IGNORE as the first token in the chain.2424+ *2525+ * The runtime performance of the algorithm should be around O(n),2626+ * however while in strict mode the average runtime can be better.2727+ */2828+2929+#include <linux/config.h>3030+#include <linux/module.h>3131+#include <linux/types.h>3232+#include <linux/string.h>3333+#include <linux/ctype.h>3434+#include <linux/textsearch.h>3535+#include <linux/textsearch_fsm.h>3636+3737+struct ts_fsm3838+{3939+ unsigned int ntokens;4040+ struct ts_fsm_token tokens[0];4141+};4242+4343+/* other values derived from ctype.h */4444+#define _A 0x100 /* ascii */4545+#define _W 0x200 /* wildcard */4646+4747+/* Map to _ctype flags and some magic numbers */4848+static u16 token_map[TS_FSM_TYPE_MAX+1] = {4949+ [TS_FSM_SPECIFIC] = 0,5050+ [TS_FSM_WILDCARD] = _W,5151+ [TS_FSM_CNTRL] = _C,5252+ [TS_FSM_LOWER] = _L,5353+ [TS_FSM_UPPER] = _U,5454+ [TS_FSM_PUNCT] = _P,5555+ [TS_FSM_SPACE] = _S,5656+ [TS_FSM_DIGIT] = _D,5757+ [TS_FSM_XDIGIT] = _D | _X,5858+ [TS_FSM_ALPHA] = _U | _L,5959+ [TS_FSM_ALNUM] = _U | _L | _D,6060+ [TS_FSM_PRINT] = _P | _U | _L | _D | _SP,6161+ [TS_FSM_GRAPH] = _P | _U | _L | _D,6262+ [TS_FSM_ASCII] = _A,6363+};6464+6565+static u16 token_lookup_tbl[256] = {6666+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 0- 3 */6767+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 4- 7 */6868+_W|_A|_C, _W|_A|_C|_S, _W|_A|_C|_S, _W|_A|_C|_S, /* 8- 11 */6969+_W|_A|_C|_S, _W|_A|_C|_S, _W|_A|_C, _W|_A|_C, /* 12- 15 */7070+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 16- 19 */7171+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 20- 23 */7272+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 24- 27 */7373+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 28- 31 */7474+_W|_A|_S|_SP, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 32- 35 */7575+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 36- 39 */7676+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 40- 43 */7777+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 44- 47 */7878+_W|_A|_D, _W|_A|_D, _W|_A|_D, _W|_A|_D, /* 48- 51 */7979+_W|_A|_D, _W|_A|_D, _W|_A|_D, _W|_A|_D, /* 52- 55 */8080+_W|_A|_D, _W|_A|_D, _W|_A|_P, _W|_A|_P, /* 56- 59 */8181+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 60- 63 */8282+_W|_A|_P, _W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U|_X, /* 64- 67 */8383+_W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U, /* 68- 71 */8484+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 72- 75 */8585+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 76- 79 */8686+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 80- 83 */8787+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 84- 87 */8888+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_P, /* 88- 91 */8989+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 92- 95 */9090+_W|_A|_P, _W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L|_X, /* 96- 99 */9191+_W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L, /* 100-103 */9292+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 104-107 */9393+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 108-111 */9494+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 112-115 */9595+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 116-119 */9696+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_P, /* 120-123 */9797+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_C, /* 124-127 */9898+_W, _W, _W, _W, /* 128-131 */9999+_W, _W, _W, _W, /* 132-135 */100100+_W, _W, _W, _W, /* 136-139 */101101+_W, _W, _W, _W, /* 140-143 */102102+_W, _W, _W, _W, /* 144-147 */103103+_W, _W, _W, _W, /* 148-151 */104104+_W, _W, _W, _W, /* 152-155 */105105+_W, _W, _W, _W, /* 156-159 */106106+_W|_S|_SP, _W|_P, _W|_P, _W|_P, /* 160-163 */107107+_W|_P, _W|_P, _W|_P, _W|_P, /* 164-167 */108108+_W|_P, _W|_P, _W|_P, _W|_P, /* 168-171 */109109+_W|_P, _W|_P, _W|_P, _W|_P, /* 172-175 */110110+_W|_P, _W|_P, _W|_P, _W|_P, /* 176-179 */111111+_W|_P, _W|_P, _W|_P, _W|_P, /* 180-183 */112112+_W|_P, _W|_P, _W|_P, _W|_P, /* 184-187 */113113+_W|_P, _W|_P, _W|_P, _W|_P, /* 188-191 */114114+_W|_U, _W|_U, _W|_U, _W|_U, /* 192-195 */115115+_W|_U, _W|_U, _W|_U, _W|_U, /* 196-199 */116116+_W|_U, _W|_U, _W|_U, _W|_U, /* 200-203 */117117+_W|_U, _W|_U, _W|_U, _W|_U, /* 204-207 */118118+_W|_U, _W|_U, _W|_U, _W|_U, /* 208-211 */119119+_W|_U, _W|_U, _W|_U, _W|_P, /* 212-215 */120120+_W|_U, _W|_U, _W|_U, _W|_U, /* 216-219 */121121+_W|_U, _W|_U, _W|_U, _W|_L, /* 220-223 */122122+_W|_L, _W|_L, _W|_L, _W|_L, /* 224-227 */123123+_W|_L, _W|_L, _W|_L, _W|_L, /* 228-231 */124124+_W|_L, _W|_L, _W|_L, _W|_L, /* 232-235 */125125+_W|_L, _W|_L, _W|_L, _W|_L, /* 236-239 */126126+_W|_L, _W|_L, _W|_L, _W|_L, /* 240-243 */127127+_W|_L, _W|_L, _W|_L, _W|_P, /* 244-247 */128128+_W|_L, _W|_L, _W|_L, _W|_L, /* 248-251 */129129+_W|_L, _W|_L, _W|_L, _W|_L}; /* 252-255 */130130+131131+static inline int match_token(struct ts_fsm_token *t, u8 d)132132+{133133+ if (t->type)134134+ return (token_lookup_tbl[d] & t->type) != 0;135135+ else136136+ return t->value == d;137137+}138138+139139+static unsigned int fsm_find(struct ts_config *conf, struct ts_state *state)140140+{141141+ struct ts_fsm *fsm = ts_config_priv(conf);142142+ struct ts_fsm_token *cur = NULL, *next;143143+ unsigned int match_start, block_idx = 0, tok_idx;144144+ unsigned block_len = 0, strict, consumed = state->offset;145145+ const u8 *data;146146+147147+#define GET_NEXT_BLOCK() \148148+({ consumed += block_idx; \149149+ block_idx = 0; \150150+ block_len = conf->get_next_block(consumed, &data, conf, state); })151151+152152+#define TOKEN_MISMATCH() \153153+ do { \154154+ if (strict) \155155+ goto no_match; \156156+ block_idx++; \157157+ goto startover; \158158+ } while(0)159159+160160+#define end_of_data() unlikely(block_idx >= block_len && !GET_NEXT_BLOCK())161161+162162+ if (end_of_data())163163+ goto no_match;164164+165165+ strict = fsm->tokens[0].recur != TS_FSM_HEAD_IGNORE;166166+167167+startover:168168+ match_start = consumed + block_idx;169169+170170+ for (tok_idx = 0; tok_idx < fsm->ntokens; tok_idx++) {171171+ cur = &fsm->tokens[tok_idx];172172+173173+ if (likely(tok_idx < (fsm->ntokens - 1)))174174+ next = &fsm->tokens[tok_idx + 1];175175+ else176176+ next = NULL;177177+178178+ switch (cur->recur) {179179+ case TS_FSM_SINGLE:180180+ if (end_of_data())181181+ goto no_match;182182+183183+ if (!match_token(cur, data[block_idx]))184184+ TOKEN_MISMATCH();185185+ break;186186+187187+ case TS_FSM_PERHAPS:188188+ if (end_of_data() ||189189+ !match_token(cur, data[block_idx]))190190+ continue;191191+ break;192192+193193+ case TS_FSM_MULTI:194194+ if (end_of_data())195195+ goto no_match;196196+197197+ if (!match_token(cur, data[block_idx]))198198+ TOKEN_MISMATCH();199199+200200+ block_idx++;201201+ /* fall through */202202+203203+ case TS_FSM_ANY:204204+ if (next == NULL)205205+ goto found_match;206206+207207+ if (end_of_data())208208+ continue;209209+210210+ while (!match_token(next, data[block_idx])) {211211+ if (!match_token(cur, data[block_idx]))212212+ TOKEN_MISMATCH();213213+ block_idx++;214214+ if (end_of_data())215215+ goto no_match;216216+ }217217+ continue;218218+219219+ /*220220+ * Optimization: Prefer small local loop over jumping221221+ * back and forth until garbage at head is munched.222222+ */223223+ case TS_FSM_HEAD_IGNORE:224224+ if (end_of_data())225225+ continue;226226+227227+ while (!match_token(next, data[block_idx])) {228228+ /*229229+ * Special case, don't start over upon230230+ * a mismatch, give the user the231231+ * chance to specify the type of data232232+ * allowed to be ignored.233233+ */234234+ if (!match_token(cur, data[block_idx]))235235+ goto no_match;236236+237237+ block_idx++;238238+ if (end_of_data())239239+ goto no_match;240240+ }241241+242242+ match_start = consumed + block_idx;243243+ continue;244244+ }245245+246246+ block_idx++;247247+ }248248+249249+ if (end_of_data())250250+ goto found_match;251251+252252+no_match:253253+ return UINT_MAX;254254+255255+found_match:256256+ state->offset = consumed + block_idx;257257+ return match_start;258258+}259259+260260+static struct ts_config *fsm_init(const void *pattern, unsigned int len,261261+ int gfp_mask)262262+{263263+ int i, err = -EINVAL;264264+ struct ts_config *conf;265265+ struct ts_fsm *fsm;266266+ struct ts_fsm_token *tokens = (struct ts_fsm_token *) pattern;267267+ unsigned int ntokens = len / sizeof(*tokens);268268+ size_t priv_size = sizeof(*fsm) + len;269269+270270+ if (len % sizeof(struct ts_fsm_token) || ntokens < 1)271271+ goto errout;272272+273273+ for (i = 0; i < ntokens; i++) {274274+ struct ts_fsm_token *t = &tokens[i];275275+276276+ if (t->type > TS_FSM_TYPE_MAX || t->recur > TS_FSM_RECUR_MAX)277277+ goto errout;278278+279279+ if (t->recur == TS_FSM_HEAD_IGNORE &&280280+ (i != 0 || i == (ntokens - 1)))281281+ goto errout;282282+ }283283+284284+ conf = alloc_ts_config(priv_size, gfp_mask);285285+ if (IS_ERR(conf))286286+ return conf;287287+288288+ fsm = ts_config_priv(conf);289289+ fsm->ntokens = ntokens;290290+ memcpy(fsm->tokens, pattern, len);291291+292292+ for (i = 0; i < fsm->ntokens; i++) {293293+ struct ts_fsm_token *t = &fsm->tokens[i];294294+ t->type = token_map[t->type];295295+ }296296+297297+ return conf;298298+299299+errout:300300+ return ERR_PTR(err);301301+}302302+303303+static void *fsm_get_pattern(struct ts_config *conf)304304+{305305+ struct ts_fsm *fsm = ts_config_priv(conf);306306+ return fsm->tokens;307307+}308308+309309+static unsigned int fsm_get_pattern_len(struct ts_config *conf)310310+{311311+ struct ts_fsm *fsm = ts_config_priv(conf);312312+ return fsm->ntokens * sizeof(struct ts_fsm_token);313313+}314314+315315+static struct ts_ops fsm_ops = {316316+ .name = "fsm",317317+ .find = fsm_find,318318+ .init = fsm_init,319319+ .get_pattern = fsm_get_pattern,320320+ .get_pattern_len = fsm_get_pattern_len,321321+ .owner = THIS_MODULE,322322+ .list = LIST_HEAD_INIT(fsm_ops.list)323323+};324324+325325+static int __init init_fsm(void)326326+{327327+ return textsearch_register(&fsm_ops);328328+}329329+330330+static void __exit exit_fsm(void)331331+{332332+ textsearch_unregister(&fsm_ops);333333+}334334+335335+MODULE_LICENSE("GPL");336336+337337+module_init(init_fsm);338338+module_exit(exit_fsm);
+145
lib/ts_kmp.c
···11+/*22+ * lib/ts_kmp.c Knuth-Morris-Pratt text search implementation33+ *44+ * This program is free software; you can redistribute it and/or55+ * modify it under the terms of the GNU General Public License66+ * as published by the Free Software Foundation; either version77+ * 2 of the License, or (at your option) any later version.88+ *99+ * Authors: Thomas Graf <tgraf@suug.ch>1010+ *1111+ * ==========================================================================1212+ * 1313+ * Implements a linear-time string-matching algorithm due to Knuth,1414+ * Morris, and Pratt [1]. Their algorithm avoids the explicit1515+ * computation of the transition function DELTA altogether. Its1616+ * matching time is O(n), for n being length(text), using just an1717+ * auxiliary function PI[1..m], for m being length(pattern),1818+ * precomputed from the pattern in time O(m). The array PI allows1919+ * the transition function DELTA to be computed efficiently2020+ * "on the fly" as needed. Roughly speaking, for any state2121+ * "q" = 0,1,...,m and any character "a" in SIGMA, the value2222+ * PI["q"] contains the information that is independent of "a" and2323+ * is needed to compute DELTA("q", "a") [2]. Since the array PI2424+ * has only m entries, whereas DELTA has O(m|SIGMA|) entries, we2525+ * save a factor of |SIGMA| in the preprocessing time by computing2626+ * PI rather than DELTA.2727+ *2828+ * [1] Cormen, Leiserson, Rivest, Stein2929+ * Introdcution to Algorithms, 2nd Edition, MIT Press3030+ * [2] See finite automation theory3131+ */3232+3333+#include <linux/config.h>3434+#include <linux/module.h>3535+#include <linux/types.h>3636+#include <linux/string.h>3737+#include <linux/textsearch.h>3838+3939+struct ts_kmp4040+{4141+ u8 * pattern;4242+ unsigned int pattern_len;4343+ unsigned int prefix_tbl[0];4444+};4545+4646+static unsigned int kmp_find(struct ts_config *conf, struct ts_state *state)4747+{4848+ struct ts_kmp *kmp = ts_config_priv(conf);4949+ unsigned int i, q = 0, text_len, consumed = state->offset;5050+ const u8 *text;5151+5252+ for (;;) {5353+ text_len = conf->get_next_block(consumed, &text, conf, state);5454+5555+ if (unlikely(text_len == 0))5656+ break;5757+5858+ for (i = 0; i < text_len; i++) {5959+ while (q > 0 && kmp->pattern[q] != text[i])6060+ q = kmp->prefix_tbl[q - 1];6161+ if (kmp->pattern[q] == text[i])6262+ q++;6363+ if (unlikely(q == kmp->pattern_len)) {6464+ state->offset = consumed + i + 1;6565+ return state->offset - kmp->pattern_len;6666+ }6767+ }6868+6969+ consumed += text_len;7070+ }7171+7272+ return UINT_MAX;7373+}7474+7575+static inline void compute_prefix_tbl(const u8 *pattern, unsigned int len,7676+ unsigned int *prefix_tbl)7777+{7878+ unsigned int k, q;7979+8080+ for (k = 0, q = 1; q < len; q++) {8181+ while (k > 0 && pattern[k] != pattern[q])8282+ k = prefix_tbl[k-1];8383+ if (pattern[k] == pattern[q])8484+ k++;8585+ prefix_tbl[q] = k;8686+ }8787+}8888+8989+static struct ts_config *kmp_init(const void *pattern, unsigned int len,9090+ int gfp_mask)9191+{9292+ struct ts_config *conf;9393+ struct ts_kmp *kmp;9494+ unsigned int prefix_tbl_len = len * sizeof(unsigned int);9595+ size_t priv_size = sizeof(*kmp) + len + prefix_tbl_len;9696+9797+ conf = alloc_ts_config(priv_size, gfp_mask);9898+ if (IS_ERR(conf))9999+ return conf;100100+101101+ kmp = ts_config_priv(conf);102102+ kmp->pattern_len = len;103103+ compute_prefix_tbl(pattern, len, kmp->prefix_tbl);104104+ kmp->pattern = (u8 *) kmp->prefix_tbl + prefix_tbl_len;105105+ memcpy(kmp->pattern, pattern, len);106106+107107+ return conf;108108+}109109+110110+static void *kmp_get_pattern(struct ts_config *conf)111111+{112112+ struct ts_kmp *kmp = ts_config_priv(conf);113113+ return kmp->pattern;114114+}115115+116116+static unsigned int kmp_get_pattern_len(struct ts_config *conf)117117+{118118+ struct ts_kmp *kmp = ts_config_priv(conf);119119+ return kmp->pattern_len;120120+}121121+122122+static struct ts_ops kmp_ops = {123123+ .name = "kmp",124124+ .find = kmp_find,125125+ .init = kmp_init,126126+ .get_pattern = kmp_get_pattern,127127+ .get_pattern_len = kmp_get_pattern_len,128128+ .owner = THIS_MODULE,129129+ .list = LIST_HEAD_INIT(kmp_ops.list)130130+};131131+132132+static int __init init_kmp(void)133133+{134134+ return textsearch_register(&kmp_ops);135135+}136136+137137+static void __exit exit_kmp(void)138138+{139139+ textsearch_unregister(&kmp_ops);140140+}141141+142142+MODULE_LICENSE("GPL");143143+144144+module_init(init_kmp);145145+module_exit(exit_kmp);
+8-117
net/core/dev.c
···115115#endif /* CONFIG_NET_RADIO */116116#include <asm/current.h>117117118118-/* This define, if set, will randomly drop a packet when congestion119119- * is more than moderate. It helps fairness in the multi-interface120120- * case when one of them is a hog, but it kills performance for the121121- * single interface case so it is off now by default.122122- */123123-#undef RAND_LIE124124-125125-/* Setting this will sample the queue lengths and thus congestion126126- * via a timer instead of as each packet is received.127127- */128128-#undef OFFLINE_SAMPLE129129-130118/*131119 * The list of packet types we will receive (as opposed to discard)132120 * and the routines to invoke.···146158static DEFINE_SPINLOCK(ptype_lock);147159static struct list_head ptype_base[16]; /* 16 way hashed list */148160static struct list_head ptype_all; /* Taps */149149-150150-#ifdef OFFLINE_SAMPLE151151-static void sample_queue(unsigned long dummy);152152-static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);153153-#endif154161155162/*156163 * The @dev_base list is protected by @dev_base_lock and the rtln···198215 * Device drivers call our routines to queue packets here. We empty the199216 * queue in the local softnet handler.200217 */201201-DEFINE_PER_CPU(struct softnet_data, softnet_data) = { 0, };218218+DEFINE_PER_CPU(struct softnet_data, softnet_data) = { NULL };202219203220#ifdef CONFIG_SYSFS204221extern int netdev_sysfs_init(void);···13461363 Receiver routines13471364 =======================================================================*/1348136513491349-int netdev_max_backlog = 300;13661366+int netdev_max_backlog = 1000;13671367+int netdev_budget = 300;13501368int weight_p = 64; /* old backlog weight */13511351-/* These numbers are selected based on intuition and some13521352- * experimentatiom, if you have more scientific way of doing this13531353- * please go ahead and fix things.13541354- */13551355-int no_cong_thresh = 10;13561356-int no_cong = 20;13571357-int lo_cong = 100;13581358-int mod_cong = 290;1359136913601370DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };13611361-13621362-13631363-static void get_sample_stats(int cpu)13641364-{13651365-#ifdef RAND_LIE13661366- unsigned long rd;13671367- int rq;13681368-#endif13691369- struct softnet_data *sd = &per_cpu(softnet_data, cpu);13701370- int blog = sd->input_pkt_queue.qlen;13711371- int avg_blog = sd->avg_blog;13721372-13731373- avg_blog = (avg_blog >> 1) + (blog >> 1);13741374-13751375- if (avg_blog > mod_cong) {13761376- /* Above moderate congestion levels. */13771377- sd->cng_level = NET_RX_CN_HIGH;13781378-#ifdef RAND_LIE13791379- rd = net_random();13801380- rq = rd % netdev_max_backlog;13811381- if (rq < avg_blog) /* unlucky bastard */13821382- sd->cng_level = NET_RX_DROP;13831383-#endif13841384- } else if (avg_blog > lo_cong) {13851385- sd->cng_level = NET_RX_CN_MOD;13861386-#ifdef RAND_LIE13871387- rd = net_random();13881388- rq = rd % netdev_max_backlog;13891389- if (rq < avg_blog) /* unlucky bastard */13901390- sd->cng_level = NET_RX_CN_HIGH;13911391-#endif13921392- } else if (avg_blog > no_cong)13931393- sd->cng_level = NET_RX_CN_LOW;13941394- else /* no congestion */13951395- sd->cng_level = NET_RX_SUCCESS;13961396-13971397- sd->avg_blog = avg_blog;13981398-}13991399-14001400-#ifdef OFFLINE_SAMPLE14011401-static void sample_queue(unsigned long dummy)14021402-{14031403-/* 10 ms 0r 1ms -- i don't care -- JHS */14041404- int next_tick = 1;14051405- int cpu = smp_processor_id();14061406-14071407- get_sample_stats(cpu);14081408- next_tick += jiffies;14091409- mod_timer(&samp_timer, next_tick);14101410-}14111411-#endif141213711413137214141373/**···1373144813741449int netif_rx(struct sk_buff *skb)13751450{13761376- int this_cpu;13771451 struct softnet_data *queue;13781452 unsigned long flags;13791453···13881464 * short when CPU is congested, but is still operating.13891465 */13901466 local_irq_save(flags);13911391- this_cpu = smp_processor_id();13921467 queue = &__get_cpu_var(softnet_data);1393146813941469 __get_cpu_var(netdev_rx_stat).total++;13951470 if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {13961471 if (queue->input_pkt_queue.qlen) {13971397- if (queue->throttle)13981398- goto drop;13991399-14001472enqueue:14011473 dev_hold(skb->dev);14021474 __skb_queue_tail(&queue->input_pkt_queue, skb);14031403-#ifndef OFFLINE_SAMPLE14041404- get_sample_stats(this_cpu);14051405-#endif14061475 local_irq_restore(flags);14071407- return queue->cng_level;14761476+ return NET_RX_SUCCESS;14081477 }14091409-14101410- if (queue->throttle)14111411- queue->throttle = 0;1412147814131479 netif_rx_schedule(&queue->backlog_dev);14141480 goto enqueue;14151481 }1416148214171417- if (!queue->throttle) {14181418- queue->throttle = 1;14191419- __get_cpu_var(netdev_rx_stat).throttled++;14201420- }14211421-14221422-drop:14231483 __get_cpu_var(netdev_rx_stat).dropped++;14241484 local_irq_restore(flags);14251485···16881780 smp_mb__before_clear_bit();16891781 netif_poll_enable(backlog_dev);1690178216911691- if (queue->throttle)16921692- queue->throttle = 0;16931783 local_irq_enable();16941784 return 0;16951785}···16961790{16971791 struct softnet_data *queue = &__get_cpu_var(softnet_data);16981792 unsigned long start_time = jiffies;16991699- int budget = netdev_max_backlog;17001700-17931793+ int budget = netdev_budget;1701179417021795 local_irq_disable();17031796···19602055 struct netif_rx_stats *s = v;1961205619622057 seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",19631963- s->total, s->dropped, s->time_squeeze, s->throttled,19641964- s->fastroute_hit, s->fastroute_success, s->fastroute_defer,19651965- s->fastroute_deferred_out,19661966-#if 019671967- s->fastroute_latency_reduction19681968-#else19691969- s->cpu_collision19701970-#endif19711971- );20582058+ s->total, s->dropped, s->time_squeeze, 0,20592059+ 0, 0, 0, 0, /* was fastroute */20602060+ s->cpu_collision );19722061 return 0;19732062}19742063···3204330532053306 queue = &per_cpu(softnet_data, i);32063307 skb_queue_head_init(&queue->input_pkt_queue);32073207- queue->throttle = 0;32083208- queue->cng_level = 0;32093209- queue->avg_blog = 10; /* arbitrary non-zero */32103308 queue->completion_queue = NULL;32113309 INIT_LIST_HEAD(&queue->poll_list);32123310 set_bit(__LINK_STATE_START, &queue->backlog_dev.state);···32113315 queue->backlog_dev.poll = process_backlog;32123316 atomic_set(&queue->backlog_dev.refcnt, 1);32133317 }32143214-32153215-#ifdef OFFLINE_SAMPLE32163216- samp_timer.expires = jiffies + (10 * HZ);32173217- add_timer(&samp_timer);32183218-#endif3219331832203319 dev_boot_phase = 0;32213320
+157
net/core/skbuff.c
···15001500 skb_split_no_header(skb, skb1, len, pos);15011501}1502150215031503+/**15041504+ * skb_prepare_seq_read - Prepare a sequential read of skb data15051505+ * @skb: the buffer to read15061506+ * @from: lower offset of data to be read15071507+ * @to: upper offset of data to be read15081508+ * @st: state variable15091509+ *15101510+ * Initializes the specified state variable. Must be called before15111511+ * invoking skb_seq_read() for the first time.15121512+ */15131513+void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,15141514+ unsigned int to, struct skb_seq_state *st)15151515+{15161516+ st->lower_offset = from;15171517+ st->upper_offset = to;15181518+ st->root_skb = st->cur_skb = skb;15191519+ st->frag_idx = st->stepped_offset = 0;15201520+ st->frag_data = NULL;15211521+}15221522+15231523+/**15241524+ * skb_seq_read - Sequentially read skb data15251525+ * @consumed: number of bytes consumed by the caller so far15261526+ * @data: destination pointer for data to be returned15271527+ * @st: state variable15281528+ *15291529+ * Reads a block of skb data at &consumed relative to the15301530+ * lower offset specified to skb_prepare_seq_read(). Assigns15311531+ * the head of the data block to &data and returns the length15321532+ * of the block or 0 if the end of the skb data or the upper15331533+ * offset has been reached.15341534+ *15351535+ * The caller is not required to consume all of the data15361536+ * returned, i.e. &consumed is typically set to the number15371537+ * of bytes already consumed and the next call to15381538+ * skb_seq_read() will return the remaining part of the block.15391539+ *15401540+ * Note: The size of each block of data returned can be arbitary,15411541+ * this limitation is the cost for zerocopy seqeuental15421542+ * reads of potentially non linear data.15431543+ *15441544+ * Note: Fragment lists within fragments are not implemented15451545+ * at the moment, state->root_skb could be replaced with15461546+ * a stack for this purpose.15471547+ */15481548+unsigned int skb_seq_read(unsigned int consumed, const u8 **data,15491549+ struct skb_seq_state *st)15501550+{15511551+ unsigned int block_limit, abs_offset = consumed + st->lower_offset;15521552+ skb_frag_t *frag;15531553+15541554+ if (unlikely(abs_offset >= st->upper_offset))15551555+ return 0;15561556+15571557+next_skb:15581558+ block_limit = skb_headlen(st->cur_skb);15591559+15601560+ if (abs_offset < block_limit) {15611561+ *data = st->cur_skb->data + abs_offset;15621562+ return block_limit - abs_offset;15631563+ }15641564+15651565+ if (st->frag_idx == 0 && !st->frag_data)15661566+ st->stepped_offset += skb_headlen(st->cur_skb);15671567+15681568+ while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) {15691569+ frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx];15701570+ block_limit = frag->size + st->stepped_offset;15711571+15721572+ if (abs_offset < block_limit) {15731573+ if (!st->frag_data)15741574+ st->frag_data = kmap_skb_frag(frag);15751575+15761576+ *data = (u8 *) st->frag_data + frag->page_offset +15771577+ (abs_offset - st->stepped_offset);15781578+15791579+ return block_limit - abs_offset;15801580+ }15811581+15821582+ if (st->frag_data) {15831583+ kunmap_skb_frag(st->frag_data);15841584+ st->frag_data = NULL;15851585+ }15861586+15871587+ st->frag_idx++;15881588+ st->stepped_offset += frag->size;15891589+ }15901590+15911591+ if (st->cur_skb->next) {15921592+ st->cur_skb = st->cur_skb->next;15931593+ st->frag_idx = 0;15941594+ goto next_skb;15951595+ } else if (st->root_skb == st->cur_skb &&15961596+ skb_shinfo(st->root_skb)->frag_list) {15971597+ st->cur_skb = skb_shinfo(st->root_skb)->frag_list;15981598+ goto next_skb;15991599+ }16001600+16011601+ return 0;16021602+}16031603+16041604+/**16051605+ * skb_abort_seq_read - Abort a sequential read of skb data16061606+ * @st: state variable16071607+ *16081608+ * Must be called if skb_seq_read() was not called until it16091609+ * returned 0.16101610+ */16111611+void skb_abort_seq_read(struct skb_seq_state *st)16121612+{16131613+ if (st->frag_data)16141614+ kunmap_skb_frag(st->frag_data);16151615+}16161616+16171617+#define TS_SKB_CB(state) ((struct skb_seq_state *) &((state)->cb))16181618+16191619+static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text,16201620+ struct ts_config *conf,16211621+ struct ts_state *state)16221622+{16231623+ return skb_seq_read(offset, text, TS_SKB_CB(state));16241624+}16251625+16261626+static void skb_ts_finish(struct ts_config *conf, struct ts_state *state)16271627+{16281628+ skb_abort_seq_read(TS_SKB_CB(state));16291629+}16301630+16311631+/**16321632+ * skb_find_text - Find a text pattern in skb data16331633+ * @skb: the buffer to look in16341634+ * @from: search offset16351635+ * @to: search limit16361636+ * @config: textsearch configuration16371637+ * @state: uninitialized textsearch state variable16381638+ *16391639+ * Finds a pattern in the skb data according to the specified16401640+ * textsearch configuration. Use textsearch_next() to retrieve16411641+ * subsequent occurrences of the pattern. Returns the offset16421642+ * to the first occurrence or UINT_MAX if no match was found.16431643+ */16441644+unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,16451645+ unsigned int to, struct ts_config *config,16461646+ struct ts_state *state)16471647+{16481648+ config->get_next_block = skb_ts_get_next_block;16491649+ config->finish = skb_ts_finish;16501650+16511651+ skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state));16521652+16531653+ return textsearch_find(config, state);16541654+}16551655+15031656void __init skb_init(void)15041657{15051658 skbuff_head_cache = kmem_cache_create("skbuff_head_cache",···16911538EXPORT_SYMBOL(skb_unlink);16921539EXPORT_SYMBOL(skb_append);16931540EXPORT_SYMBOL(skb_split);15411541+EXPORT_SYMBOL(skb_prepare_seq_read);15421542+EXPORT_SYMBOL(skb_seq_read);15431543+EXPORT_SYMBOL(skb_abort_seq_read);15441544+EXPORT_SYMBOL(skb_find_text);
···449449 To compile this code as a module, choose M here: the450450 module will be called em_meta.451451452452+config NET_EMATCH_TEXT453453+ tristate "Textsearch"454454+ depends on NET_EMATCH455455+ select TEXTSEARCH456456+ ---help---457457+ Say Y here if you want to be ablt to classify packets based on458458+ textsearch comparisons. Please select the appropriate textsearch459459+ algorithms in the Library section.460460+461461+ To compile this code as a module, choose M here: the462462+ module will be called em_text.463463+452464config NET_CLS_ACT453465 bool "Packet ACTION"454466 depends on EXPERIMENTAL && NET_CLS && NET_QOS