From 4dfbb9d8c6cbfc32faa5c71145bd2a43e1f8237c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 11 Oct 2006 01:45:14 -0400 Subject: Lockdep: add lockdep_set_class_and_subclass() and lockdep_set_subclass() This annotation makes it possible to assign a subclass on lock init. This annotation is meant to reduce the _nested() annotations by assigning a default subclass. One could do without this annotation and rely on lockdep_set_class() exclusively, but that would require a manual stack of struct lock_class_key objects. Signed-off-by: Peter Zijlstra Signed-off-by: Dmitry Torokhov --- include/linux/lockdep.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 1314ca0f29be..14fec2a23b2e 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -202,7 +202,7 @@ extern int lockdep_internal(void); */ extern void lockdep_init_map(struct lockdep_map *lock, const char *name, - struct lock_class_key *key); + struct lock_class_key *key, int subclass); /* * Reinitialize a lock key - for cases where there is special locking or @@ -211,9 +211,14 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name, * or they are too narrow (they suffer from a false class-split): */ #define lockdep_set_class(lock, key) \ - lockdep_init_map(&(lock)->dep_map, #key, key) + lockdep_init_map(&(lock)->dep_map, #key, key, 0) #define lockdep_set_class_and_name(lock, key, name) \ - lockdep_init_map(&(lock)->dep_map, name, key) + lockdep_init_map(&(lock)->dep_map, name, key, 0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + lockdep_init_map(&(lock)->dep_map, #key, key, sub) +#define lockdep_set_subclass(lock, sub) \ + lockdep_init_map(&(lock)->dep_map, #lock, \ + (lock)->dep_map.key, sub) /* * Acquire a lock. @@ -257,10 +262,12 @@ static inline int lockdep_internal(void) # define lock_release(l, n, i) do { } while (0) # define lockdep_init() do { } while (0) # define lockdep_info() do { } while (0) -# define lockdep_init_map(lock, name, key) do { (void)(key); } while (0) +# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0) # define lockdep_set_class(lock, key) do { (void)(key); } while (0) # define lockdep_set_class_and_name(lock, key, name) \ do { (void)(key); } while (0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + do { (void)(key); } while (0) # define INIT_LOCKDEP # define lockdep_reset() do { debug_locks = 1; } while (0) # define lockdep_free_key_range(start, size) do { } while (0) -- cgit v1.2.3-71-gd317 From 88aa0103e408616e433c209e80169ab8d6eda99e Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 11 Oct 2006 01:45:31 -0400 Subject: Input: serio - add lockdep annotations Signed-off-by: Jiri Kosina Acked-by: Peter Zijlstra Signed-off-by: Dmitry Torokhov --- drivers/input/serio/libps2.c | 3 ++- drivers/input/serio/serio.c | 6 +++++- include/linux/serio.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index dcb16b5cbec0..e5b1b60757bb 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -189,7 +189,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) return -1; } - mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); + mutex_lock(&ps2dev->cmd_mutex); serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; @@ -296,6 +296,7 @@ EXPORT_SYMBOL(ps2_schedule_command); void ps2_init(struct ps2dev *ps2dev, struct serio *serio) { mutex_init(&ps2dev->cmd_mutex); + lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth); init_waitqueue_head(&ps2dev->wait); ps2dev->serio = serio; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 960fae3c3cea..480fdc5d20b3 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -538,8 +538,12 @@ static void serio_init_port(struct serio *serio) "serio%ld", (long)atomic_inc_return(&serio_no) - 1); serio->dev.bus = &serio_bus; serio->dev.release = serio_release_port; - if (serio->parent) + if (serio->parent) { serio->dev.parent = &serio->parent->dev; + serio->depth = serio->parent->depth + 1; + } else + serio->depth = 0; + lockdep_set_subclass(&serio->lock, serio->depth); } /* diff --git a/include/linux/serio.h b/include/linux/serio.h index 3a697cc6ecae..b99c5ca9708d 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -41,6 +41,7 @@ struct serio { void (*stop)(struct serio *); struct serio *parent, *child; + unsigned int depth; /* level of nesting in serio hierarchy */ struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ -- cgit v1.2.3-71-gd317 From 07646e217f473a3e6213f8228336a9046833d6aa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 Oct 2006 23:45:23 -0400 Subject: Lockdep: fix compile error in drivers/input/serio/serio.c lockdep_set_subclass() was missing in !LOCKDEP case Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- include/linux/lockdep.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 14fec2a23b2e..819f08f1310d 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -268,6 +268,8 @@ static inline int lockdep_internal(void) do { (void)(key); } while (0) #define lockdep_set_class_and_subclass(lock, key, sub) \ do { (void)(key); } while (0) +#define lockdep_set_subclass(lock, sub) do { } while (0) + # define INIT_LOCKDEP # define lockdep_reset() do { debug_locks = 1; } while (0) # define lockdep_free_key_range(start, size) do { } while (0) -- cgit v1.2.3-71-gd317 From aaa248f6c9c81b2683db7dbb0689cd5ed1c86d88 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Oct 2006 00:09:42 -0700 Subject: [PATCH] rename net_random to random32 Make net_random() more widely available by calling it random32 akpm: hopefully this will permit the removal of carta_random32. That needs confirmation from Stephane - this code looks somewhat more computationally expensive, and has a different (ie: callee-stateful) interface. [akpm@osdl.org: lots of build fixes, cleanups] Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Cc: Stephane Eranian Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/net.h | 7 +-- include/linux/random.h | 3 ++ lib/Makefile | 2 +- lib/random32.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ net/core/dev.c | 2 - net/core/utils.c | 116 ---------------------------------------- 6 files changed, 150 insertions(+), 122 deletions(-) create mode 100644 lib/random32.c (limited to 'include/linux') diff --git a/include/linux/net.h b/include/linux/net.h index c257f716e00f..15c733b816f0 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -19,6 +19,7 @@ #define _LINUX_NET_H #include +#include #include struct poll_table_struct; @@ -193,9 +194,9 @@ extern int sock_map_fd(struct socket *sock); extern struct socket *sockfd_lookup(int fd, int *err); #define sockfd_put(sock) fput(sock->file) extern int net_ratelimit(void); -extern unsigned long net_random(void); -extern void net_srandom(unsigned long); -extern void net_random_init(void); + +#define net_random() random32() +#define net_srandom(seed) srandom32(seed) extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t len); diff --git a/include/linux/random.h b/include/linux/random.h index 5d6456bcdeba..0248b30e306d 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -69,6 +69,9 @@ extern struct file_operations random_fops, urandom_fops; unsigned int get_random_int(void); unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len); +u32 random32(void); +void srandom32(u32 seed); + #endif /* __KERNEL___ */ #endif /* _LINUX_RANDOM_H */ diff --git a/lib/Makefile b/lib/Makefile index 59070dbfbeb4..4b8052f6a7b0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,7 +12,7 @@ lib-$(CONFIG_SMP) += cpumask.o lib-y += kobject.o kref.o kobject_uevent.o klist.o -obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o +obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o random32.o ifeq ($(CONFIG_DEBUG_KOBJECT),y) CFLAGS_kobject.o += -DDEBUG diff --git a/lib/random32.c b/lib/random32.c new file mode 100644 index 000000000000..4a15ce51cea7 --- /dev/null +++ b/lib/random32.c @@ -0,0 +1,142 @@ +/* + This is a maximally equidistributed combined Tausworthe generator + based on code from GNU Scientific Library 1.5 (30 Jun 2004) + + x_n = (s1_n ^ s2_n ^ s3_n) + + s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) + s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) + s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) + + The period of this generator is about 2^88. + + From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe + Generators", Mathematics of Computation, 65, 213 (1996), 203--213. + + This is available on the net from L'Ecuyer's home page, + + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps + ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps + + There is an erratum in the paper "Tables of Maximally + Equidistributed Combined LFSR Generators", Mathematics of + Computation, 68, 225 (1999), 261--269: + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps + + ... the k_j most significant bits of z_j must be non- + zero, for each j. (Note: this restriction also applies to the + computer code given in [4], but was mistakenly not mentioned in + that paper.) + + This affects the seeding procedure by imposing the requirement + s1 > 1, s2 > 7, s3 > 15. + +*/ + +#include +#include +#include +#include + +struct rnd_state { + u32 s1, s2, s3; +}; + +static DEFINE_PER_CPU(struct rnd_state, net_rand_state); + +static u32 __random32(struct rnd_state *state) +{ +#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) + + state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); + state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); + state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); + + return (state->s1 ^ state->s2 ^ state->s3); +} + +static void __set_random32(struct rnd_state *state, unsigned long s) +{ + if (s == 0) + s = 1; /* default seed is 1 */ + +#define LCG(n) (69069 * n) + state->s1 = LCG(s); + state->s2 = LCG(state->s1); + state->s3 = LCG(state->s2); + + /* "warm it up" */ + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); +} + +/** + * random32 - pseudo random number generator + * + * A 32 bit pseudo-random number is generated using a fast + * algorithm suitable for simulation. This algorithm is NOT + * considered safe for cryptographic use. + */ +u32 random32(void) +{ + unsigned long r; + struct rnd_state *state = &get_cpu_var(net_rand_state); + r = __random32(state); + put_cpu_var(state); + return r; +} +EXPORT_SYMBOL(random32); + +/** + * srandom32 - add entropy to pseudo random number generator + * @seed: seed value + * + * Add some additional seeding to the random32() pool. + * Note: this pool is per cpu so it only affects current CPU. + */ +void srandom32(u32 entropy) +{ + struct rnd_state *state = &get_cpu_var(net_rand_state); + __set_random32(state, state->s1 ^ entropy); + put_cpu_var(state); +} +EXPORT_SYMBOL(srandom32); + +/* + * Generate some initially weak seeding values to allow + * to start the random32() engine. + */ +static int __init random32_init(void) +{ + int i; + + for_each_possible_cpu(i) { + struct rnd_state *state = &per_cpu(net_rand_state,i); + __set_random32(state, i + jiffies); + } + return 0; +} +core_initcall(random32_init); + +/* + * Generate better values after random number generator + * is fully initalized. + */ +static int __init random32_reseed(void) +{ + int i; + unsigned long seed; + + for_each_possible_cpu(i) { + struct rnd_state *state = &per_cpu(net_rand_state,i); + + get_random_bytes(&seed, sizeof(seed)); + __set_random32(state, seed); + } + return 0; +} +late_initcall(random32_reseed); diff --git a/net/core/dev.c b/net/core/dev.c index 4d891beab138..81c426adcd1e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3502,8 +3502,6 @@ static int __init net_dev_init(void) BUG_ON(!dev_boot_phase); - net_random_init(); - if (dev_proc_init()) goto out; diff --git a/net/core/utils.c b/net/core/utils.c index 94c5d761c830..d93fe64f6693 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -30,119 +30,6 @@ #include #include -/* - This is a maximally equidistributed combined Tausworthe generator - based on code from GNU Scientific Library 1.5 (30 Jun 2004) - - x_n = (s1_n ^ s2_n ^ s3_n) - - s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) - s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) - s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) - - The period of this generator is about 2^88. - - From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe - Generators", Mathematics of Computation, 65, 213 (1996), 203--213. - - This is available on the net from L'Ecuyer's home page, - - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps - ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps - - There is an erratum in the paper "Tables of Maximally - Equidistributed Combined LFSR Generators", Mathematics of - Computation, 68, 225 (1999), 261--269: - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps - - ... the k_j most significant bits of z_j must be non- - zero, for each j. (Note: this restriction also applies to the - computer code given in [4], but was mistakenly not mentioned in - that paper.) - - This affects the seeding procedure by imposing the requirement - s1 > 1, s2 > 7, s3 > 15. - -*/ -struct nrnd_state { - u32 s1, s2, s3; -}; - -static DEFINE_PER_CPU(struct nrnd_state, net_rand_state); - -static u32 __net_random(struct nrnd_state *state) -{ -#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) - - state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); - state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); - state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); - - return (state->s1 ^ state->s2 ^ state->s3); -} - -static void __net_srandom(struct nrnd_state *state, unsigned long s) -{ - if (s == 0) - s = 1; /* default seed is 1 */ - -#define LCG(n) (69069 * n) - state->s1 = LCG(s); - state->s2 = LCG(state->s1); - state->s3 = LCG(state->s2); - - /* "warm it up" */ - __net_random(state); - __net_random(state); - __net_random(state); - __net_random(state); - __net_random(state); - __net_random(state); -} - - -unsigned long net_random(void) -{ - unsigned long r; - struct nrnd_state *state = &get_cpu_var(net_rand_state); - r = __net_random(state); - put_cpu_var(state); - return r; -} - - -void net_srandom(unsigned long entropy) -{ - struct nrnd_state *state = &get_cpu_var(net_rand_state); - __net_srandom(state, state->s1^entropy); - put_cpu_var(state); -} - -void __init net_random_init(void) -{ - int i; - - for_each_possible_cpu(i) { - struct nrnd_state *state = &per_cpu(net_rand_state,i); - __net_srandom(state, i+jiffies); - } -} - -static int net_random_reseed(void) -{ - int i; - unsigned long seed; - - for_each_possible_cpu(i) { - struct nrnd_state *state = &per_cpu(net_rand_state,i); - - get_random_bytes(&seed, sizeof(seed)); - __net_srandom(state, seed); - } - return 0; -} -late_initcall(net_random_reseed); - int net_msg_cost = 5*HZ; int net_msg_burst = 10; @@ -153,10 +40,7 @@ int net_ratelimit(void) { return __printk_ratelimit(net_msg_cost, net_msg_burst); } - -EXPORT_SYMBOL(net_random); EXPORT_SYMBOL(net_ratelimit); -EXPORT_SYMBOL(net_srandom); /* * Convert an ASCII string to binary IP. -- cgit v1.2.3-71-gd317 From a460e745e8f9c75a0525ff94154a0629f9d3e05d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 17 Oct 2006 00:10:03 -0700 Subject: [PATCH] genirq: clean up irq-flow-type naming Introduce desc->name and eliminate the handle_irq_name() hack. Add set_irq_chip_and_handler_name() to set the flow type and name at once. Signed-off-by: Ingo Molnar Acked-by: Thomas Gleixner Cc: "Eric W. Biederman" Cc: Matthew Wilcox Cc: Kyle McMartin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/i8259.c | 7 ++++--- arch/i386/kernel/io_apic.c | 17 ++++++++++------- arch/i386/kernel/irq.c | 2 +- arch/x86_64/kernel/i8259.c | 7 ++++--- arch/x86_64/kernel/io_apic.c | 15 ++++++++------- arch/x86_64/kernel/irq.c | 2 +- include/linux/irq.h | 22 ++++++++++------------ kernel/irq/chip.c | 33 +++++++++------------------------ 8 files changed, 47 insertions(+), 58 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d53eafb6daa7..62996cd17084 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -113,7 +113,8 @@ void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); io_apic_irqs &= ~(1<name); - seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); + seq_printf(p, "-%-8s", irq_desc[i].name); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 0612a33bb896..c4ef801b765b 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -178,7 +178,8 @@ void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); io_apic_irqs &= ~(1<name); - seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); + seq_printf(p, "-%-8s", irq_desc[i].name); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) diff --git a/include/linux/irq.h b/include/linux/irq.h index c64f3cc7e870..775f5a7da493 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -141,6 +141,7 @@ struct irq_chip { * @pending_mask: pending rebalanced interrupts * @dir: /proc/irq/ procfs entry * @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP + * @name: flow handler name for /proc/interrupts output * * Pad this out to 32 bytes for cache and indexing reasons. */ @@ -165,8 +166,9 @@ struct irq_desc { cpumask_t pending_mask; #endif #ifdef CONFIG_PROC_FS - struct proc_dir_entry *dir; + struct proc_dir_entry *dir; #endif + const char *name; } ____cacheline_aligned; extern struct irq_desc irq_desc[NR_IRQS]; @@ -271,12 +273,6 @@ extern void fastcall handle_simple_irq(unsigned int irq, struct irq_desc *desc); extern void fastcall handle_percpu_irq(unsigned int irq, struct irq_desc *desc); extern void fastcall handle_bad_irq(unsigned int irq, struct irq_desc *desc); -/* - * Get a descriptive string for the highlevel handler, for - * /proc/interrupts output: - */ -extern const char *handle_irq_name(irq_flow_handler_t handle); - /* * Monolithic do_IRQ implementation. * (is an explicit fastcall, because i386 4KSTACKS calls it from assembly) @@ -326,10 +322,12 @@ extern struct irq_chip no_irq_chip; extern struct irq_chip dummy_irq_chip; extern void -set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, - irq_flow_handler_t handle); +set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, + irq_flow_handler_t handle, const char *name); + extern void -__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained); +__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, + const char *name); /* * Set a highlevel flow handler for a given IRQ: @@ -337,7 +335,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained); static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle) { - __set_irq_handler(irq, handle, 0); + __set_irq_handler(irq, handle, 0, NULL); } /* @@ -349,7 +347,7 @@ static inline void set_irq_chained_handler(unsigned int irq, irq_flow_handler_t handle) { - __set_irq_handler(irq, handle, 1); + __set_irq_handler(irq, handle, 1, NULL); } /* Handle dynamic irq creation and destruction */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 11c99697acfe..2d0dc3efe813 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -499,7 +499,8 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc) #endif /* CONFIG_SMP */ void -__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained) +__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, + const char *name) { struct irq_desc *desc; unsigned long flags; @@ -540,6 +541,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained) desc->depth = 1; } desc->handle_irq = handle; + desc->name = name; if (handle != handle_bad_irq && is_chained) { desc->status &= ~IRQ_DISABLED; @@ -555,30 +557,13 @@ set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle) { set_irq_chip(irq, chip); - __set_irq_handler(irq, handle, 0); + __set_irq_handler(irq, handle, 0, NULL); } -/* - * Get a descriptive string for the highlevel handler, for - * /proc/interrupts output: - */ -const char * -handle_irq_name(irq_flow_handler_t handle) +void +set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, + irq_flow_handler_t handle, const char *name) { - if (handle == handle_level_irq) - return "level "; - if (handle == handle_fasteoi_irq) - return "fasteoi"; - if (handle == handle_edge_irq) - return "edge "; - if (handle == handle_simple_irq) - return "simple "; -#ifdef CONFIG_SMP - if (handle == handle_percpu_irq) - return "percpu "; -#endif - if (handle == handle_bad_irq) - return "bad "; - - return NULL; + set_irq_chip(irq, chip); + __set_irq_handler(irq, handle, 0, name); } -- cgit v1.2.3-71-gd317 From 7762f5a0b709b415fda132258ad37b9f2a1db994 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 17 Oct 2006 00:10:07 -0700 Subject: [PATCH] document i_size_write locking rules Unless someone reads the documentation for write_seqcount_{begin,end} it is not obvious, that i_size_write() needs locking. Especially, that lack of such locking can result in a system hang. Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 34406ed467c3..661c7c572149 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -656,7 +656,11 @@ static inline loff_t i_size_read(struct inode *inode) #endif } - +/* + * NOTE: unlike i_size_read(), i_size_write() does need locking around it + * (normally i_mutex), otherwise on 32bit/SMP an update of i_size_seqcount + * can be lost, resulting in subsequent i_size_read() calls spinning forever. + */ static inline void i_size_write(struct inode *inode, loff_t i_size) { #if BITS_PER_LONG==32 && defined(CONFIG_SMP) -- cgit v1.2.3-71-gd317 From d343fce148a4eee24a907a05c4101d3268045aae Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 17 Oct 2006 00:10:18 -0700 Subject: [PATCH] knfsd: Allow lockd to drop replies as appropriate It is possible for the ->fopen callback from lockd into nfsd to find that an answer cannot be given straight away (an upcall is needed) and so the request has to be 'dropped', to be retried later. That error status is not currently propagated back. So: Change nlm_fopen to return nlm error codes (rather than a private protocol) and define a new nlm_drop_reply code. Cause nlm_drop_reply to cause the rpc request to get rpc_drop_reply when this error comes back. Cause svc_process to drop a request which returns a status of rpc_drop_reply. [akpm@osdl.org: fix warning storm] Cc: Marc Eshel Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc4proc.c | 12 ++++++------ fs/lockd/svcproc.c | 16 +++++++++------- fs/lockd/svcsubs.c | 6 ------ fs/nfsd/lockd.c | 14 ++++++++------ include/linux/lockd/bind.h | 5 +++++ include/linux/lockd/xdr.h | 4 ++++ include/linux/sunrpc/msg_prot.h | 4 +++- include/linux/sunrpc/xdr.h | 1 + net/sunrpc/svc.c | 5 +++++ 9 files changed, 41 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index fa370f6eb07b..399ad11b97be 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -96,7 +96,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now check for conflicting locks */ resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock); @@ -126,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; #if 0 /* If supplied state doesn't match current state, we assume it's @@ -169,7 +169,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Try to cancel request. */ resp->status = nlmsvc_cancel_blocked(file, &argp->lock); @@ -202,7 +202,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to remove the lock */ resp->status = nlmsvc_unlock(file, &argp->lock); @@ -339,7 +339,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to create the share */ resp->status = nlmsvc_share_file(host, file, argp); @@ -372,7 +372,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to lock the file */ resp->status = nlmsvc_unshare_file(host, file, argp); diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 75b2c81bcb93..6a931f4ab75c 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -59,7 +59,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm_lock *lock = &argp->lock; - u32 error; + u32 error = 0; /* nfsd callbacks must have been installed for this procedure */ if (!nlmsvc_ops) @@ -88,6 +88,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, no_locks: if (host) nlm_release_host(host); + if (error) + return error; return nlm_lck_denied_nolocks; } @@ -122,7 +124,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now check for conflicting locks */ resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock)); @@ -153,7 +155,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; #if 0 /* If supplied state doesn't match current state, we assume it's @@ -196,7 +198,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Try to cancel request. */ resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); @@ -229,7 +231,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to remove the lock */ resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); @@ -368,7 +370,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to create the share */ resp->status = cast_status(nlmsvc_share_file(host, file, argp)); @@ -401,7 +403,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain client and file */ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return rpc_success; + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; /* Now try to unshare the file */ resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index c5f9113cdc70..7dac96e6c82c 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -135,12 +135,6 @@ out_unlock: out_free: kfree(file); -#ifdef CONFIG_LOCKD_V4 - if (nfserr == 1) - nfserr = nlm4_stale_fh; - else -#endif - nfserr = nlm_lck_denied; goto out_unlock; } diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 7b889ff15ae6..9b9e7e127c03 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -39,18 +39,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) fh_put(&fh); rqstp->rq_client = NULL; exp_readunlock(); - /* nlm and nfsd don't share error codes. - * we invent: 0 = no error - * 1 = stale file handle - * 2 = other error + /* We return nlm error codes as nlm doesn't know + * about nfsd, but nfsd does know about nlm.. */ switch (nfserr) { case nfs_ok: return 0; + case nfserr_dropit: + return nlm_drop_reply; +#ifdef CONFIG_LOCKD_V4 case nfserr_stale: - return 1; + return nlm4_stale_fh; +#endif default: - return 2; + return nlm_lck_denied; } } diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index 81e3a185f951..aa50d89eacd7 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h @@ -10,6 +10,11 @@ #define LINUX_LOCKD_BIND_H #include +/* need xdr-encoded error codes too, so... */ +#include +#ifdef CONFIG_LOCKD_V4 +#include +#endif /* Dummy declarations */ struct svc_rqst; diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h index bb0a0f1caa91..66fdae3b490c 100644 --- a/include/linux/lockd/xdr.h +++ b/include/linux/lockd/xdr.h @@ -13,6 +13,8 @@ #include #include +struct svc_rqst; + #define NLM_MAXCOOKIELEN 32 #define NLM_MAXSTRLEN 1024 @@ -22,6 +24,8 @@ #define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED) #define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD) +#define nlm_drop_reply __constant_htonl(30000) + /* Lock info passed via NLM */ struct nlm_lock { char * caller; diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index 1e65f2dd80e5..606cb2165232 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -56,7 +56,9 @@ enum rpc_accept_stat { RPC_PROG_MISMATCH = 2, RPC_PROC_UNAVAIL = 3, RPC_GARBAGE_ARGS = 4, - RPC_SYSTEM_ERR = 5 + RPC_SYSTEM_ERR = 5, + /* internal use only */ + RPC_DROP_REPLY = 60000, }; enum rpc_reject_stat { diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 953723b09bc6..ac69e5511606 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -74,6 +74,7 @@ struct xdr_buf { #define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL) #define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS) #define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR) +#define rpc_drop_reply __constant_htonl(RPC_DROP_REPLY) #define rpc_auth_ok __constant_htonl(RPC_AUTH_OK) #define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED) diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 2807fa0eab40..eb44ec929ca1 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -828,6 +828,11 @@ svc_process(struct svc_rqst *rqstp) *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); /* Encode reply */ + if (*statp == rpc_drop_reply) { + if (procp->pc_release) + procp->pc_release(rqstp, NULL, rqstp->rq_resp); + goto dropit; + } if (*statp == rpc_success && (xdr = procp->pc_encode) && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { dprintk("svc: failed to encode reply\n"); -- cgit v1.2.3-71-gd317 From 58ff407bee5a55f9c1188a3f9d70ffc79485183c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 17 Oct 2006 00:10:19 -0700 Subject: [PATCH] Fix IO error reporting on fsync() When IO error happens on metadata buffer, buffer is freed from memory and later fsync() is called, filesystems like ext2 fail to report EIO. We solve the problem by introducing a pointer to associated address space into the buffer_head. When a buffer is removed from a list of metadata buffers associated with an address space, IO error is transferred from the buffer to the address space, so that fsync can later report it. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 11 +++++++++-- include/linux/buffer_head.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index f65ef8821c73..35527dca1dbc 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -452,6 +452,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate) bdevname(bh->b_bdev, b)); } set_bit(AS_EIO, &page->mapping->flags); + set_buffer_write_io_error(bh); clear_buffer_uptodate(bh); SetPageError(page); } @@ -571,6 +572,10 @@ EXPORT_SYMBOL(mark_buffer_async_write); static inline void __remove_assoc_queue(struct buffer_head *bh) { list_del_init(&bh->b_assoc_buffers); + WARN_ON(!bh->b_assoc_map); + if (buffer_write_io_error(bh)) + set_bit(AS_EIO, &bh->b_assoc_map->flags); + bh->b_assoc_map = NULL; } int inode_has_buffers(struct inode *inode) @@ -669,6 +674,7 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) spin_lock(&buffer_mapping->private_lock); list_move_tail(&bh->b_assoc_buffers, &mapping->private_list); + bh->b_assoc_map = mapping; spin_unlock(&buffer_mapping->private_lock); } } @@ -765,7 +771,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) spin_lock(lock); while (!list_empty(list)) { bh = BH_ENTRY(list->next); - list_del_init(&bh->b_assoc_buffers); + __remove_assoc_queue(bh); if (buffer_dirty(bh) || buffer_locked(bh)) { list_add(&bh->b_assoc_buffers, &tmp); if (buffer_dirty(bh)) { @@ -786,7 +792,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) while (!list_empty(&tmp)) { bh = BH_ENTRY(tmp.prev); - __remove_assoc_queue(bh); + list_del_init(&bh->b_assoc_buffers); get_bh(bh); spin_unlock(lock); wait_on_buffer(bh); @@ -1167,6 +1173,7 @@ void __bforget(struct buffer_head *bh) spin_lock(&buffer_mapping->private_lock); list_del_init(&bh->b_assoc_buffers); + bh->b_assoc_map = NULL; spin_unlock(&buffer_mapping->private_lock); } __brelse(bh); diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 131ffd37e716..5d9fb0e94156 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -69,6 +69,8 @@ struct buffer_head { bh_end_io_t *b_end_io; /* I/O completion */ void *b_private; /* reserved for b_end_io */ struct list_head b_assoc_buffers; /* associated with another mapping */ + struct address_space *b_assoc_map; /* mapping this buffer is + associated with */ atomic_t b_count; /* users using this buffer_head */ }; -- cgit v1.2.3-71-gd317 From 74d919465a93b6c2b928b29a8ed3e5e41adbfa93 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Wed, 18 Oct 2006 08:55:54 -0400 Subject: [pci_ids] Add Quicknet XJ vendor/device ID's. Signed-off-by: Ben Collins --- include/linux/pci_ids.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f069df245469..f3a168f3c9df 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2351,3 +2351,5 @@ #define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 +#define PCI_VENDOR_ID_QUICKNET 0x15E2 +#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500 -- cgit v1.2.3-71-gd317 From 29f3eb64634cf96903a3cdb56b1f9a80bebad17d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 16 Oct 2006 16:20:21 -0700 Subject: pci: Additional search functions In order to finish converting to pci_get_* interfaces we need to add a couple of bits of missing functionaility pci_get_bus_and_slot() provides the equivalent to pci_find_slot() (pci_get_slot is already taken as a name for something similar but not the same) pci_get_device_reverse() is the equivalent of pci_find_device_reverse but refcounting Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/search.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-- include/linux/pci.h | 3 ++- 2 files changed, 72 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/search.c b/drivers/pci/search.c index d529462d1b53..2f13eba5d5ae 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -139,6 +139,31 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) return dev; } +/** + * pci_get_bus_and_slot - locate PCI device from a given PCI slot + * @bus: number of PCI bus on which desired PCI device resides + * @devfn: encodes number of PCI slot in which the desired PCI + * device resides and the logical device number within that slot + * in case of multi-function devices. + * + * Given a PCI bus and slot/function number, the desired PCI device + * is located in system global list of PCI devices. If the device + * is found, a pointer to its data structure is returned. If no + * device is found, %NULL is returned. The returned device has its + * reference count bumped by one. + */ + +struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) +{ + struct pci_dev *dev = NULL; + + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (dev->bus->number == bus && dev->devfn == devfn) + return dev; + } + return NULL; +} + /** * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids @@ -274,6 +299,45 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); } +/** + * pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices in the reverse order of + * pci_get_device. + * If a PCI device is found with a matching @vendor and @device, the reference + * count to the device is incremented and a pointer to its device structure + * is returned Otherwise, %NULL is returned. A new search is initiated by + * passing %NULL as the @from argument. Otherwise if @from is not %NULL, + * searches continue from next device on the global list. The reference + * count for @from is always decremented if it is not %NULL. + */ +struct pci_dev * +pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from) +{ + struct list_head *n; + struct pci_dev *dev; + + WARN_ON(in_interrupt()); + down_read(&pci_bus_sem); + n = from ? from->global_list.prev : pci_devices.prev; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device)) + goto exit; + n = n->prev; + } + dev = NULL; +exit: + dev = pci_dev_get(dev); + up_read(&pci_bus_sem); + pci_dev_put(from); + return dev; +} /** * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id @@ -382,12 +446,16 @@ exit: } EXPORT_SYMBOL(pci_dev_present); -EXPORT_SYMBOL(pci_find_bus); -EXPORT_SYMBOL(pci_find_next_bus); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); +/* For boot time work */ +EXPORT_SYMBOL(pci_find_bus); +EXPORT_SYMBOL(pci_find_next_bus); +/* For everyone */ EXPORT_SYMBOL(pci_get_device); +EXPORT_SYMBOL(pci_get_device_reverse); EXPORT_SYMBOL(pci_get_subsys); EXPORT_SYMBOL(pci_get_slot); +EXPORT_SYMBOL(pci_get_bus_and_slot); EXPORT_SYMBOL(pci_get_class); diff --git a/include/linux/pci.h b/include/linux/pci.h index 5c604f5fad67..09bf88fc80c5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -452,13 +452,14 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); int pci_find_ext_capability (struct pci_dev *dev, int cap); -struct pci_bus * pci_find_next_bus(const struct pci_bus *from); +struct pci_bus *pci_find_next_bus(const struct pci_bus *from); struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from); struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from); struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn); +struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn); struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from); int pci_dev_present(const struct pci_device_id *ids); -- cgit v1.2.3-71-gd317 From 6b4b78fed47e7380dfe9280b154e8b9bfcd4c86c Mon Sep 17 00:00:00 2001 From: Matt Domsch Date: Fri, 29 Sep 2006 15:23:23 -0500 Subject: PCI: optionally sort device lists breadth-first Problem: New Dell PowerEdge servers have 2 embedded ethernet ports, which are labeled NIC1 and NIC2 on the chassis, in the BIOS setup screens, and in the printed documentation. Assuming no other add-in ethernet ports in the system, Linux 2.4 kernels name these eth0 and eth1 respectively. Many people have come to expect this naming. Linux 2.6 kernels name these eth1 and eth0 respectively (backwards from expectations). I also have reports that various Sun and HP servers have similar behavior. Root cause: Linux 2.4 kernels walk the pci_devices list, which happens to be sorted in breadth-first order (or pcbios_find_device order on i386, which most often is breadth-first also). 2.6 kernels have both the pci_devices list and the pci_bus_type.klist_devices list, the latter is what is walked at driver load time to match the pci_id tables; this klist happens to be in depth-first order. On systems where, for physical routing reasons, NIC1 appears on a lower bus number than NIC2, but NIC2's bridge is discovered first in the depth-first ordering, NIC2 will be discovered before NIC1. If the list were sorted breadth-first, NIC1 would be discovered before NIC2. A PowerEdge 1955 system has the following topology which easily exhibits the difference between depth-first and breadth-first device lists. -[0000:00]-+-00.0 Intel Corporation 5000P Chipset Memory Controller Hub +-02.0-[0000:03-08]--+-00.0-[0000:04-07]--+-00.0-[0000:05-06]----00.0-[0000:06]----00.0 Broadcom Corporation NetXtreme II BCM5708S Gigabit Ethernet (labeled NIC2, 2.4 kernel name eth1, 2.6 kernel name eth0) +-1c.0-[0000:01-02]----00.0-[0000:02]----00.0 Broadcom Corporation NetXtreme II BCM5708S Gigabit Ethernet (labeled NIC1, 2.4 kernel name eth0, 2.6 kernel name eth1) Other factors, such as device driver load order and the presence of PCI slots at various points in the bus hierarchy further complicate this problem; I'm not trying to solve those here, just restore the device order, and thus basic behavior, that 2.4 kernels had. Solution: The solution can come in multiple steps. Suggested fix #1: kernel Patch below optionally sorts the two device lists into breadth-first ordering to maintain compatibility with 2.4 kernels. It adds two new command line options: pci=bfsort pci=nobfsort to force the sort order, or not, as you wish. It also adds DMI checks for the specific Dell systems which exhibit "backwards" ordering, to make them "right". Suggested fix #2: udev rules from userland Many people also have the expectation that embedded NICs are always discovered before add-in NICs (which this patch does not try to do). Using the PCI IRQ Routing Table provided by system BIOS, it's easy to determine which PCI devices are embedded, or if add-in, which PCI slot they're in. I'm working on a tool that would allow udev to name ethernet devices in ascending embedded, slot 1 .. slot N order, subsort by PCI bus/dev/fn breadth-first. It'll be possible to use it independent of udev as well for those distributions that don't use udev in their installers. Suggested fix #3: system board routing rules One can constrain the system board layout to put NIC1 ahead of NIC2 regardless of breadth-first or depth-first discovery order. This adds a significant level of complexity to board routing, and may not be possible in all instances (witness the above systems from several major manufacturers). I don't want to encourage this particular train of thought too far, at the expense of not doing #1 or #2 above. Feedback appreciated. Patch tested on a Dell PowerEdge 1955 blade with 2.6.18. You'll also note I took some liberty and temporarily break the klist abstraction to simplify and speed up the sort algorithm. I think that's both safe and appropriate in this instance. Signed-off-by: Matt Domsch Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 5 ++ arch/i386/pci/common.c | 59 +++++++++++++++++++++++- arch/i386/pci/pci.h | 7 +++ drivers/pci/probe.c | 92 +++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 5 files changed, 162 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ff571f9298e0..dd00fd556a60 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1231,6 +1231,11 @@ and is between 256 and 4096 characters. It is defined in the file machine check when some devices' config space is read. But various workarounds are disabled and some IOMMU drivers will not work. + bfsort Sort PCI devices into breadth-first order. + This sorting is done to get a device + order compatible with older (<= 2.4) kernels. + nobfsort Don't sort PCI devices into breadth-first order. + pcmv= [HW,PCMCIA] BadgePAD 4 pd. [PARIDE] diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 68bce194e688..6d5ace845e44 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -20,6 +20,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | PCI_PROBE_MMCONF; +int pci_bf_sort; int pci_routeirq; int pcibios_last_bus = -1; unsigned long pirq_table_addr; @@ -117,6 +118,20 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b) pci_read_bridge_bases(b); } +/* + * Only use DMI information to set this if nothing was passed + * on the kernel command line (which was parsed earlier). + */ + +static int __devinit set_bf_sort(struct dmi_system_id *d) +{ + if (pci_bf_sort == pci_bf_sort_default) { + pci_bf_sort = pci_dmi_bf; + printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); + } + return 0; +} + /* * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) */ @@ -130,11 +145,11 @@ static int __devinit assign_all_busses(struct dmi_system_id *d) } #endif +static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { +#ifdef __i386__ /* * Laptops which need pci=assign-busses to see Cardbus cards */ -static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { -#ifdef __i386__ { .callback = assign_all_busses, .ident = "Samsung X20 Laptop", @@ -144,6 +159,38 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { }, }, #endif /* __i386__ */ + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 1950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 1955", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 2900", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 2950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), + }, + }, {} }; @@ -189,6 +236,8 @@ static int __init pcibios_init(void) pcibios_resource_survey(); + if (pci_bf_sort >= pci_force_bf) + pci_sort_breadthfirst(); #ifdef CONFIG_PCI_BIOS if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) pcibios_sort(); @@ -203,6 +252,12 @@ char * __devinit pcibios_setup(char *str) if (!strcmp(str, "off")) { pci_probe = 0; return NULL; + } else if (!strcmp(str, "bfsort")) { + pci_bf_sort = pci_force_bf; + return NULL; + } else if (!strcmp(str, "nobfsort")) { + pci_bf_sort = pci_force_nobf; + return NULL; } #ifdef CONFIG_PCI_BIOS else if (!strcmp(str, "bios")) { diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index 1814f74569c6..ad065cebd7b9 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h @@ -30,6 +30,13 @@ extern unsigned int pci_probe; extern unsigned long pirq_table_addr; +enum pci_bf_sort_state { + pci_bf_sort_default, + pci_force_nobf, + pci_force_bf, + pci_dmi_bf, +}; + /* pci-i386.c */ extern unsigned int pcibios_max_latency; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3b0a5eb5054..e159d6604494 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1067,3 +1067,95 @@ EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL(pci_scan_single_device); EXPORT_SYMBOL_GPL(pci_scan_child_bus); #endif + +static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b) +{ + if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1; + else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1; + + if (a->bus->number < b->bus->number) return -1; + else if (a->bus->number > b->bus->number) return 1; + + if (a->devfn < b->devfn) return -1; + else if (a->devfn > b->devfn) return 1; + + return 0; +} + +/* + * Yes, this forcably breaks the klist abstraction temporarily. It + * just wants to sort the klist, not change reference counts and + * take/drop locks rapidly in the process. It does all this while + * holding the lock for the list, so objects can't otherwise be + * added/removed while we're swizzling. + */ +static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list) +{ + struct list_head *pos; + struct klist_node *n; + struct device *dev; + struct pci_dev *b; + + list_for_each(pos, list) { + n = container_of(pos, struct klist_node, n_node); + dev = container_of(n, struct device, knode_bus); + b = to_pci_dev(dev); + if (pci_sort_bf_cmp(a, b) <= 0) { + list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node); + return; + } + } + list_move_tail(&a->dev.knode_bus.n_node, list); +} + +static void __init pci_sort_breadthfirst_klist(void) +{ + LIST_HEAD(sorted_devices); + struct list_head *pos, *tmp; + struct klist_node *n; + struct device *dev; + struct pci_dev *pdev; + + spin_lock(&pci_bus_type.klist_devices.k_lock); + list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { + n = container_of(pos, struct klist_node, n_node); + dev = container_of(n, struct device, knode_bus); + pdev = to_pci_dev(dev); + pci_insertion_sort_klist(pdev, &sorted_devices); + } + list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); + spin_unlock(&pci_bus_type.klist_devices.k_lock); +} + +static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) +{ + struct pci_dev *b; + + list_for_each_entry(b, list, global_list) { + if (pci_sort_bf_cmp(a, b) <= 0) { + list_move_tail(&a->global_list, &b->global_list); + return; + } + } + list_move_tail(&a->global_list, list); +} + +static void __init pci_sort_breadthfirst_devices(void) +{ + LIST_HEAD(sorted_devices); + struct pci_dev *dev, *tmp; + + down_write(&pci_bus_sem); + list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) { + pci_insertion_sort_devices(dev, &sorted_devices); + } + list_splice(&sorted_devices, &pci_devices); + up_write(&pci_bus_sem); +} + +void __init pci_sort_breadthfirst(void) +{ + pci_sort_breadthfirst_devices(); + pci_sort_breadthfirst_klist(); +} + diff --git a/include/linux/pci.h b/include/linux/pci.h index 09bf88fc80c5..4689e2a699c0 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -443,6 +443,7 @@ extern void pci_remove_bus(struct pci_bus *b); extern void pci_remove_bus_device(struct pci_dev *dev); extern void pci_stop_bus_device(struct pci_dev *dev); void pci_setup_cardbus(struct pci_bus *bus); +extern void pci_sort_breadthfirst(void); /* Generic PCI functions exported to card drivers */ -- cgit v1.2.3-71-gd317 From 7a54f25cef6c763f16c9fd49ae382de162147873 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 13 Oct 2006 20:05:19 -0700 Subject: PCI Hotplug: move pci_hotplug.h to include/linux/ This makes it possible to build pci hotplug drivers outside of the main kernel tree, and Sam keeps telling me to move local header files to their proper places... Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpi_pcihp.c | 2 +- drivers/pci/hotplug/acpiphp.h | 2 +- drivers/pci/hotplug/acpiphp_core.c | 2 +- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/pci/hotplug/acpiphp_ibm.c | 1 - drivers/pci/hotplug/cpci_hotplug_core.c | 2 +- drivers/pci/hotplug/cpci_hotplug_pci.c | 2 +- drivers/pci/hotplug/cpqphp.h | 1 - drivers/pci/hotplug/cpqphp_core.c | 1 + drivers/pci/hotplug/cpqphp_ctrl.c | 1 + drivers/pci/hotplug/cpqphp_nvram.c | 1 + drivers/pci/hotplug/cpqphp_pci.c | 1 + drivers/pci/hotplug/cpqphp_sysfs.c | 1 + drivers/pci/hotplug/fakephp.c | 2 +- drivers/pci/hotplug/ibmphp.h | 2 +- drivers/pci/hotplug/pci_hotplug.h | 236 -------------------------------- drivers/pci/hotplug/pci_hotplug_core.c | 7 +- drivers/pci/hotplug/pciehp.h | 2 +- drivers/pci/hotplug/pcihp_skeleton.c | 2 +- drivers/pci/hotplug/rpadlpar_sysfs.c | 2 +- drivers/pci/hotplug/rpaphp_core.c | 2 +- drivers/pci/hotplug/sgi_hotplug.c | 2 +- drivers/pci/hotplug/shpchp.h | 3 +- include/linux/pci_hotplug.h | 236 ++++++++++++++++++++++++++++++++ 24 files changed, 258 insertions(+), 257 deletions(-) delete mode 100644 drivers/pci/hotplug/pci_hotplug.h create mode 100644 include/linux/pci_hotplug.h (limited to 'include/linux') diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 51cb9f817c22..270a33cc08f6 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -29,10 +29,10 @@ #include #include #include +#include #include #include #include -#include "pci_hotplug.h" #define MY_NAME "acpi_pcihp" diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7fff07e877c7..59c5b242d86d 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -38,7 +38,7 @@ #include #include /* for KOBJ_NAME_LEN */ #include -#include "pci_hotplug.h" +#include #define dbg(format, arg...) \ do { \ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index e2fef60c2d06..c57d9d5ce84e 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -37,10 +37,10 @@ #include #include +#include #include #include #include -#include "pci_hotplug.h" #include "acpiphp.h" #define MY_NAME "acpiphp" diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 83e8e4412de5..c44311ac2fd3 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -45,11 +45,11 @@ #include #include +#include #include #include #include "../pci.h" -#include "pci_hotplug.h" #include "acpiphp.h" static LIST_HEAD(bridge_list); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index d0a07d9ab30c..bd40aee10e16 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -35,7 +35,6 @@ #include #include "acpiphp.h" -#include "pci_hotplug.h" #define DRIVER_VERSION "1.0.1" #define DRIVER_AUTHOR "Irene Zubarev , Vernon Mauery " diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index d06ab4045134..684551559d44 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -29,12 +29,12 @@ #include #include #include +#include #include #include #include #include #include -#include "pci_hotplug.h" #include "cpci_hotplug.h" #define DRIVER_AUTHOR "Scott Murray " diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 4afcaffd031c..7b1beaad2752 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -26,9 +26,9 @@ #include #include #include +#include #include #include "../pci.h" -#include "pci_hotplug.h" #include "cpci_hotplug.h" #define MY_NAME "cpci_hotplug" diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index ea040c32f47d..298ad7f3f4f4 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -28,7 +28,6 @@ #ifndef _CPQPHP_H #define _CPQPHP_H -#include "pci_hotplug.h" #include #include /* for read? and write? functions */ #include /* for delays */ diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 1fc259913b68..5617cfdadc5c 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 3ec2ad7db49a..79ff6b4de3a6 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "cpqphp.h" static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index cf0878917537..298a6cfd8406 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include "cpqphp.h" diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 0d9688952f4a..fc7c74d72595 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 5bab666cd67e..634f74d919d3 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "cpqphp.h" diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index aaeb1129132e..e27907c91d92 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -35,10 +35,10 @@ #include #include #include +#include #include #include #include -#include "pci_hotplug.h" #include "../pci.h" #if !defined(MODULE) diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index dba6d8ca9bda..612d96301509 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -30,7 +30,7 @@ * */ -#include "pci_hotplug.h" +#include extern int ibmphp_debug; diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h deleted file mode 100644 index a675a05c4091..000000000000 --- a/drivers/pci/hotplug/pci_hotplug.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * PCI HotPlug Core Functions - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ -#ifndef _PCI_HOTPLUG_H -#define _PCI_HOTPLUG_H - - -/* These values come from the PCI Hotplug Spec */ -enum pci_bus_speed { - PCI_SPEED_33MHz = 0x00, - PCI_SPEED_66MHz = 0x01, - PCI_SPEED_66MHz_PCIX = 0x02, - PCI_SPEED_100MHz_PCIX = 0x03, - PCI_SPEED_133MHz_PCIX = 0x04, - PCI_SPEED_66MHz_PCIX_ECC = 0x05, - PCI_SPEED_100MHz_PCIX_ECC = 0x06, - PCI_SPEED_133MHz_PCIX_ECC = 0x07, - PCI_SPEED_66MHz_PCIX_266 = 0x09, - PCI_SPEED_100MHz_PCIX_266 = 0x0a, - PCI_SPEED_133MHz_PCIX_266 = 0x0b, - PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0x12, - PCI_SPEED_133MHz_PCIX_533 = 0x13, - PCI_SPEED_UNKNOWN = 0xff, -}; - -/* These values come from the PCI Express Spec */ -enum pcie_link_width { - PCIE_LNK_WIDTH_RESRV = 0x00, - PCIE_LNK_X1 = 0x01, - PCIE_LNK_X2 = 0x02, - PCIE_LNK_X4 = 0x04, - PCIE_LNK_X8 = 0x08, - PCIE_LNK_X12 = 0x0C, - PCIE_LNK_X16 = 0x10, - PCIE_LNK_X32 = 0x20, - PCIE_LNK_WIDTH_UNKNOWN = 0xFF, -}; - -enum pcie_link_speed { - PCIE_2PT5GB = 0x14, - PCIE_LNK_SPEED_UNKNOWN = 0xFF, -}; - -struct hotplug_slot; -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; -#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); - -/** - * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use - * @owner: The module owner of this structure - * @enable_slot: Called when the user wants to enable a specific pci slot - * @disable_slot: Called when the user wants to disable a specific pci slot - * @set_attention_status: Called to set the specific slot's attention LED to - * the specified value - * @hardware_test: Called to run a specified hardware test on the specified - * slot. - * @get_power_status: Called to get the current power status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_attention_status: Called to get the current attention status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_latch_status: Called to get the current latch status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_adapter_status: Called to get see if an adapter is present in the slot or not. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_address: Called to get pci address of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_max_bus_speed: Called to get the max bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_cur_bus_speed: Called to get the current bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * - * The table of function pointers that is passed to the hotplug pci core by a - * hotplug pci driver. These functions are called by the hotplug pci core when - * the user wants to do something to a specific slot (query it for information, - * set an LED, enable / disable power, etc.) - */ -struct hotplug_slot_ops { - struct module *owner; - int (*enable_slot) (struct hotplug_slot *slot); - int (*disable_slot) (struct hotplug_slot *slot); - int (*set_attention_status) (struct hotplug_slot *slot, u8 value); - int (*hardware_test) (struct hotplug_slot *slot, u32 value); - int (*get_power_status) (struct hotplug_slot *slot, u8 *value); - int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); - int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); - int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); - int (*get_address) (struct hotplug_slot *slot, u32 *value); - int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); - int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); -}; - -/** - * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot - * @power: if power is enabled or not (1/0) - * @attention_status: if the attention light is enabled or not (1/0) - * @latch_status: if the latch (if any) is open or closed (1/0) - * @adapter_present: if there is a pci board present in the slot or not (1/0) - * @address: (domain << 16 | bus << 8 | dev) - * - * Used to notify the hotplug pci core of the status of a specific slot. - */ -struct hotplug_slot_info { - u8 power_status; - u8 attention_status; - u8 latch_status; - u8 adapter_status; - u32 address; - enum pci_bus_speed max_bus_speed; - enum pci_bus_speed cur_bus_speed; -}; - -/** - * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. - * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the initial values for - * this slot. - * @release: called during pci_hp_deregister to free memory allocated in a - * hotplug_slot structure. - * @private: used by the hotplug pci controller driver to store whatever it - * needs. - */ -struct hotplug_slot { - char *name; - struct hotplug_slot_ops *ops; - struct hotplug_slot_info *info; - void (*release) (struct hotplug_slot *slot); - void *private; - - /* Variables below this are for use only by the hotplug pci core. */ - struct list_head slot_list; - struct kobject kobj; -}; -#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) - -extern int pci_hp_register (struct hotplug_slot *slot); -extern int pci_hp_deregister (struct hotplug_slot *slot); -extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, - struct hotplug_slot_info *info); -extern struct subsystem pci_hotplug_slots_subsys; - -/* PCI Setting Record (Type 0) */ -struct hpp_type0 { - u32 revision; - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; -}; - -/* PCI-X Setting Record (Type 1) */ -struct hpp_type1 { - u32 revision; - u8 max_mem_read; - u8 avg_max_split; - u16 tot_max_split; -}; - -/* PCI Express Setting Record (Type 2) */ -struct hpp_type2 { - u32 revision; - u32 unc_err_mask_and; - u32 unc_err_mask_or; - u32 unc_err_sever_and; - u32 unc_err_sever_or; - u32 cor_err_mask_and; - u32 cor_err_mask_or; - u32 adv_err_cap_and; - u32 adv_err_cap_or; - u16 pci_exp_devctl_and; - u16 pci_exp_devctl_or; - u16 pci_exp_lnkctl_and; - u16 pci_exp_lnkctl_or; - u32 sec_unc_err_sever_and; - u32 sec_unc_err_sever_or; - u32 sec_unc_err_mask_and; - u32 sec_unc_err_mask_or; -}; - -struct hotplug_params { - struct hpp_type0 *t0; /* Type0: NULL if not available */ - struct hpp_type1 *t1; /* Type1: NULL if not available */ - struct hpp_type2 *t2; /* Type2: NULL if not available */ - struct hpp_type0 type0_data; - struct hpp_type1 type1_data; - struct hpp_type2 type2_data; -}; - -#ifdef CONFIG_ACPI -#include -#include -#include -extern acpi_status acpi_run_oshp(acpi_handle handle); -extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, - struct hotplug_params *hpp); -int acpi_root_bridge(acpi_handle handle); -#endif -#endif - diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index fa666d0cc489..f5d632e72323 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,11 +39,8 @@ #include #include #include +#include #include -#include -#include -#include "pci_hotplug.h" - #define MY_NAME "pci_hotplug" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 30f021c55fe5..4fb12fcda563 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -31,11 +31,11 @@ #include #include +#include #include #include /* signal_pending() */ #include #include -#include "pci_hotplug.h" #define MY_NAME "pciehp" diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index 2b9e10e38613..50bcd3fe61da 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -33,8 +33,8 @@ #include #include #include +#include #include -#include "pci_hotplug.h" #define SLOT_NAME_SIZE 10 struct slot { diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index db69be85b458..6c5be3ff578c 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -14,7 +14,7 @@ */ #include #include -#include "pci_hotplug.h" +#include #include "rpadlpar.h" #define DLPAR_KOBJ_NAME "control" diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 7288a3eccfb3..141486df235b 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,6 @@ #include "../pci.h" /* for pci_add_new_bus */ /* and pci_do_scan_bus */ #include "rpaphp.h" -#include "pci_hotplug.h" int debug; static struct semaphore rpaphp_sem; diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index f31d83c2c633..b62ad31a9739 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include #include "../pci.h" -#include "pci_hotplug.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 7e7d490622e1..ea2087c34149 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -31,12 +31,11 @@ #include #include +#include #include #include /* signal_pending(), struct timer_list */ #include -#include "pci_hotplug.h" - #if !defined(MODULE) #define MY_NAME "shpchp" #else diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h new file mode 100644 index 000000000000..a675a05c4091 --- /dev/null +++ b/include/linux/pci_hotplug.h @@ -0,0 +1,236 @@ +/* + * PCI HotPlug Core Functions + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ +#ifndef _PCI_HOTPLUG_H +#define _PCI_HOTPLUG_H + + +/* These values come from the PCI Hotplug Spec */ +enum pci_bus_speed { + PCI_SPEED_33MHz = 0x00, + PCI_SPEED_66MHz = 0x01, + PCI_SPEED_66MHz_PCIX = 0x02, + PCI_SPEED_100MHz_PCIX = 0x03, + PCI_SPEED_133MHz_PCIX = 0x04, + PCI_SPEED_66MHz_PCIX_ECC = 0x05, + PCI_SPEED_100MHz_PCIX_ECC = 0x06, + PCI_SPEED_133MHz_PCIX_ECC = 0x07, + PCI_SPEED_66MHz_PCIX_266 = 0x09, + PCI_SPEED_100MHz_PCIX_266 = 0x0a, + PCI_SPEED_133MHz_PCIX_266 = 0x0b, + PCI_SPEED_66MHz_PCIX_533 = 0x11, + PCI_SPEED_100MHz_PCIX_533 = 0x12, + PCI_SPEED_133MHz_PCIX_533 = 0x13, + PCI_SPEED_UNKNOWN = 0xff, +}; + +/* These values come from the PCI Express Spec */ +enum pcie_link_width { + PCIE_LNK_WIDTH_RESRV = 0x00, + PCIE_LNK_X1 = 0x01, + PCIE_LNK_X2 = 0x02, + PCIE_LNK_X4 = 0x04, + PCIE_LNK_X8 = 0x08, + PCIE_LNK_X12 = 0x0C, + PCIE_LNK_X16 = 0x10, + PCIE_LNK_X32 = 0x20, + PCIE_LNK_WIDTH_UNKNOWN = 0xFF, +}; + +enum pcie_link_speed { + PCIE_2PT5GB = 0x14, + PCIE_LNK_SPEED_UNKNOWN = 0xFF, +}; + +struct hotplug_slot; +struct hotplug_slot_attribute { + struct attribute attr; + ssize_t (*show)(struct hotplug_slot *, char *); + ssize_t (*store)(struct hotplug_slot *, const char *, size_t); +}; +#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); + +/** + * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use + * @owner: The module owner of this structure + * @enable_slot: Called when the user wants to enable a specific pci slot + * @disable_slot: Called when the user wants to disable a specific pci slot + * @set_attention_status: Called to set the specific slot's attention LED to + * the specified value + * @hardware_test: Called to run a specified hardware test on the specified + * slot. + * @get_power_status: Called to get the current power status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_attention_status: Called to get the current attention status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_latch_status: Called to get the current latch status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_adapter_status: Called to get see if an adapter is present in the slot or not. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_address: Called to get pci address of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_max_bus_speed: Called to get the max bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_cur_bus_speed: Called to get the current bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * + * The table of function pointers that is passed to the hotplug pci core by a + * hotplug pci driver. These functions are called by the hotplug pci core when + * the user wants to do something to a specific slot (query it for information, + * set an LED, enable / disable power, etc.) + */ +struct hotplug_slot_ops { + struct module *owner; + int (*enable_slot) (struct hotplug_slot *slot); + int (*disable_slot) (struct hotplug_slot *slot); + int (*set_attention_status) (struct hotplug_slot *slot, u8 value); + int (*hardware_test) (struct hotplug_slot *slot, u32 value); + int (*get_power_status) (struct hotplug_slot *slot, u8 *value); + int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); + int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); + int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); + int (*get_address) (struct hotplug_slot *slot, u32 *value); + int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); + int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); +}; + +/** + * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot + * @power: if power is enabled or not (1/0) + * @attention_status: if the attention light is enabled or not (1/0) + * @latch_status: if the latch (if any) is open or closed (1/0) + * @adapter_present: if there is a pci board present in the slot or not (1/0) + * @address: (domain << 16 | bus << 8 | dev) + * + * Used to notify the hotplug pci core of the status of a specific slot. + */ +struct hotplug_slot_info { + u8 power_status; + u8 attention_status; + u8 latch_status; + u8 adapter_status; + u32 address; + enum pci_bus_speed max_bus_speed; + enum pci_bus_speed cur_bus_speed; +}; + +/** + * struct hotplug_slot - used to register a physical slot with the hotplug pci core + * @name: the name of the slot being registered. This string must + * be unique amoung slots registered on this system. + * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot + * @info: pointer to the &struct hotplug_slot_info for the initial values for + * this slot. + * @release: called during pci_hp_deregister to free memory allocated in a + * hotplug_slot structure. + * @private: used by the hotplug pci controller driver to store whatever it + * needs. + */ +struct hotplug_slot { + char *name; + struct hotplug_slot_ops *ops; + struct hotplug_slot_info *info; + void (*release) (struct hotplug_slot *slot); + void *private; + + /* Variables below this are for use only by the hotplug pci core. */ + struct list_head slot_list; + struct kobject kobj; +}; +#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) + +extern int pci_hp_register (struct hotplug_slot *slot); +extern int pci_hp_deregister (struct hotplug_slot *slot); +extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, + struct hotplug_slot_info *info); +extern struct subsystem pci_hotplug_slots_subsys; + +/* PCI Setting Record (Type 0) */ +struct hpp_type0 { + u32 revision; + u8 cache_line_size; + u8 latency_timer; + u8 enable_serr; + u8 enable_perr; +}; + +/* PCI-X Setting Record (Type 1) */ +struct hpp_type1 { + u32 revision; + u8 max_mem_read; + u8 avg_max_split; + u16 tot_max_split; +}; + +/* PCI Express Setting Record (Type 2) */ +struct hpp_type2 { + u32 revision; + u32 unc_err_mask_and; + u32 unc_err_mask_or; + u32 unc_err_sever_and; + u32 unc_err_sever_or; + u32 cor_err_mask_and; + u32 cor_err_mask_or; + u32 adv_err_cap_and; + u32 adv_err_cap_or; + u16 pci_exp_devctl_and; + u16 pci_exp_devctl_or; + u16 pci_exp_lnkctl_and; + u16 pci_exp_lnkctl_or; + u32 sec_unc_err_sever_and; + u32 sec_unc_err_sever_or; + u32 sec_unc_err_mask_and; + u32 sec_unc_err_mask_or; +}; + +struct hotplug_params { + struct hpp_type0 *t0; /* Type0: NULL if not available */ + struct hpp_type1 *t1; /* Type1: NULL if not available */ + struct hpp_type2 *t2; /* Type2: NULL if not available */ + struct hpp_type0 type0_data; + struct hpp_type1 type1_data; + struct hpp_type2 type2_data; +}; + +#ifdef CONFIG_ACPI +#include +#include +#include +extern acpi_status acpi_run_oshp(acpi_handle handle); +extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, + struct hotplug_params *hpp); +int acpi_root_bridge(acpi_handle handle); +#endif +#endif + -- cgit v1.2.3-71-gd317 From eb409460b1abec0e2a1f9c9d07019f4157a6d6bc Mon Sep 17 00:00:00 2001 From: Lijun Chen Date: Mon, 16 Oct 2006 21:59:42 -0700 Subject: [TIPC]: Added subscription cancellation capability This patch allows a TIPC application to cancel an existing topology service subscription by re-requesting the subscription with the TIPC_SUB_CANCEL filter bit set. (All other bits of the cancel request must match the original subscription request.) Signed-off-by: Allan Stephens Signed-off-by: Per Liden Signed-off-by: David S. Miller --- include/linux/tipc.h | 1 + net/tipc/subscr.c | 99 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tipc.h b/include/linux/tipc.h index 243a15f54002..bea469455a0c 100644 --- a/include/linux/tipc.h +++ b/include/linux/tipc.h @@ -129,6 +129,7 @@ static inline unsigned int tipc_node(__u32 addr) #define TIPC_SUB_PORTS 0x01 /* filter for port availability */ #define TIPC_SUB_SERVICE 0x02 /* filter for service availability */ +#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */ #if 0 /* The following filter options are not currently implemented */ #define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */ diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index c51600ba5f4a..7a918f12a5df 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -155,7 +155,7 @@ void tipc_subscr_report_overlap(struct subscription *sub, sub->seq.upper, found_lower, found_upper); if (!tipc_subscr_overlap(sub, found_lower, found_upper)) return; - if (!must && (sub->filter != TIPC_SUB_PORTS)) + if (!must && !(sub->filter & TIPC_SUB_PORTS)) return; subscr_send_event(sub, found_lower, found_upper, event, port_ref, node); } @@ -176,6 +176,13 @@ static void subscr_timeout(struct subscription *sub) if (subscriber == NULL) return; + /* Validate timeout (in case subscription is being cancelled) */ + + if (sub->timeout == TIPC_WAIT_FOREVER) { + tipc_ref_unlock(subscriber_ref); + return; + } + /* Unlink subscription from name table */ tipc_nametbl_unsubscribe(sub); @@ -198,6 +205,20 @@ static void subscr_timeout(struct subscription *sub) atomic_dec(&topsrv.subscription_count); } +/** + * subscr_del - delete a subscription within a subscription list + * + * Called with subscriber locked. + */ + +static void subscr_del(struct subscription *sub) +{ + tipc_nametbl_unsubscribe(sub); + list_del(&sub->subscription_list); + kfree(sub); + atomic_dec(&topsrv.subscription_count); +} + /** * subscr_terminate - terminate communication with a subscriber * @@ -227,12 +248,9 @@ static void subscr_terminate(struct subscriber *subscriber) k_cancel_timer(&sub->timer); k_term_timer(&sub->timer); } - tipc_nametbl_unsubscribe(sub); - list_del(&sub->subscription_list); - dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n", + dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n", sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber); - kfree(sub); - atomic_dec(&topsrv.subscription_count); + subscr_del(sub); } /* Sever connection to subscriber */ @@ -252,6 +270,49 @@ static void subscr_terminate(struct subscriber *subscriber) kfree(subscriber); } +/** + * subscr_cancel - handle subscription cancellation request + * + * Called with subscriber locked. Routine must temporarily release this lock + * to enable the subscription timeout routine to finish without deadlocking; + * the lock is then reclaimed to allow caller to release it upon return. + * + * Note that fields of 's' use subscriber's endianness! + */ + +static void subscr_cancel(struct tipc_subscr *s, + struct subscriber *subscriber) +{ + struct subscription *sub; + struct subscription *sub_temp; + int found = 0; + + /* Find first matching subscription, exit if not found */ + + list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, + subscription_list) { + if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) { + found = 1; + break; + } + } + if (!found) + return; + + /* Cancel subscription timer (if used), then delete subscription */ + + if (sub->timeout != TIPC_WAIT_FOREVER) { + sub->timeout = TIPC_WAIT_FOREVER; + spin_unlock_bh(subscriber->lock); + k_cancel_timer(&sub->timer); + k_term_timer(&sub->timer); + spin_lock_bh(subscriber->lock); + } + dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n", + sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber); + subscr_del(sub); +} + /** * subscr_subscribe - create subscription for subscriber * @@ -263,6 +324,21 @@ static void subscr_subscribe(struct tipc_subscr *s, { struct subscription *sub; + /* Determine/update subscriber's endianness */ + + if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE)) + subscriber->swap = 0; + else + subscriber->swap = 1; + + /* Detect & process a subscription cancellation request */ + + if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) { + s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap); + subscr_cancel(s, subscriber); + return; + } + /* Refuse subscription if global limit exceeded */ if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) { @@ -281,13 +357,6 @@ static void subscr_subscribe(struct tipc_subscr *s, return; } - /* Determine/update subscriber's endianness */ - - if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE)) - subscriber->swap = 0; - else - subscriber->swap = 1; - /* Initialize subscription object */ memset(sub, 0, sizeof(*sub)); @@ -296,8 +365,8 @@ static void subscr_subscribe(struct tipc_subscr *s, sub->seq.upper = htohl(s->seq.upper, subscriber->swap); sub->timeout = htohl(s->timeout, subscriber->swap); sub->filter = htohl(s->filter, subscriber->swap); - if ((((sub->filter != TIPC_SUB_PORTS) - && (sub->filter != TIPC_SUB_SERVICE))) + if ((!(sub->filter & TIPC_SUB_PORTS) + == !(sub->filter & TIPC_SUB_SERVICE)) || (sub->seq.lower > sub->seq.upper)) { warn("Subscription rejected, illegal request\n"); kfree(sub); -- cgit v1.2.3-71-gd317 From ae8064ac32d07f609114d73928cdef803be87134 Mon Sep 17 00:00:00 2001 From: John Heffner Date: Wed, 18 Oct 2006 20:36:48 -0700 Subject: [TCP]: Bound TSO defer time This patch limits the amount of time you will defer sending a TSO segment to less than two clock ticks, or the time between two acks, whichever is longer. On slow links, deferring causes significant bursts. See attached plots, which show RTT through a 1 Mbps link with a 100 ms RTT and ~100 ms queue for (a) non-TSO, (b) currnet TSO, and (c) patched TSO. This burstiness causes significant jitter, tends to overflow queues early (bad for short queues), and makes delay-based congestion control more difficult. Deferring by a couple clock ticks I believe will have a relatively small impact on performance. Signed-off-by: John Heffner Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 ++ net/ipv4/tcp_output.c | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0e058a2d1c6d..2d36f6db3706 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -342,6 +342,8 @@ struct tcp_sock { unsigned long last_synq_overflow; + __u32 tso_deferred; + /* Receiver side RTT estimation */ struct { __u32 rtt; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f22536e32cb1..ca406157724c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1096,10 +1096,14 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ u32 send_win, cong_win, limit, in_flight; if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) - return 0; + goto send_now; if (icsk->icsk_ca_state != TCP_CA_Open) - return 0; + goto send_now; + + /* Defer for less than two clock ticks. */ + if (!tp->tso_deferred && ((jiffies<<1)>>1) - (tp->tso_deferred>>1) > 1) + goto send_now; in_flight = tcp_packets_in_flight(tp); @@ -1115,7 +1119,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ /* If a full-sized TSO skb can be sent, do it. */ if (limit >= 65536) - return 0; + goto send_now; if (sysctl_tcp_tso_win_divisor) { u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache); @@ -1125,7 +1129,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ */ chunk /= sysctl_tcp_tso_win_divisor; if (limit >= chunk) - return 0; + goto send_now; } else { /* Different approach, try not to defer past a single * ACK. Receiver should ACK every other full sized @@ -1133,11 +1137,17 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ * then send now. */ if (limit > tcp_max_burst(tp) * tp->mss_cache) - return 0; + goto send_now; } /* Ok, it looks like it is advisable to defer. */ + tp->tso_deferred = 1 | (jiffies<<1); + return 1; + +send_now: + tp->tso_deferred = 0; + return 0; } /* Create a new MTU probe if we are ready. -- cgit v1.2.3-71-gd317 From 62752ee198dca9209b7dee504763e51b11e9e0ca Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 17 Oct 2006 10:31:38 +0200 Subject: [PATCH] Take i_mutex in splice_from_pipe() The splice_actor may be calling ->prepare_write() and ->commit_write(). We want i_mutex on the inode being written to before calling those so that we don't race i_size changes. The double locking behavior is done elsewhere in splice.c, and if we eventually want _nolock variants of generic_file_splice_write(), fs modules might have to replicate the nasty locking code. We introduce inode_double_lock() and inode_double_unlock() to consolidate the locking rules into one set of functions. Signed-off-by: Mark Fasheh Signed-off-by: Jens Axboe --- fs/inode.c | 36 ++++++++++++++++++++++++++++++++++++ fs/splice.c | 24 +++++++++++------------- include/linux/fs.h | 3 +++ 3 files changed, 50 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/fs/inode.c b/fs/inode.c index d9a21d122926..26cdb115ce67 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1306,6 +1306,42 @@ void wake_up_inode(struct inode *inode) wake_up_bit(&inode->i_state, __I_LOCK); } +/* + * We rarely want to lock two inodes that do not have a parent/child + * relationship (such as directory, child inode) simultaneously. The + * vast majority of file systems should be able to get along fine + * without this. Do not use these functions except as a last resort. + */ +void inode_double_lock(struct inode *inode1, struct inode *inode2) +{ + if (inode1 == NULL || inode2 == NULL || inode1 == inode2) { + if (inode1) + mutex_lock(&inode1->i_mutex); + else if (inode2) + mutex_lock(&inode2->i_mutex); + return; + } + + if (inode1 < inode2) { + mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD); + } else { + mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); + } +} +EXPORT_SYMBOL(inode_double_lock); + +void inode_double_unlock(struct inode *inode1, struct inode *inode2) +{ + if (inode1) + mutex_unlock(&inode1->i_mutex); + + if (inode2 && inode2 != inode1) + mutex_unlock(&inode2->i_mutex); +} +EXPORT_SYMBOL(inode_double_unlock); + static __initdata unsigned long ihash_entries; static int __init set_ihash_entries(char *str) { diff --git a/fs/splice.c b/fs/splice.c index a567010b62ac..c1072b6940c3 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -713,6 +713,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, { int ret, do_wakeup, err; struct splice_desc sd; + struct inode *inode = out->f_mapping->host; ret = 0; do_wakeup = 0; @@ -722,8 +723,13 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, sd.file = out; sd.pos = *ppos; - if (pipe->inode) - mutex_lock(&pipe->inode->i_mutex); + /* + * The actor worker might be calling ->prepare_write and + * ->commit_write. Most of the time, these expect i_mutex to + * be held. Since this may result in an ABBA deadlock with + * pipe->inode, we have to order lock acquiry here. + */ + inode_double_lock(inode, pipe->inode); for (;;) { if (pipe->nrbufs) { @@ -797,8 +803,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, pipe_wait(pipe); } - if (pipe->inode) - mutex_unlock(&pipe->inode->i_mutex); + inode_double_unlock(inode, pipe->inode); if (do_wakeup) { smp_mb(); @@ -1400,13 +1405,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, * grabbing by inode address. Otherwise two different processes * could deadlock (one doing tee from A -> B, the other from B -> A). */ - if (ipipe->inode < opipe->inode) { - mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT); - mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD); - } else { - mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT); - mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD); - } + inode_double_lock(ipipe->inode, opipe->inode); do { if (!opipe->readers) { @@ -1450,8 +1449,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, i++; } while (len); - mutex_unlock(&ipipe->inode->i_mutex); - mutex_unlock(&opipe->inode->i_mutex); + inode_double_unlock(ipipe->inode, opipe->inode); /* * If we put data in the output pipe, wakeup any potential readers. diff --git a/include/linux/fs.h b/include/linux/fs.h index 661c7c572149..853a02f23936 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -623,6 +623,9 @@ enum inode_i_mutex_lock_class I_MUTEX_QUOTA }; +extern void inode_double_lock(struct inode *inode1, struct inode *inode2); +extern void inode_double_unlock(struct inode *inode1, struct inode *inode2); + /* * NOTE: in a 32bit arch with a preemptable kernel and * an UP compile the i_size_read/write must be atomic -- cgit v1.2.3-71-gd317 From 6da61809822c22634a3de2dcb3c60283b836a88a Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 17 Oct 2006 18:43:07 +0200 Subject: [PATCH] Introduce generic_file_splice_write_nolock() This allows file systems to manage their own i_mutex locking while still re-using the generic_file_splice_write() logic. OCFS2 in particular wants this so that it can order cluster locks within i_mutex. Signed-off-by: Mark Fasheh Signed-off-by: Jens Axboe --- fs/splice.c | 80 ++++++++++++++++++++++++++++++++++++++++++++---------- include/linux/fs.h | 2 ++ 2 files changed, 68 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/fs/splice.c b/fs/splice.c index c1072b6940c3..68e20e65c6e1 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -707,13 +707,12 @@ out_ret: * key here is the 'actor' worker passed in that actually moves the data * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. */ -ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags, - splice_actor *actor) +static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, + struct file *out, loff_t *ppos, size_t len, + unsigned int flags, splice_actor *actor) { int ret, do_wakeup, err; struct splice_desc sd; - struct inode *inode = out->f_mapping->host; ret = 0; do_wakeup = 0; @@ -723,14 +722,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, sd.file = out; sd.pos = *ppos; - /* - * The actor worker might be calling ->prepare_write and - * ->commit_write. Most of the time, these expect i_mutex to - * be held. Since this may result in an ABBA deadlock with - * pipe->inode, we have to order lock acquiry here. - */ - inode_double_lock(inode, pipe->inode); - for (;;) { if (pipe->nrbufs) { struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; @@ -803,8 +794,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, pipe_wait(pipe); } - inode_double_unlock(inode, pipe->inode); - if (do_wakeup) { smp_mb(); if (waitqueue_active(&pipe->wait)) @@ -815,6 +804,69 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, return ret; } +ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags, + splice_actor *actor) +{ + ssize_t ret; + struct inode *inode = out->f_mapping->host; + + /* + * The actor worker might be calling ->prepare_write and + * ->commit_write. Most of the time, these expect i_mutex to + * be held. Since this may result in an ABBA deadlock with + * pipe->inode, we have to order lock acquiry here. + */ + inode_double_lock(inode, pipe->inode); + ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor); + inode_double_unlock(inode, pipe->inode); + + return ret; +} + +/** + * generic_file_splice_write_nolock - generic_file_splice_write without mutexes + * @pipe: pipe info + * @out: file to write to + * @len: number of bytes to splice + * @flags: splice modifier flags + * + * Will either move or copy pages (determined by @flags options) from + * the given pipe inode to the given file. The caller is responsible + * for acquiring i_mutex on both inodes. + * + */ +ssize_t +generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + struct address_space *mapping = out->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + int err; + + ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); + if (ret > 0) { + *ppos += ret; + + /* + * If file or inode is SYNC and we actually wrote some data, + * sync it. + */ + if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { + err = generic_osync_inode(inode, mapping, + OSYNC_METADATA|OSYNC_DATA); + + if (err) + ret = err; + } + } + + return ret; +} + +EXPORT_SYMBOL(generic_file_splice_write_nolock); + /** * generic_file_splice_write - splice data from a pipe to a file * @pipe: pipe info diff --git a/include/linux/fs.h b/include/linux/fs.h index 853a02f23936..d695ba2346a3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1758,6 +1758,8 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); extern ssize_t generic_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); +extern ssize_t generic_file_splice_write_nolock(struct pipe_inode_info *, + struct file *, loff_t *, size_t, unsigned int); extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, loff_t *, size_t len, unsigned int flags); extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, -- cgit v1.2.3-71-gd317 From 01de85e057328ecbef36e108673b1e81059d54c1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 17 Oct 2006 19:50:36 +0200 Subject: [PATCH] Add lockless helpers for remove_suid() Right now users have to grab i_mutex before calling remove_suid(), in the unlikely event that a call to ->setattr() may be needed. Split up the function in two parts: - One to check if we need to remove suid - One to actually remove it The first we can call lockless. Signed-off-by: Jens Axboe --- include/linux/fs.h | 2 ++ mm/filemap.c | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index d695ba2346a3..2fe6e3f900ba 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1712,6 +1712,8 @@ extern void __iget(struct inode * inode); extern void clear_inode(struct inode *); extern void destroy_inode(struct inode *); extern struct inode *new_inode(struct super_block *); +extern int __remove_suid(struct dentry *, int); +extern int should_remove_suid(struct dentry *); extern int remove_suid(struct dentry *); extern void remove_dquot_ref(struct super_block *, int, struct list_head *); diff --git a/mm/filemap.c b/mm/filemap.c index 3464b681f844..7c7addb9333c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1884,11 +1884,10 @@ repeat: * if suid or (sgid and xgrp) * remove privs */ -int remove_suid(struct dentry *dentry) +int should_remove_suid(struct dentry *dentry) { mode_t mode = dentry->d_inode->i_mode; int kill = 0; - int result = 0; /* suid always must be killed */ if (unlikely(mode & S_ISUID)) @@ -1901,13 +1900,28 @@ int remove_suid(struct dentry *dentry) if (unlikely((mode & S_ISGID) && (mode & S_IXGRP))) kill |= ATTR_KILL_SGID; - if (unlikely(kill && !capable(CAP_FSETID))) { - struct iattr newattrs; + if (unlikely(kill && !capable(CAP_FSETID))) + return kill; - newattrs.ia_valid = ATTR_FORCE | kill; - result = notify_change(dentry, &newattrs); - } - return result; + return 0; +} + +int __remove_suid(struct dentry *dentry, int kill) +{ + struct iattr newattrs; + + newattrs.ia_valid = ATTR_FORCE | kill; + return notify_change(dentry, &newattrs); +} + +int remove_suid(struct dentry *dentry) +{ + int kill = should_remove_suid(dentry); + + if (unlikely(kill)) + return __remove_suid(dentry, kill); + + return 0; } EXPORT_SYMBOL(remove_suid); -- cgit v1.2.3-71-gd317 From 79e2de4bc53d7ca2a8eedee49e4a92479b4b530e Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Thu, 19 Oct 2006 23:28:15 -0700 Subject: [PATCH] export clear_queue_congested and set_queue_congested Export the clear_queue_congested() and set_queue_congested() functions located in ll_rw_blk.c The functions are renamed to blk_clear_queue_congested() and blk_set_queue_congested(). (needed in the pktcdvd driver's bio write congestion control) Signed-off-by: Thomas Maier Cc: Peter Osterlund Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- block/ll_rw_blk.c | 20 ++++++++++---------- include/linux/blkdev.h | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index c847e17e5caa..132a858ce2c5 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -117,7 +117,7 @@ static void blk_queue_congestion_threshold(struct request_queue *q) * congested queues, and wake up anyone who was waiting for requests to be * put back. */ -static void clear_queue_congested(request_queue_t *q, int rw) +void blk_clear_queue_congested(request_queue_t *q, int rw) { enum bdi_state bit; wait_queue_head_t *wqh = &congestion_wqh[rw]; @@ -128,18 +128,20 @@ static void clear_queue_congested(request_queue_t *q, int rw) if (waitqueue_active(wqh)) wake_up(wqh); } +EXPORT_SYMBOL(blk_clear_queue_congested); /* * A queue has just entered congestion. Flag that in the queue's VM-visible * state flags and increment the global gounter of congested queues. */ -static void set_queue_congested(request_queue_t *q, int rw) +void blk_set_queue_congested(request_queue_t *q, int rw) { enum bdi_state bit; bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; set_bit(bit, &q->backing_dev_info.state); } +EXPORT_SYMBOL(blk_set_queue_congested); /** * blk_get_backing_dev_info - get the address of a queue's backing_dev_info @@ -159,7 +161,6 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev) ret = &q->backing_dev_info; return ret; } - EXPORT_SYMBOL(blk_get_backing_dev_info); void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) @@ -167,7 +168,6 @@ void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) q->activity_fn = fn; q->activity_data = data; } - EXPORT_SYMBOL(blk_queue_activity_fn); /** @@ -2067,7 +2067,7 @@ static void __freed_request(request_queue_t *q, int rw) struct request_list *rl = &q->rq; if (rl->count[rw] < queue_congestion_off_threshold(q)) - clear_queue_congested(q, rw); + blk_clear_queue_congested(q, rw); if (rl->count[rw] + 1 <= q->nr_requests) { if (waitqueue_active(&rl->wait[rw])) @@ -2137,7 +2137,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, } } } - set_queue_congested(q, rw); + blk_set_queue_congested(q, rw); } /* @@ -3765,14 +3765,14 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count) blk_queue_congestion_threshold(q); if (rl->count[READ] >= queue_congestion_on_threshold(q)) - set_queue_congested(q, READ); + blk_set_queue_congested(q, READ); else if (rl->count[READ] < queue_congestion_off_threshold(q)) - clear_queue_congested(q, READ); + blk_clear_queue_congested(q, READ); if (rl->count[WRITE] >= queue_congestion_on_threshold(q)) - set_queue_congested(q, WRITE); + blk_set_queue_congested(q, WRITE); else if (rl->count[WRITE] < queue_congestion_off_threshold(q)) - clear_queue_congested(q, WRITE); + blk_clear_queue_congested(q, WRITE); if (rl->count[READ] >= q->nr_requests) { blk_set_queue_full(q, READ); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d370d2cfe138..9575e3a5ff2a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -651,6 +651,8 @@ extern void blk_recount_segments(request_queue_t *, struct bio *); extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); extern int sg_scsi_ioctl(struct file *, struct request_queue *, struct gendisk *, struct scsi_ioctl_command __user *); +extern void blk_clear_queue_congested(request_queue_t *q, int rw); +extern void blk_set_queue_congested(request_queue_t *q, int rw); extern void blk_start_queue(request_queue_t *q); extern void blk_stop_queue(request_queue_t *q); extern void blk_sync_queue(struct request_queue *q); -- cgit v1.2.3-71-gd317 From 3fcfab16c5b86eaa3db3a9a31adba550c5b67141 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Oct 2006 23:28:16 -0700 Subject: [PATCH] separate bdi congestion functions from queue congestion functions Separate out the concept of "queue congestion" from "backing-dev congestion". Congestion is a backing-dev concept, not a queue concept. The blk_* congestion functions are retained, as wrappers around the core backing-dev congestion functions. This proper layering is needed so that NFS can cleanly use the congestion functions, and so that CONFIG_BLOCK=n actually links. Cc: "Thomas Maier" Cc: "Jens Axboe" Cc: Trond Myklebust Cc: David Howells Cc: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/lib/usercopy.c | 3 +- block/ll_rw_blk.c | 71 --------------------------------------------- drivers/md/dm-crypt.c | 3 +- fs/fat/file.c | 3 +- fs/nfs/write.c | 4 ++- fs/reiserfs/journal.c | 3 +- fs/xfs/linux-2.6/kmem.c | 5 ++-- fs/xfs/linux-2.6/xfs_buf.c | 3 +- include/linux/backing-dev.h | 7 +++++ include/linux/blkdev.h | 24 ++++++++++++--- include/linux/writeback.h | 1 - mm/Makefile | 3 +- mm/backing-dev.c | 69 +++++++++++++++++++++++++++++++++++++++++++ mm/page-writeback.c | 17 +++-------- mm/page_alloc.c | 5 ++-- mm/shmem.c | 3 +- mm/vmscan.c | 6 ++-- 17 files changed, 126 insertions(+), 104 deletions(-) create mode 100644 mm/backing-dev.c (limited to 'include/linux') diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 258df6b4d7d7..d22cfc9d656c 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -741,7 +742,7 @@ survive: if (retval == -ENOMEM && is_init(current)) { up_read(¤t->mm->mmap_sem); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto survive; } diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 132a858ce2c5..136066583c68 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -56,11 +56,6 @@ static kmem_cache_t *requestq_cachep; */ static kmem_cache_t *iocontext_cachep; -static wait_queue_head_t congestion_wqh[2] = { - __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]), - __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1]) - }; - /* * Controlling structure to kblockd */ @@ -112,37 +107,6 @@ static void blk_queue_congestion_threshold(struct request_queue *q) q->nr_congestion_off = nr; } -/* - * A queue has just exitted congestion. Note this in the global counter of - * congested queues, and wake up anyone who was waiting for requests to be - * put back. - */ -void blk_clear_queue_congested(request_queue_t *q, int rw) -{ - enum bdi_state bit; - wait_queue_head_t *wqh = &congestion_wqh[rw]; - - bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; - clear_bit(bit, &q->backing_dev_info.state); - smp_mb__after_clear_bit(); - if (waitqueue_active(wqh)) - wake_up(wqh); -} -EXPORT_SYMBOL(blk_clear_queue_congested); - -/* - * A queue has just entered congestion. Flag that in the queue's VM-visible - * state flags and increment the global gounter of congested queues. - */ -void blk_set_queue_congested(request_queue_t *q, int rw) -{ - enum bdi_state bit; - - bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; - set_bit(bit, &q->backing_dev_info.state); -} -EXPORT_SYMBOL(blk_set_queue_congested); - /** * blk_get_backing_dev_info - get the address of a queue's backing_dev_info * @bdev: device @@ -2755,41 +2719,6 @@ void blk_end_sync_rq(struct request *rq, int error) } EXPORT_SYMBOL(blk_end_sync_rq); -/** - * blk_congestion_wait - wait for a queue to become uncongested - * @rw: READ or WRITE - * @timeout: timeout in jiffies - * - * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion. - * If no queues are congested then just wait for the next request to be - * returned. - */ -long blk_congestion_wait(int rw, long timeout) -{ - long ret; - DEFINE_WAIT(wait); - wait_queue_head_t *wqh = &congestion_wqh[rw]; - - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - ret = io_schedule_timeout(timeout); - finish_wait(wqh, &wait); - return ret; -} - -EXPORT_SYMBOL(blk_congestion_wait); - -/** - * blk_congestion_end - wake up sleepers on a congestion queue - * @rw: READ or WRITE - */ -void blk_congestion_end(int rw) -{ - wait_queue_head_t *wqh = &congestion_wqh[rw]; - - if (waitqueue_active(wqh)) - wake_up(wqh); -} - /* * Has to be called with the request spinlock acquired */ diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 655d816760e5..a625576fdeeb 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -602,7 +603,7 @@ static void process_write(struct crypt_io *io) /* out of memory -> run queues */ if (remaining) - blk_congestion_wait(bio_data_dir(clone), HZ/100); + congestion_wait(bio_data_dir(clone), HZ/100); } } diff --git a/fs/fat/file.c b/fs/fat/file.c index f4b8f8b3fbdd..8337451e7897 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -13,6 +13,7 @@ #include #include #include +#include #include int fat_generic_ioctl(struct inode *inode, struct file *filp, @@ -118,7 +119,7 @@ static int fat_file_release(struct inode *inode, struct file *filp) if ((filp->f_mode & FMODE_WRITE) && MSDOS_SB(inode->i_sb)->options.flush) { fat_flush_inodes(inode->i_sb, inode, NULL); - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } return 0; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index f6675d2c386c..ca92ac36fe9d 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -57,6 +57,8 @@ #include #include #include +#include + #include #include @@ -395,7 +397,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) out: clear_bit(BDI_write_congested, &bdi->state); wake_up_all(&nfs_write_congestion); - writeback_congestion_end(); + congestion_end(WRITE); return err; } diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index ad8cbc49883a..85ce23268302 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -53,6 +53,7 @@ #include #include #include +#include /* gets a struct reiserfs_journal_list * from a list head */ #define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \ @@ -970,7 +971,7 @@ int reiserfs_async_progress_wait(struct super_block *s) DEFINE_WAIT(wait); struct reiserfs_journal *j = SB_JOURNAL(s); if (atomic_read(&j->j_async_throttle)) - blk_congestion_wait(WRITE, HZ / 10); + congestion_wait(WRITE, HZ / 10); return 0; } diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index d59737589815..004baf600611 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "time.h" #include "kmem.h" @@ -53,7 +54,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags) printk(KERN_ERR "XFS: possible memory allocation " "deadlock in %s (mode:0x%x)\n", __FUNCTION__, lflags); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); } while (1); } @@ -131,7 +132,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags) printk(KERN_ERR "XFS: possible memory allocation " "deadlock in %s (mode:0x%x)\n", __FUNCTION__, lflags); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); } while (1); } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 9bbadafdcb00..db5f5a3608ca 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "xfs_linux.h" STATIC kmem_zone_t *xfs_buf_zone; @@ -395,7 +396,7 @@ _xfs_buf_lookup_pages( XFS_STATS_INC(xb_page_retries); xfsbufd_wakeup(0, gfp_mask); - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto retry; } diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index f7a1390d67f5..7011d6255593 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -10,6 +10,8 @@ #include +struct page; + /* * Bits in backing_dev_info.state */ @@ -88,6 +90,11 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi) (1 << BDI_write_congested)); } +void clear_bdi_congested(struct backing_dev_info *bdi, int rw); +void set_bdi_congested(struct backing_dev_info *bdi, int rw); +long congestion_wait(int rw, long timeout); +void congestion_end(int rw); + #define bdi_cap_writeback_dirty(bdi) \ (!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK)) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 9575e3a5ff2a..7bfcde2d5578 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -651,8 +651,26 @@ extern void blk_recount_segments(request_queue_t *, struct bio *); extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); extern int sg_scsi_ioctl(struct file *, struct request_queue *, struct gendisk *, struct scsi_ioctl_command __user *); -extern void blk_clear_queue_congested(request_queue_t *q, int rw); -extern void blk_set_queue_congested(request_queue_t *q, int rw); + +/* + * A queue has just exitted congestion. Note this in the global counter of + * congested queues, and wake up anyone who was waiting for requests to be + * put back. + */ +static inline void blk_clear_queue_congested(request_queue_t *q, int rw) +{ + clear_bdi_congested(&q->backing_dev_info, rw); +} + +/* + * A queue has just entered congestion. Flag that in the queue's VM-visible + * state flags and increment the global gounter of congested queues. + */ +static inline void blk_set_queue_congested(request_queue_t *q, int rw) +{ + set_bdi_congested(&q->backing_dev_info, rw); +} + extern void blk_start_queue(request_queue_t *q); extern void blk_stop_queue(request_queue_t *q); extern void blk_sync_queue(struct request_queue *q); @@ -767,10 +785,8 @@ extern int blk_queue_init_tags(request_queue_t *, int, struct blk_queue_tag *); extern void blk_queue_free_tags(request_queue_t *); extern int blk_queue_resize_tags(request_queue_t *, int); extern void blk_queue_invalidate_tags(request_queue_t *); -extern long blk_congestion_wait(int rw, long timeout); extern struct blk_queue_tag *blk_init_tags(int); extern void blk_free_tags(struct blk_queue_tag *); -extern void blk_congestion_end(int rw); static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, int tag) diff --git a/include/linux/writeback.h b/include/linux/writeback.h index a341c8032866..fc35e6bdfb93 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -85,7 +85,6 @@ int wakeup_pdflush(long nr_pages); void laptop_io_completion(void); void laptop_sync_completion(void); void throttle_vm_writeout(void); -void writeback_congestion_end(void); /* These are exported to sysctl. */ extern int dirty_background_ratio; diff --git a/mm/Makefile b/mm/Makefile index 12b3a4eee88d..f3c077eb0b8e 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -10,7 +10,8 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ page_alloc.o page-writeback.o pdflush.o \ readahead.o swap.o truncate.o vmscan.o \ - prio_tree.o util.o mmzone.o vmstat.o $(mmu-y) + prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ + $(mmu-y) ifeq ($(CONFIG_MMU)$(CONFIG_BLOCK),yy) obj-y += bounce.o diff --git a/mm/backing-dev.c b/mm/backing-dev.c new file mode 100644 index 000000000000..f50a2811f9dc --- /dev/null +++ b/mm/backing-dev.c @@ -0,0 +1,69 @@ + +#include +#include +#include +#include +#include + +static wait_queue_head_t congestion_wqh[2] = { + __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]), + __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1]) + }; + + +void clear_bdi_congested(struct backing_dev_info *bdi, int rw) +{ + enum bdi_state bit; + wait_queue_head_t *wqh = &congestion_wqh[rw]; + + bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; + clear_bit(bit, &bdi->state); + smp_mb__after_clear_bit(); + if (waitqueue_active(wqh)) + wake_up(wqh); +} +EXPORT_SYMBOL(clear_bdi_congested); + +void set_bdi_congested(struct backing_dev_info *bdi, int rw) +{ + enum bdi_state bit; + + bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; + set_bit(bit, &bdi->state); +} +EXPORT_SYMBOL(set_bdi_congested); + +/** + * congestion_wait - wait for a backing_dev to become uncongested + * @rw: READ or WRITE + * @timeout: timeout in jiffies + * + * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit + * write congestion. If no backing_devs are congested then just wait for the + * next write to be completed. + */ +long congestion_wait(int rw, long timeout) +{ + long ret; + DEFINE_WAIT(wait); + wait_queue_head_t *wqh = &congestion_wqh[rw]; + + prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); + ret = io_schedule_timeout(timeout); + finish_wait(wqh, &wait); + return ret; +} +EXPORT_SYMBOL(congestion_wait); + +/** + * congestion_end - wake up sleepers on a congested backing_dev_info + * @rw: READ or WRITE + */ +void congestion_end(int rw) +{ + wait_queue_head_t *wqh = &congestion_wqh[rw]; + + if (waitqueue_active(wqh)) + wake_up(wqh); +} +EXPORT_SYMBOL(congestion_end); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index a0f339057449..8d9b19f239c3 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -222,7 +222,7 @@ static void balance_dirty_pages(struct address_space *mapping) if (pages_written >= write_chunk) break; /* We've done our duty */ } - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } if (nr_reclaimable + global_page_state(NR_WRITEBACK) @@ -314,7 +314,7 @@ void throttle_vm_writeout(void) if (global_page_state(NR_UNSTABLE_NFS) + global_page_state(NR_WRITEBACK) <= dirty_thresh) break; - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } } @@ -351,7 +351,7 @@ static void background_writeout(unsigned long _min_pages) min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) { /* Wrote less than expected */ - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); if (!wbc.encountered_congestion) break; } @@ -422,7 +422,7 @@ static void wb_kupdate(unsigned long arg) writeback_inodes(&wbc); if (wbc.nr_to_write > 0) { if (wbc.encountered_congestion) - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); else break; /* All the old data is written */ } @@ -955,15 +955,6 @@ int test_set_page_writeback(struct page *page) } EXPORT_SYMBOL(test_set_page_writeback); -/* - * Wakes up tasks that are being throttled due to writeback congestion - */ -void writeback_congestion_end(void) -{ - blk_congestion_end(WRITE); -} -EXPORT_SYMBOL(writeback_congestion_end); - /* * Return true if any of the pages in the mapping are marged with the * passed tag. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 40db96a655d0..afee38f04d84 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1050,7 +1051,7 @@ nofail_alloc: if (page) goto got_pg; if (gfp_mask & __GFP_NOFAIL) { - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto nofail_alloc; } } @@ -1113,7 +1114,7 @@ rebalance: do_retry = 1; } if (do_retry) { - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); goto rebalance; } diff --git a/mm/shmem.c b/mm/shmem.c index b378f66cf2f9..4959535fc14c 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -1131,7 +1132,7 @@ repeat: page_cache_release(swappage); if (error == -ENOMEM) { /* let kswapd refresh zone for GFP_ATOMICs */ - blk_congestion_wait(WRITE, HZ/50); + congestion_wait(WRITE, HZ/50); } goto repeat; } diff --git a/mm/vmscan.c b/mm/vmscan.c index af73c14f9d88..f05527bf792b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1059,7 +1059,7 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) /* Take a nap, wait for some writeback to complete */ if (sc.nr_scanned && priority < DEF_PRIORITY - 2) - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); } /* top priority shrink_caches still had more to do? don't OOM, then */ if (!sc.all_unreclaimable) @@ -1214,7 +1214,7 @@ scan: * another pass across the zones. */ if (total_scanned && priority < DEF_PRIORITY - 2) - blk_congestion_wait(WRITE, HZ/10); + congestion_wait(WRITE, HZ/10); /* * We do this so kswapd doesn't build up large priorities for @@ -1458,7 +1458,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages) goto out; if (sc.nr_scanned && prio < DEF_PRIORITY - 2) - blk_congestion_wait(WRITE, HZ / 10); + congestion_wait(WRITE, HZ / 10); } lru_pages = 0; -- cgit v1.2.3-71-gd317 From 34e856e6a522a8fc0feba7497f5b05aeaa13d473 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 Oct 2006 23:28:17 -0700 Subject: [PATCH] Make userspace proof contains the constants for personality(2) but also some defintions that are useless or even harmful in userspace such as the personality() macro. Signed-off-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/personality.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux') diff --git a/include/linux/personality.h b/include/linux/personality.h index 80d780e5a8f5..bf4cf2080e5c 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -1,6 +1,8 @@ #ifndef _LINUX_PERSONALITY_H #define _LINUX_PERSONALITY_H +#ifdef __KERNEL__ + /* * Handling of different ABIs (personalities). */ @@ -12,6 +14,8 @@ extern int register_exec_domain(struct exec_domain *); extern int unregister_exec_domain(struct exec_domain *); extern int __set_personality(unsigned long); +#endif /* __KERNEL__ */ + /* * Flags for bug emulation. * @@ -71,6 +75,7 @@ enum { PER_MASK = 0x00ff, }; +#ifdef __KERNEL__ /* * Description of an execution domain. @@ -111,4 +116,6 @@ struct exec_domain { #define set_personality(pers) \ ((current->personality == pers) ? 0 : __set_personality(pers)) +#endif /* __KERNEL__ */ + #endif /* _LINUX_PERSONALITY_H */ -- cgit v1.2.3-71-gd317 From 145fc655a1ceabda76cf2ad74f7cf96863c65b65 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 19 Oct 2006 23:28:28 -0700 Subject: [PATCH] genirq: clean up irq-flow-type naming, fix Re-add the set_irq_chip_and_handler() prototype, it's still widely used. Signed-off-by: Ingo Molnar Cc: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 775f5a7da493..52fc4052a0ae 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -321,6 +321,9 @@ extern int can_request_irq(unsigned int irq, unsigned long irqflags); extern struct irq_chip no_irq_chip; extern struct irq_chip dummy_irq_chip; +extern void +set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, + irq_flow_handler_t handle); extern void set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle, const char *name); -- cgit v1.2.3-71-gd317 From 8ac773b4f73afa6fd66695131103944b975d5d5c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 19 Oct 2006 23:28:32 -0700 Subject: [PATCH] OOM killer meets userspace headers Despite mm.h is not being exported header, it does contain one thing which is part of userspace ABI -- value disabling OOM killer for given process. So, a) create and export include/linux/oom.h b) move OOM_DISABLE define there. c) turn bounding values of /proc/$PID/oom_adj into defines and export them too. Note: mass __KERNEL__ removal will be done later. Signed-off-by: Alexey Dobriyan Cc: Nick Piggin Cc: David Woodhouse Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 4 +++- include/linux/Kbuild | 1 + include/linux/mm.h | 3 --- include/linux/oom.h | 10 ++++++++++ mm/oom_kill.c | 1 + 5 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 include/linux/oom.h (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index 26a8f8416b79..8df27401d292 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -72,6 +72,7 @@ #include #include #include +#include #include "internal.h" /* NOTE: @@ -689,7 +690,8 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, if (copy_from_user(buffer, buf, count)) return -EFAULT; oom_adjust = simple_strtol(buffer, &end, 0); - if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE) + if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && + oom_adjust != OOM_DISABLE) return -EINVAL; if (*end == '\n') end++; diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 5114ff18101d..a1155a2beb32 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -120,6 +120,7 @@ header-y += netrom.h header-y += nfs2.h header-y += nfs4_mount.h header-y += nfs_mount.h +header-y += oom.h header-y += param.h header-y += pci_ids.h header-y += pci_regs.h diff --git a/include/linux/mm.h b/include/linux/mm.h index 5a6068ff5556..d538de901965 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1115,9 +1115,6 @@ int in_gate_area_no_task(unsigned long addr); #define in_gate_area(task, addr) ({(void)task; in_gate_area_no_task(addr);}) #endif /* __HAVE_ARCH_GATE_AREA */ -/* /proc//oom_adj set to -17 protects from the oom-killer */ -#define OOM_DISABLE -17 - int drop_caches_sysctl_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask, diff --git a/include/linux/oom.h b/include/linux/oom.h new file mode 100644 index 000000000000..ad76463629a0 --- /dev/null +++ b/include/linux/oom.h @@ -0,0 +1,10 @@ +#ifndef __INCLUDE_LINUX_OOM_H +#define __INCLUDE_LINUX_OOM_H + +/* /proc//oom_adj set to -17 protects from the oom-killer */ +#define OOM_DISABLE (-17) +/* inclusive */ +#define OOM_ADJUST_MIN (-16) +#define OOM_ADJUST_MAX 15 + +#endif diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 20f41b082e16..2e3ce3a928b9 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -15,6 +15,7 @@ * kernel subsystems and hints as to where to find out what things do. */ +#include #include #include #include -- cgit v1.2.3-71-gd317 From cd9ae2b6a75bb1fa0d370929c2d7a7da1ed719d9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Oct 2006 23:28:40 -0700 Subject: [PATCH] NFS: Deal with failure of invalidate_inode_pages2() If invalidate_inode_pages2() fails, then it should in principle just be because the current process was signalled. In that case, we just want to ensure that the inode's page cache remains marked as invalid. Also add a helper to allow the O_DIRECT code to simply mark the page cache as invalid once it is finished writing, instead of calling invalidate_inode_pages2() itself. Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/dir.c | 6 ++++-- fs/nfs/direct.c | 13 ++----------- fs/nfs/inode.c | 28 +++++++++++++++++++++++----- include/linux/nfs_fs.h | 1 + 4 files changed, 30 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 481f8892a919..58d44057813e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -203,8 +203,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) * Note: assumes we have exclusive access to this mapping either * through inode->i_mutex or some other mechanism. */ - if (page->index == 0) - invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1); + if (page->index == 0 && invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1) < 0) { + /* Should never happen */ + nfs_zap_mapping(inode, inode->i_mapping); + } unlock_page(page); return 0; error: diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 1e873fcab947..bdfabf854a51 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -497,6 +497,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode if (dreq->commit_data != NULL) nfs_commit_free(dreq->commit_data); nfs_direct_free_writedata(dreq); + nfs_zap_mapping(inode, inode->i_mapping); nfs_direct_complete(dreq); } } @@ -517,6 +518,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode { nfs_end_data_update(inode); nfs_direct_free_writedata(dreq); + nfs_zap_mapping(inode, inode->i_mapping); nfs_direct_complete(dreq); } #endif @@ -830,17 +832,6 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos); - /* - * XXX: nfs_end_data_update() already ensures this file's - * cached data is subsequently invalidated. Do we really - * need to call invalidate_inode_pages2() again here? - * - * For aio writes, this invalidation will almost certainly - * occur before the writes complete. Kind of racey. - */ - if (mapping->nrpages) - invalidate_inode_pages2(mapping); - if (retval > 0) iocb->ki_pos = pos + retval; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bc9376ca86cd..9979ad1cf8eb 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -131,6 +131,15 @@ void nfs_zap_caches(struct inode *inode) spin_unlock(&inode->i_lock); } +void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) +{ + if (mapping->nrpages != 0) { + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; + spin_unlock(&inode->i_lock); + } +} + static void nfs_zap_acl_cache(struct inode *inode) { void (*clear_acl_cache)(struct inode *); @@ -671,13 +680,20 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (ret < 0) + goto out; if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { - nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); - if (S_ISREG(inode->i_mode)) - nfs_sync_mapping(mapping); - invalidate_inode_pages2(mapping); - + if (mapping->nrpages != 0) { + if (S_ISREG(inode->i_mode)) { + ret = nfs_sync_mapping(mapping); + if (ret < 0) + goto out; + } + ret = invalidate_inode_pages2(mapping); + if (ret < 0) + goto out; + } spin_lock(&inode->i_lock); nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; if (S_ISDIR(inode->i_mode)) { @@ -687,10 +703,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) } spin_unlock(&inode->i_lock); + nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); } +out: return ret; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 76ff54846ada..6b2de1be5815 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -290,6 +290,7 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long * linux/fs/nfs/inode.c */ extern int nfs_sync_mapping(struct address_space *mapping); +extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping); extern void nfs_zap_caches(struct inode *); extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); -- cgit v1.2.3-71-gd317 From 7111c66e4e70588c9602035a4996c9cdc2087d2d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:45 -0700 Subject: [PATCH] fix svc_procfunc declaration svc_procfunc instances return __be32, not int Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc4proc.c | 40 ++++++++++++++++++++-------------------- fs/lockd/svcproc.c | 40 ++++++++++++++++++++-------------------- fs/nfs/callback_xdr.c | 4 ++-- fs/nfsd/nfs2acl.c | 10 +++++----- fs/nfsd/nfs3acl.c | 6 +++--- fs/nfsd/nfs3proc.c | 44 ++++++++++++++++++++++---------------------- fs/nfsd/nfs4proc.c | 4 ++-- fs/nfsd/nfsproc.c | 32 ++++++++++++++++---------------- include/linux/sunrpc/svc.h | 2 +- 9 files changed, 91 insertions(+), 91 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 399ad11b97be..4e719860b4bf 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -68,7 +68,7 @@ no_locks: /* * NULL: Test for presence of service */ -static int +static __be32 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { dprintk("lockd: NULL called\n"); @@ -78,7 +78,7 @@ nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * TEST: Check for conflicting lock */ -static int +static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -107,7 +107,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -150,7 +150,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -183,7 +183,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNLOCK: release a lock */ -static int +static __be32 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -217,7 +217,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, * GRANTED: A server calls us to tell that a process' lock request * was granted */ -static int +static __be32 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -253,12 +253,12 @@ static const struct rpc_call_ops nlm4svc_callback_ops = { * because we send the callback before the reply proper. I hope this * doesn't break any clients. */ -static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, - int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) +static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, + __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) { struct nlm_host *host; struct nlm_rqst *call; - int stat; + __be32 stat; host = nlmsvc_lookup_host(rqstp, argp->lock.caller, @@ -282,35 +282,35 @@ static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *a return rpc_success; } -static int nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: TEST_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test); } -static int nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: LOCK_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock); } -static int nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: CANCEL_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel); } -static int nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: UNLOCK_MSG called\n"); return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock); } -static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: GRANTED_MSG called\n"); @@ -320,7 +320,7 @@ static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *arg /* * SHARE: create a DOS share or alter existing share. */ -static int +static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -353,7 +353,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNSHARE: Release a DOS share. */ -static int +static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -386,7 +386,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* * NM_LOCK: Create an unmonitored lock */ -static int +static __be32 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -399,7 +399,7 @@ nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* * FREE_ALL: Release all locks and shares held by client */ -static int +static __be32 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -417,7 +417,7 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, /* * SM_NOTIFY: private callback from statd (not part of official NLM proto) */ -static int +static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { @@ -446,7 +446,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, /* * client sent a GRANTED_RES, let's remove the associated block */ -static int +static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, void *resp) { diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 6a931f4ab75c..db8d85c32d29 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -96,7 +96,7 @@ no_locks: /* * NULL: Test for presence of service */ -static int +static __be32 nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { dprintk("lockd: NULL called\n"); @@ -106,7 +106,7 @@ nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * TEST: Check for conflicting lock */ -static int +static __be32 nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -136,7 +136,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -179,7 +179,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, return rpc_success; } -static int +static __be32 nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -212,7 +212,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNLOCK: release a lock */ -static int +static __be32 nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -246,7 +246,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, * GRANTED: A server calls us to tell that a process' lock request * was granted */ -static int +static __be32 nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -282,12 +282,12 @@ static const struct rpc_call_ops nlmsvc_callback_ops = { * because we send the callback before the reply proper. I hope this * doesn't break any clients. */ -static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, - int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) +static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp, + __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *)) { struct nlm_host *host; struct nlm_rqst *call; - int stat; + __be32 stat; host = nlmsvc_lookup_host(rqstp, argp->lock.caller, @@ -311,28 +311,28 @@ static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *ar return rpc_success; } -static int nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: TEST_MSG called\n"); return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, argp, nlmsvc_proc_test); } -static int nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: LOCK_MSG called\n"); return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlmsvc_proc_lock); } -static int nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, +static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { dprintk("lockd: CANCEL_MSG called\n"); return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlmsvc_proc_cancel); } -static int +static __be32 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -340,7 +340,7 @@ nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlmsvc_proc_unlock); } -static int +static __be32 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -351,7 +351,7 @@ nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, /* * SHARE: create a DOS share or alter existing share. */ -static int +static __be32 nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -384,7 +384,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, /* * UNSHARE: Release a DOS share. */ -static int +static __be32 nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -417,7 +417,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, /* * NM_LOCK: Create an unmonitored lock */ -static int +static __be32 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_res *resp) { @@ -430,7 +430,7 @@ nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, /* * FREE_ALL: Release all locks and shares held by client */ -static int +static __be32 nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, void *resp) { @@ -448,7 +448,7 @@ nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, /* * SM_NOTIFY: private callback from statd (not part of official NLM proto) */ -static int +static __be32 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { @@ -477,7 +477,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, /* * client sent a GRANTED_RES, let's remove the associated block */ -static int +static __be32 nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, void *resp) { diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 29f932192054..5998d0c71757 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -36,7 +36,7 @@ struct callback_op { static struct callback_op callback_ops[]; -static int nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp) +static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp) { return htonl(NFS4_OK); } @@ -399,7 +399,7 @@ static unsigned process_op(struct svc_rqst *rqstp, /* * Decode, process and encode a COMPOUND */ -static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp) +static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp) { struct cb_compound_hdr_arg hdr_arg; struct cb_compound_hdr_res hdr_res; diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 9187755661df..8d48616882c1 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -21,7 +21,7 @@ /* * NULL call. */ -static int +static __be32 nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -30,7 +30,7 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * Get the Access and/or Default ACL of a file. */ -static int nfsacld_proc_getacl(struct svc_rqst * rqstp, +static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { svc_fh *fh; @@ -97,7 +97,7 @@ fail: /* * Set the Access and/or Default ACL of a file. */ -static int nfsacld_proc_setacl(struct svc_rqst * rqstp, +static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd_attrstat *resp) { @@ -128,7 +128,7 @@ static int nfsacld_proc_setacl(struct svc_rqst * rqstp, /* * Check file attributes */ -static int nfsacld_proc_getattr(struct svc_rqst * rqstp, +static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) { dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); @@ -140,7 +140,7 @@ static int nfsacld_proc_getattr(struct svc_rqst * rqstp, /* * Check file access */ -static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, +static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { int nfserr; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index d4bdc00c1169..ed6e2c27b5e8 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -19,7 +19,7 @@ /* * NULL call. */ -static int +static __be32 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -28,7 +28,7 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * Get the Access and/or Default ACL of a file. */ -static int nfsd3_proc_getacl(struct svc_rqst * rqstp, +static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { svc_fh *fh; @@ -93,7 +93,7 @@ fail: /* * Set the Access and/or Default ACL of a file. */ -static int nfsd3_proc_setacl(struct svc_rqst * rqstp, +static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp, struct nfsd3_attrstat *resp) { diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index a5ebc7dbb384..a12663fdfe16 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -43,7 +43,7 @@ static int nfs3_ftypes[] = { /* * NULL call. */ -static int +static __be32 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -52,7 +52,7 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) /* * Get a file's attributes */ -static int +static __be32 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, struct nfsd3_attrstat *resp) { @@ -76,7 +76,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, /* * Set a file's attributes */ -static int +static __be32 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, struct nfsd3_attrstat *resp) { @@ -94,7 +94,7 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, /* * Look up a path name component */ -static int +static __be32 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_diropres *resp) { @@ -118,7 +118,7 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, /* * Check file access */ -static int +static __be32 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { @@ -137,7 +137,7 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, /* * Read a symlink. */ -static int +static __be32 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp, struct nfsd3_readlinkres *resp) { @@ -155,7 +155,7 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp, /* * Read a portion of a file. */ -static int +static __be32 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, struct nfsd3_readres *resp) { @@ -195,7 +195,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, /* * Write data to a file */ -static int +static __be32 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, struct nfsd3_writeres *resp) { @@ -223,7 +223,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, * At least in theory; we'll see how it fares in practice when the * first reports about SunOS compatibility problems start to pour in... */ -static int +static __be32 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, struct nfsd3_diropres *resp) { @@ -265,7 +265,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, /* * Make directory. This operation is not idempotent. */ -static int +static __be32 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, struct nfsd3_diropres *resp) { @@ -285,7 +285,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, RETURN_STATUS(nfserr); } -static int +static __be32 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, struct nfsd3_diropres *resp) { @@ -307,7 +307,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, /* * Make socket/fifo/device. */ -static int +static __be32 nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, struct nfsd3_diropres *resp) { @@ -343,7 +343,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, /* * Remove file/fifo/socket etc. */ -static int +static __be32 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_attrstat *resp) { @@ -363,7 +363,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, /* * Remove a directory */ -static int +static __be32 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, struct nfsd3_attrstat *resp) { @@ -379,7 +379,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, RETURN_STATUS(nfserr); } -static int +static __be32 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, struct nfsd3_renameres *resp) { @@ -401,7 +401,7 @@ nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, RETURN_STATUS(nfserr); } -static int +static __be32 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, struct nfsd3_linkres *resp) { @@ -424,7 +424,7 @@ nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, /* * Read a portion of a directory. */ -static int +static __be32 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, struct nfsd3_readdirres *resp) { @@ -459,7 +459,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, * Read a portion of a directory, including file handles and attrs. * For now, we choose to ignore the dircount parameter. */ -static int +static __be32 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, struct nfsd3_readdirres *resp) { @@ -517,7 +517,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, /* * Get file system stats */ -static int +static __be32 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_fsstatres *resp) { @@ -534,7 +534,7 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, /* * Get file system info */ -static int +static __be32 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_fsinfores *resp) { @@ -576,7 +576,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, /* * Get pathconf info for the specified file */ -static int +static __be32 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd3_pathconfres *resp) { @@ -619,7 +619,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, /* * Commit a file (range) to stable storage. */ -static int +static __be32 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, struct nfsd3_commitres *resp) { diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index d1fac6872c44..795ad6c5cb2c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -715,7 +715,7 @@ out_kfree: /* * NULL call. */ -static int +static __be32 nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -731,7 +731,7 @@ static inline void nfsd4_increment_op_stats(u32 opnum) /* * COMPOUND call. */ -static int +static __be32 nfsd4_proc_compound(struct svc_rqst *rqstp, struct nfsd4_compoundargs *args, struct nfsd4_compoundres *resp) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 9ee1dab5d44a..09030afd7249 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -30,7 +30,7 @@ typedef struct svc_buf svc_buf; #define NFSDDBG_FACILITY NFSDDBG_PROC -static int +static __be32 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { return nfs_ok; @@ -56,7 +56,7 @@ nfsd_return_dirop(int err, struct nfsd_diropres *resp) * Get a file's attributes * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) { @@ -72,7 +72,7 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, * Set a file's attributes * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, struct nfsd_attrstat *resp) { @@ -92,7 +92,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, * doesn't exist yet. * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, struct nfsd_diropres *resp) { @@ -112,7 +112,7 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, /* * Read a symlink. */ -static int +static __be32 nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp, struct nfsd_readlinkres *resp) { @@ -132,7 +132,7 @@ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp, * Read a portion of a file. * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, struct nfsd_readres *resp) { @@ -172,7 +172,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, * Write data to a file * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, struct nfsd_attrstat *resp) { @@ -197,7 +197,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, * and the actual create() call in compliance with VFS protocols. * N.B. After this call _both_ argp->fh and resp->fh need an fh_put */ -static int +static __be32 nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, struct nfsd_diropres *resp) { @@ -348,7 +348,7 @@ done: return nfsd_return_dirop(nfserr, resp); } -static int +static __be32 nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, void *resp) { @@ -363,7 +363,7 @@ nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, return nfserr; } -static int +static __be32 nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp, void *resp) { @@ -381,7 +381,7 @@ nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp, return nfserr; } -static int +static __be32 nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp, void *resp) { @@ -401,7 +401,7 @@ nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp, return nfserr; } -static int +static __be32 nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, void *resp) { @@ -430,7 +430,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, * Make directory. This operation is not idempotent. * N.B. After this call resp->fh needs an fh_put */ -static int +static __be32 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, struct nfsd_diropres *resp) { @@ -454,7 +454,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, /* * Remove a directory */ -static int +static __be32 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, void *resp) { @@ -470,7 +470,7 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, /* * Read a portion of a directory. */ -static int +static __be32 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, struct nfsd_readdirres *resp) { @@ -509,7 +509,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, /* * Get file system info */ -static int +static __be32 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, struct nfsd_statfsres *resp) { diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 9c9a8ad92477..965d6c20086e 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -335,7 +335,7 @@ struct svc_version { /* * RPC procedure info */ -typedef int (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp); +typedef __be32 (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp); struct svc_procedure { svc_procfunc pc_func; /* process the request */ kxdrproc_t pc_decode; /* XDR decode args */ -- cgit v1.2.3-71-gd317 From 52921e02a4f4163a7b1f4b5dde71e1debc71de4a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:46 -0700 Subject: [PATCH] lockd endianness annotations Signed-off-by: Alexey Dobriyan Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 4 +-- fs/lockd/mon.c | 12 +++---- fs/lockd/svc4proc.c | 4 +-- fs/lockd/svclock.c | 10 +++--- fs/lockd/svcproc.c | 8 ++--- fs/lockd/svcshare.c | 4 +-- fs/lockd/svcsubs.c | 4 +-- fs/lockd/xdr.c | 76 +++++++++++++++++++++--------------------- fs/lockd/xdr4.c | 80 ++++++++++++++++++++++----------------------- include/linux/lockd/lockd.h | 12 +++---- include/linux/lockd/share.h | 4 +-- include/linux/lockd/xdr.h | 26 +++++++-------- include/linux/lockd/xdr4.h | 26 +++++++-------- 13 files changed, 135 insertions(+), 135 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index e8c7765419e8..b85a0ad2cfb6 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -100,12 +100,12 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) /* * The server lockd has called us back to tell us the lock was granted */ -u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) +__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) { const struct file_lock *fl = &lock->fl; const struct nfs_fh *fh = &lock->fh; struct nlm_wait *block; - u32 res = nlm_lck_denied; + __be32 res = nlm_lck_denied; /* * Look up blocked request based on arguments. diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e0179f8c327f..eb243edf8932 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -148,8 +148,8 @@ nsm_create(void) * XDR functions for NSM. */ -static u32 * -xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) +static __be32 * +xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { char buffer[20], *name; @@ -176,7 +176,7 @@ xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) } static int -xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) +xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { p = xdr_encode_common(rqstp, p, argp); if (IS_ERR(p)) @@ -192,7 +192,7 @@ xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) } static int -xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) +xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { p = xdr_encode_common(rqstp, p, argp); if (IS_ERR(p)) @@ -202,7 +202,7 @@ xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) } static int -xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) +xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) { resp->status = ntohl(*p++); resp->state = ntohl(*p++); @@ -212,7 +212,7 @@ xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) } static int -xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) +xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) { resp->state = ntohl(*p++); return 0; diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 4e719860b4bf..0ce5c81ff507 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -24,14 +24,14 @@ /* * Obtain client and file from arguments */ -static u32 +static __be32 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_host **hostp, struct nlm_file **filp) { struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm_lock *lock = &argp->lock; - u32 error = 0; + __be32 error = 0; /* nfsd callbacks must have been installed for this procedure */ if (!nlmsvc_ops) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 814c6064c9e0..7e219b938552 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -334,13 +334,13 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) * Attempt to establish a lock, and if it can't be granted, block it * if required. */ -u32 +__be32 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) { struct nlm_block *block, *newblock = NULL; int error; - u32 ret; + __be32 ret; dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", file->f_file->f_dentry->d_inode->i_sb->s_id, @@ -415,7 +415,7 @@ out: /* * Test for presence of a conflicting lock. */ -u32 +__be32 nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, struct nlm_lock *conflock) { @@ -448,7 +448,7 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, * afterwards. In this case the block will still be there, and hence * must be removed. */ -u32 +__be32 nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) { int error; @@ -476,7 +476,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) * be in progress. * The calling procedure must check whether the file can be closed. */ -u32 +__be32 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) { struct nlm_block *block; diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index db8d85c32d29..32e99a6e8dca 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -22,8 +22,8 @@ #define NLMDBG_FACILITY NLMDBG_CLIENT #ifdef CONFIG_LOCKD_V4 -static u32 -cast_to_nlm(u32 status, u32 vers) +static __be32 +cast_to_nlm(__be32 status, u32 vers) { /* Note: status is assumed to be in network byte order !!! */ if (vers != 4){ @@ -52,14 +52,14 @@ cast_to_nlm(u32 status, u32 vers) /* * Obtain client and file from arguments */ -static u32 +static __be32 nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_host **hostp, struct nlm_file **filp) { struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm_lock *lock = &argp->lock; - u32 error = 0; + __be32 error = 0; /* nfsd callbacks must have been installed for this procedure */ if (!nlmsvc_ops) diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c index b9926ce8782e..6220dc2a3f2c 100644 --- a/fs/lockd/svcshare.c +++ b/fs/lockd/svcshare.c @@ -23,7 +23,7 @@ nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh) && !memcmp(share->s_owner.data, oh->data, oh->len); } -u32 +__be32 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, struct nlm_args *argp) { @@ -64,7 +64,7 @@ update: /* * Delete a share. */ -u32 +__be32 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, struct nlm_args *argp) { diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 7dac96e6c82c..e83024e16042 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -78,14 +78,14 @@ static inline unsigned int file_hash(struct nfs_fh *f) * This is not quite right, but for now, we assume the client performs * the proper R/W checking. */ -u32 +__be32 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, struct nfs_fh *f) { struct hlist_node *pos; struct nlm_file *file; unsigned int hash; - u32 nfserr; + __be32 nfserr; nlm_debug_print_fh("nlm_file_lookup", f); diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 61c46facf257..b7c949256e5a 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -43,7 +43,7 @@ loff_t_to_s32(loff_t offset) /* * XDR functions for basic NLM types */ -static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c) +static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) { unsigned int len; @@ -69,8 +69,8 @@ static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static inline u32 * -nlm_encode_cookie(u32 *p, struct nlm_cookie *c) +static inline __be32 * +nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) { *p++ = htonl(c->len); memcpy(p, c->data, c->len); @@ -78,8 +78,8 @@ nlm_encode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static u32 * -nlm_decode_fh(u32 *p, struct nfs_fh *f) +static __be32 * +nlm_decode_fh(__be32 *p, struct nfs_fh *f) { unsigned int len; @@ -95,8 +95,8 @@ nlm_decode_fh(u32 *p, struct nfs_fh *f) return p + XDR_QUADLEN(NFS2_FHSIZE); } -static inline u32 * -nlm_encode_fh(u32 *p, struct nfs_fh *f) +static inline __be32 * +nlm_encode_fh(__be32 *p, struct nfs_fh *f) { *p++ = htonl(NFS2_FHSIZE); memcpy(p, f->data, NFS2_FHSIZE); @@ -106,20 +106,20 @@ nlm_encode_fh(u32 *p, struct nfs_fh *f) /* * Encode and decode owner handle */ -static inline u32 * -nlm_decode_oh(u32 *p, struct xdr_netobj *oh) +static inline __be32 * +nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_decode_netobj(p, oh); } -static inline u32 * -nlm_encode_oh(u32 *p, struct xdr_netobj *oh) +static inline __be32 * +nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_encode_netobj(p, oh); } -static u32 * -nlm_decode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm_decode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; s32 start, len, end; @@ -153,8 +153,8 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock) /* * Encode a lock as part of an NLM call */ -static u32 * -nlm_encode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm_encode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; __s32 start, len; @@ -184,8 +184,8 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock) /* * Encode result of a TEST/TEST_MSG call */ -static u32 * -nlm_encode_testres(u32 *p, struct nlm_res *resp) +static __be32 * +nlm_encode_testres(__be32 *p, struct nlm_res *resp) { s32 start, len; @@ -221,7 +221,7 @@ nlm_encode_testres(u32 *p, struct nlm_res *resp) * First, the server side XDR functions */ int -nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -238,7 +238,7 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_testres(p, resp))) return 0; @@ -246,7 +246,7 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -266,7 +266,7 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -282,7 +282,7 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { if (!(p = nlm_decode_cookie(p, &argp->cookie)) || !(p = nlm_decode_lock(p, &argp->lock))) @@ -292,7 +292,7 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -313,7 +313,7 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_cookie(p, &resp->cookie))) return 0; @@ -323,7 +323,7 @@ nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_cookie(p, &resp->cookie))) return 0; @@ -332,7 +332,7 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) +nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -344,7 +344,7 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) } int -nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) +nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp) { if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) return 0; @@ -357,7 +357,7 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) } int -nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return 0; @@ -366,13 +366,13 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); } int -nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } @@ -389,7 +389,7 @@ nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) #endif static int -nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -403,7 +403,7 @@ nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return -EIO; @@ -438,7 +438,7 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) static int -nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -455,7 +455,7 @@ nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -470,7 +470,7 @@ nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -483,7 +483,7 @@ nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_cookie(p, &resp->cookie))) return -EIO; @@ -493,7 +493,7 @@ nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_encode_testres(p, resp))) return -EIO; @@ -502,7 +502,7 @@ nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return -EIO; diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 36eb175ec335..f4c0b2b9f75a 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -44,8 +44,8 @@ loff_t_to_s64(loff_t offset) /* * XDR functions for basic NLM types */ -static u32 * -nlm4_decode_cookie(u32 *p, struct nlm_cookie *c) +static __be32 * +nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) { unsigned int len; @@ -71,8 +71,8 @@ nlm4_decode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static u32 * -nlm4_encode_cookie(u32 *p, struct nlm_cookie *c) +static __be32 * +nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) { *p++ = htonl(c->len); memcpy(p, c->data, c->len); @@ -80,8 +80,8 @@ nlm4_encode_cookie(u32 *p, struct nlm_cookie *c) return p; } -static u32 * -nlm4_decode_fh(u32 *p, struct nfs_fh *f) +static __be32 * +nlm4_decode_fh(__be32 *p, struct nfs_fh *f) { memset(f->data, 0, sizeof(f->data)); f->size = ntohl(*p++); @@ -95,8 +95,8 @@ nlm4_decode_fh(u32 *p, struct nfs_fh *f) return p + XDR_QUADLEN(f->size); } -static u32 * -nlm4_encode_fh(u32 *p, struct nfs_fh *f) +static __be32 * +nlm4_encode_fh(__be32 *p, struct nfs_fh *f) { *p++ = htonl(f->size); if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */ @@ -107,20 +107,20 @@ nlm4_encode_fh(u32 *p, struct nfs_fh *f) /* * Encode and decode owner handle */ -static u32 * -nlm4_decode_oh(u32 *p, struct xdr_netobj *oh) +static __be32 * +nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_decode_netobj(p, oh); } -static u32 * -nlm4_encode_oh(u32 *p, struct xdr_netobj *oh) +static __be32 * +nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh) { return xdr_encode_netobj(p, oh); } -static u32 * -nlm4_decode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; __s64 len, start, end; @@ -153,8 +153,8 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock) /* * Encode a lock as part of an NLM call */ -static u32 * -nlm4_encode_lock(u32 *p, struct nlm_lock *lock) +static __be32 * +nlm4_encode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; __s64 start, len; @@ -185,8 +185,8 @@ nlm4_encode_lock(u32 *p, struct nlm_lock *lock) /* * Encode result of a TEST/TEST_MSG call */ -static u32 * -nlm4_encode_testres(u32 *p, struct nlm_res *resp) +static __be32 * +nlm4_encode_testres(__be32 *p, struct nlm_res *resp) { s64 start, len; @@ -227,7 +227,7 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp) * First, the server side XDR functions */ int -nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -244,7 +244,7 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_testres(p, resp))) return 0; @@ -252,7 +252,7 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -272,7 +272,7 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { u32 exclusive; @@ -288,7 +288,7 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { if (!(p = nlm4_decode_cookie(p, &argp->cookie)) || !(p = nlm4_decode_lock(p, &argp->lock))) @@ -298,7 +298,7 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -319,7 +319,7 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) } int -nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_cookie(p, &resp->cookie))) return 0; @@ -329,7 +329,7 @@ nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_cookie(p, &resp->cookie))) return 0; @@ -338,7 +338,7 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) +nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -350,7 +350,7 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) } int -nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) +nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp) { if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) return 0; @@ -363,7 +363,7 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) } int -nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return 0; @@ -372,13 +372,13 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) } int -nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); } int -nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } @@ -388,14 +388,14 @@ nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) */ #ifdef NLMCLNT_SUPPORT_SHARES static int -nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) +nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr) { return 0; } #endif static int -nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -409,7 +409,7 @@ nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return -EIO; @@ -444,7 +444,7 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) static int -nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -461,7 +461,7 @@ nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -476,7 +476,7 @@ nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) { struct nlm_lock *lock = &argp->lock; @@ -489,7 +489,7 @@ nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) } static int -nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_cookie(p, &resp->cookie))) return -EIO; @@ -499,7 +499,7 @@ nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_encode_testres(p, resp))) return -EIO; @@ -508,7 +508,7 @@ nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) } static int -nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return -EIO; diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 2909619c0295..862d9730a60d 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -154,7 +154,7 @@ int nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *); struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl); void nlmclnt_finish_block(struct nlm_wait *block); int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout); -u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *); +__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *); void nlmclnt_recovery(struct nlm_host *); int nlmclnt_reclaim(struct nlm_host *, struct file_lock *); void nlmclnt_next_cookie(struct nlm_cookie *); @@ -184,12 +184,12 @@ typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref) /* * Server-side lock handling */ -u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, +__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, struct nlm_lock *, int, struct nlm_cookie *); -u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); -u32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *, +__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); +__be32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *, struct nlm_lock *); -u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); +__be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); unsigned long nlmsvc_retry_blocked(void); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t match); @@ -198,7 +198,7 @@ void nlmsvc_grant_reply(struct nlm_cookie *, u32); /* * File handling for the server personality */ -u32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, +__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, struct nfs_fh *); void nlm_release_file(struct nlm_file *); void nlmsvc_mark_resources(void); diff --git a/include/linux/lockd/share.h b/include/linux/lockd/share.h index cd7816e74c05..630c5bf69b07 100644 --- a/include/linux/lockd/share.h +++ b/include/linux/lockd/share.h @@ -21,9 +21,9 @@ struct nlm_share { u32 s_mode; /* deny mode */ }; -u32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, +__be32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, struct nlm_args *); -u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, +__be32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, struct nlm_args *); void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t); diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h index 66fdae3b490c..29e7d9fc9dad 100644 --- a/include/linux/lockd/xdr.h +++ b/include/linux/lockd/xdr.h @@ -90,19 +90,19 @@ struct nlm_reboot { */ #define NLMSVC_XDRSIZE sizeof(struct nlm_args) -int nlmsvc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_encode_void(struct svc_rqst *, u32 *, void *); -int nlmsvc_decode_void(struct svc_rqst *, u32 *, void *); -int nlmsvc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlmsvc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *); -int nlmsvc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *); +int nlmsvc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_encode_void(struct svc_rqst *, __be32 *, void *); +int nlmsvc_decode_void(struct svc_rqst *, __be32 *, void *); +int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlmsvc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *); /* int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h index 3cc1ae25009b..dd12b4c9e613 100644 --- a/include/linux/lockd/xdr4.h +++ b/include/linux/lockd/xdr4.h @@ -23,19 +23,19 @@ -int nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_encode_void(struct svc_rqst *, u32 *, void *); -int nlm4svc_decode_void(struct svc_rqst *, u32 *, void *); -int nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *); -int nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *); -int nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *); +int nlm4svc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_encode_void(struct svc_rqst *, __be32 *, void *); +int nlm4svc_decode_void(struct svc_rqst *, __be32 *, void *); +int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *); +int nlm4svc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *); +int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *); /* int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); -- cgit v1.2.3-71-gd317 From 0dbb4c6799cf8fa8c5ba1926153a30960117477d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:49 -0700 Subject: [PATCH] xdr annotations: NFS readdir entries on-the-wire data is big-endian [in large part pulled from Alexey's patch] Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/dir.c | 6 +++--- fs/nfs/internal.h | 6 +++--- fs/nfs/nfs2xdr.c | 4 ++-- fs/nfs/nfs3xdr.c | 4 ++-- fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4proc.c | 4 ++-- fs/nfs/nfs4xdr.c | 2 +- include/linux/nfs_xdr.h | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c86a1ead4772..4133ef5264e5 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -142,12 +142,12 @@ nfs_opendir(struct inode *inode, struct file *filp) return res; } -typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); +typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int); typedef struct { struct file *file; struct page *page; unsigned long page_index; - u32 *ptr; + __be32 *ptr; u64 *dir_cookie; loff_t current_index; struct nfs_entry *entry; @@ -220,7 +220,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) static inline int dir_decode(nfs_readdir_descriptor_t *desc) { - u32 *p = desc->ptr; + __be32 *p = desc->ptr; p = desc->decode(p, desc->entry, desc->plus); if (IS_ERR(p)) return PTR_ERR(p); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index bea0b016bd70..d205466233f6 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -93,15 +93,15 @@ extern void nfs_destroy_directcache(void); /* nfs2xdr.c */ extern int nfs_stat_to_errno(int); extern struct rpc_procinfo nfs_procedures[]; -extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); +extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); /* nfs3xdr.c */ extern struct rpc_procinfo nfs3_procedures[]; -extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); +extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); /* nfs4xdr.c */ #ifdef CONFIG_NFS_V4 -extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); +extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); #endif /* nfs4proc.c */ diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1d801e30c40e..3be4e72a0227 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -468,8 +468,8 @@ err_unmap: goto out; } -u32 * -nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) +__be32 * +nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) { if (!*p++) { if (!*p) diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index b4e740e4494a..0ace092d126f 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -583,8 +583,8 @@ err_unmap: goto out; } -u32 * -nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) +__be32 * +nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) { struct nfs_entry old = *entry; diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 61095fe4b5ca..6f346677332d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -212,7 +212,7 @@ extern void nfs_free_seqid(struct nfs_seqid *seqid); extern const nfs4_stateid zero_stateid; /* nfs4xdr.c */ -extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus); +extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; struct nfs4_mount_data; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7421bcb3b728..8d09b47c91b9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -141,7 +141,7 @@ const u32 nfs4_fs_locations_bitmap[2] = { static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, struct nfs4_readdir_arg *readdir) { - u32 *start, *p; + __be32 *start, *p; BUG_ON(readdir->count < 80); if (cookie > 2) { @@ -162,7 +162,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, * when talking to the server, we always send cookie 0 * instead of 1 or 2. */ - start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0); + start = p = kmap_atomic(*readdir->pages, KM_USER0); if (cookie == 0) { *p++ = xdr_one; /* next */ diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e284123b9774..0cf3fa312a33 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4421,7 +4421,7 @@ out: return status; } -uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) +__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) { uint32_t bitmap[2] = {0}; uint32_t len; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index dc5397d9d23c..ac8058bc8f94 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -811,7 +811,7 @@ struct nfs_rpc_ops { int (*pathconf) (struct nfs_server *, struct nfs_fh *, struct nfs_pathconf *); int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); - u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); + __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus); void (*read_setup) (struct nfs_read_data *); int (*read_done) (struct rpc_task *, struct nfs_read_data *); void (*write_setup) (struct nfs_write_data *, int how); -- cgit v1.2.3-71-gd317 From bc4785cd475a11ba125df7af674e16c6ea1cfc30 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:51 -0700 Subject: [PATCH] nfs: verifier is network-endian Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/nfs3proc.c | 2 +- fs/nfs/nfs4proc.c | 6 +++--- include/linux/nfs_fs.h | 2 +- include/linux/nfs_xdr.h | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3b234d4601e7..e5f128ffc32d 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -668,7 +668,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, { struct inode *dir = dentry->d_inode; struct nfs_fattr dir_attr; - u32 *verf = NFS_COOKIEVERF(dir); + __be32 *verf = NFS_COOKIEVERF(dir); struct nfs3_readdirargs arg = { .fh = NFS_FH(dir), .cookie = cookie, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8d09b47c91b9..8118036cc449 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -138,7 +138,7 @@ const u32 nfs4_fs_locations_bitmap[2] = { | FATTR4_WORD1_MOUNTED_ON_FILEID }; -static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, +static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry, struct nfs4_readdir_arg *readdir) { __be32 *start, *p; @@ -2915,11 +2915,11 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po .rpc_resp = clp, .rpc_cred = cred, }; - u32 *p; + __be32 *p; int loop = 0; int status; - p = (u32*)sc_verifier.data; + p = (__be32*)sc_verifier.data; *p++ = htonl((u32)clp->cl_boot_time.tv_sec); *p = htonl((u32)clp->cl_boot_time.tv_nsec); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 6b2de1be5815..45228c1a1195 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -157,7 +157,7 @@ struct nfs_inode { * This is the cookie verifier used for NFSv3 readdir * operations */ - __u32 cookieverf[2]; + __be32 cookieverf[2]; /* * This is the list of dirty unwritten pages. diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index ac8058bc8f94..768c1ad5ff6f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -266,7 +266,7 @@ struct nfs_writeargs { struct nfs_writeverf { enum nfs3_stable_how committed; - __u32 verifier[2]; + __be32 verifier[2]; }; struct nfs_writeres { @@ -420,7 +420,7 @@ struct nfs3_createargs { unsigned int len; struct iattr * sattr; enum nfs3_createmode createmode; - __u32 verifier[2]; + __be32 verifier[2]; }; struct nfs3_mkdirargs { @@ -467,7 +467,7 @@ struct nfs3_linkargs { struct nfs3_readdirargs { struct nfs_fh * fh; __u64 cookie; - __u32 verf[2]; + __be32 verf[2]; int plus; unsigned int count; struct page ** pages; @@ -503,7 +503,7 @@ struct nfs3_linkres { struct nfs3_readdirres { struct nfs_fattr * dir_attr; - __u32 * verf; + __be32 * verf; int plus; }; -- cgit v1.2.3-71-gd317 From 63f103111fdfc3cba00e4c94921d32362f375d93 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:54 -0700 Subject: [PATCH] nfsd: nfserrno() endianness annotations Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsproc.c | 7 +++---- include/linux/nfsd/export.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 09030afd7249..03ab6822291f 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -579,11 +579,11 @@ struct svc_version nfsd_version2 = { /* * Map errnos to NFS errnos. */ -int +__be32 nfserrno (int errno) { static struct { - int nfserr; + __be32 nfserr; int syserr; } nfs_errtbl[] = { { nfs_ok, 0 }, @@ -615,11 +615,10 @@ nfserrno (int errno) { nfserr_badname, -ESRCH }, { nfserr_io, -ETXTBSY }, { nfserr_notsupp, -EOPNOTSUPP }, - { -1, -EIO } }; int i; - for (i = 0; nfs_errtbl[i].nfserr != -1; i++) { + for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) { if (nfs_errtbl[i].syserr == errno) return nfs_errtbl[i].nfserr; } diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 6e78ea969f49..27666f5b8b53 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -118,7 +118,7 @@ struct svc_export * exp_parent(struct auth_domain *clp, int exp_rootfh(struct auth_domain *, char *path, struct knfsd_fh *, int maxsize); int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); -int nfserrno(int errno); +__be32 nfserrno(int errno); extern struct cache_detail svc_export_cache; -- cgit v1.2.3-71-gd317 From 83b11340d683a67a77e35a5ffb5ad4afbf0be4e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:55 -0700 Subject: [PATCH] nfsfh simple endianness annotations Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfsfh.c | 10 +++++----- include/linux/nfsd/nfsfh.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 501d83884530..727ab3bd450d 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -76,7 +76,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) * comment in the NFSv3 spec says this is incorrect (implementation notes for * the write call). */ -static inline int +static inline __be32 nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type) { /* Type can be negative when creating hardlinks - not to a dir */ @@ -110,13 +110,13 @@ nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type) * This is only called at the start of an nfsproc call, so fhp points to * a svc_fh which is all 0 except for the over-the-wire file handle. */ -u32 +__be32 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) { struct knfsd_fh *fh = &fhp->fh_handle; struct svc_export *exp = NULL; struct dentry *dentry; - u32 error = 0; + __be32 error = 0; dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); @@ -315,7 +315,7 @@ static inline void _fh_update_old(struct dentry *dentry, fh->ofh_dirino = 0; } -int +__be32 fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh) { /* ref_fh is a reference file handle. @@ -451,7 +451,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st * Update file handle information after changing a dentry. * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create */ -int +__be32 fh_update(struct svc_fh *fhp) { struct dentry *dentry; diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 069257ea99a0..749bad1ca16f 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -209,9 +209,9 @@ extern char * SVCFH_fmt(struct svc_fh *fhp); /* * Function prototypes */ -u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); -int fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); -int fh_update(struct svc_fh *); +__be32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); +__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); +__be32 fh_update(struct svc_fh *); void fh_put(struct svc_fh *); static __inline__ struct svc_fh * -- cgit v1.2.3-71-gd317 From 131a21c2177c267ab259fcd06947c6f593a7de8e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:56 -0700 Subject: [PATCH] xdr annotations: NFSv2 server Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs2acl.c | 18 ++++++------ fs/nfsd/nfsxdr.c | 72 +++++++++++++++++++++++------------------------ include/linux/nfsd/nfsd.h | 2 +- include/linux/nfsd/xdr.h | 50 ++++++++++++++++---------------- 4 files changed, 71 insertions(+), 71 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 8d48616882c1..fd5397d8c62a 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -158,7 +158,7 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessarg /* * XDR decode functions */ -static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclargs *argp) { if (!(p = nfs2svc_decode_fh(p, &argp->fh))) @@ -169,7 +169,7 @@ static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, } -static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_setaclargs *argp) { struct kvec *head = rqstp->rq_arg.head; @@ -194,7 +194,7 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, return (n > 0); } -static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *argp) { if (!(p = nfs2svc_decode_fh(p, &argp->fh))) @@ -202,7 +202,7 @@ static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, return xdr_argsize_check(rqstp, p); } -static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessargs *argp) { if (!(p = nfs2svc_decode_fh(p, &argp->fh))) @@ -217,7 +217,7 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, */ /* GETACL */ -static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { struct dentry *dentry = resp->fh.fh_dentry; @@ -259,7 +259,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, return 1; } -static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_attrstat *resp) { p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); @@ -267,7 +267,7 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, } /* ACCESS */ -static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessres *resp) { p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); @@ -278,7 +278,7 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, /* * XDR release functions */ -static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { fh_put(&resp->fh); @@ -287,7 +287,7 @@ static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, return 1; } -static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, +static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *resp) { fh_put(&resp->fh); diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 1135c0d14557..56ebb1443e0e 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -37,8 +37,8 @@ static u32 nfs_ftypes[] = { /* * XDR functions for basic NFS types */ -static u32 * -decode_fh(u32 *p, struct svc_fh *fhp) +static __be32 * +decode_fh(__be32 *p, struct svc_fh *fhp) { fh_init(fhp, NFS_FHSIZE); memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE); @@ -50,13 +50,13 @@ decode_fh(u32 *p, struct svc_fh *fhp) } /* Helper function for NFSv2 ACL code */ -u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp) +__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp) { return decode_fh(p, fhp); } -static inline u32 * -encode_fh(u32 *p, struct svc_fh *fhp) +static inline __be32 * +encode_fh(__be32 *p, struct svc_fh *fhp) { memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE); return p + (NFS_FHSIZE>> 2); @@ -66,8 +66,8 @@ encode_fh(u32 *p, struct svc_fh *fhp) * Decode a file name and make sure that the path contains * no slashes or null bytes. */ -static inline u32 * -decode_filename(u32 *p, char **namp, int *lenp) +static inline __be32 * +decode_filename(__be32 *p, char **namp, int *lenp) { char *name; int i; @@ -82,8 +82,8 @@ decode_filename(u32 *p, char **namp, int *lenp) return p; } -static inline u32 * -decode_pathname(u32 *p, char **namp, int *lenp) +static inline __be32 * +decode_pathname(__be32 *p, char **namp, int *lenp) { char *name; int i; @@ -98,8 +98,8 @@ decode_pathname(u32 *p, char **namp, int *lenp) return p; } -static inline u32 * -decode_sattr(u32 *p, struct iattr *iap) +static inline __be32 * +decode_sattr(__be32 *p, struct iattr *iap) { u32 tmp, tmp1; @@ -151,8 +151,8 @@ decode_sattr(u32 *p, struct iattr *iap) return p; } -static u32 * -encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, +static __be32 * +encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) { struct dentry *dentry = fhp->fh_dentry; @@ -195,7 +195,7 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, } /* Helper function for NFSv2 ACL code */ -u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct kstat stat; vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat); @@ -206,13 +206,13 @@ u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) * XDR decode functions */ int -nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); } int -nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args) +nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args) { if (!(p = decode_fh(p, &args->fh))) return 0; @@ -220,7 +220,7 @@ nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args) } int -nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_sattrargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -231,7 +231,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_diropargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -242,7 +242,7 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readargs *args) { unsigned int len; @@ -273,7 +273,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_writeargs *args) { unsigned int len; @@ -303,7 +303,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_createargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -315,7 +315,7 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_renameargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -328,7 +328,7 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinkargs *args) +nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args) { if (!(p = decode_fh(p, &args->fh))) return 0; @@ -338,7 +338,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinka } int -nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_linkargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -350,7 +350,7 @@ nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_symlinkargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -363,7 +363,7 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, +nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readdirargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -382,13 +382,13 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, * XDR encode functions */ int -nfssvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } int -nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd_attrstat *resp) { p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); @@ -396,7 +396,7 @@ nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_diropres *resp) { p = encode_fh(p, &resp->fh); @@ -405,7 +405,7 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkres *resp) { *p++ = htonl(resp->len); @@ -421,7 +421,7 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readres *resp) { p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); @@ -440,7 +440,7 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readdirres *resp) { xdr_ressize_check(rqstp, p); @@ -453,7 +453,7 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, } int -nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p, +nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p, struct nfsd_statfsres *resp) { struct kstatfs *stat = &resp->stats; @@ -471,7 +471,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common); - u32 *p = cd->buffer; + __be32 *p = cd->buffer; int buflen, slen; /* @@ -497,7 +497,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name, *p++ = htonl((u32) ino); /* file id */ p = xdr_encode_array(p, name, namlen);/* name length & name */ cd->offset = p; /* remember pointer */ - *p++ = ~(u32) 0; /* offset of next entry */ + *p++ = htonl(~0U); /* offset of next entry */ cd->buflen = buflen; cd->buffer = p; @@ -509,7 +509,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name, * XDR release functions */ int -nfssvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, +nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *resp) { fh_put(&resp->fh); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index d0d4aae7085f..2f75160a5824 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -50,7 +50,7 @@ * Callback function for readdir */ struct readdir_cd { - int err; /* 0, nfserr, or nfserr_eof */ + __be32 err; /* 0, nfserr, or nfserr_eof */ }; typedef int (*encode_dent_fn)(struct readdir_cd *, const char *, int, loff_t, ino_t, unsigned int); diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index 0e53de87d886..877192d3ae79 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -81,7 +81,7 @@ struct nfsd_readdirargs { struct svc_fh fh; __u32 cookie; __u32 count; - u32 * buffer; + __be32 * buffer; }; struct nfsd_attrstat { @@ -108,9 +108,9 @@ struct nfsd_readdirres { int count; struct readdir_cd common; - u32 * buffer; + __be32 * buffer; int buflen; - u32 * offset; + __be32 * offset; }; struct nfsd_statfsres { @@ -135,43 +135,43 @@ union nfsd_xdrstore { #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore) -int nfssvc_decode_void(struct svc_rqst *, u32 *, void *); -int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); -int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *, +int nfssvc_decode_void(struct svc_rqst *, __be32 *, void *); +int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *); +int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *, struct nfsd_sattrargs *); -int nfssvc_decode_diropargs(struct svc_rqst *, u32 *, +int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *, struct nfsd_diropargs *); -int nfssvc_decode_readargs(struct svc_rqst *, u32 *, +int nfssvc_decode_readargs(struct svc_rqst *, __be32 *, struct nfsd_readargs *); -int nfssvc_decode_writeargs(struct svc_rqst *, u32 *, +int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *, struct nfsd_writeargs *); -int nfssvc_decode_createargs(struct svc_rqst *, u32 *, +int nfssvc_decode_createargs(struct svc_rqst *, __be32 *, struct nfsd_createargs *); -int nfssvc_decode_renameargs(struct svc_rqst *, u32 *, +int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *, struct nfsd_renameargs *); -int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *, +int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *, struct nfsd_readlinkargs *); -int nfssvc_decode_linkargs(struct svc_rqst *, u32 *, +int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *, struct nfsd_linkargs *); -int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *, +int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *, struct nfsd_symlinkargs *); -int nfssvc_decode_readdirargs(struct svc_rqst *, u32 *, +int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *, struct nfsd_readdirargs *); -int nfssvc_encode_void(struct svc_rqst *, u32 *, void *); -int nfssvc_encode_attrstat(struct svc_rqst *, u32 *, struct nfsd_attrstat *); -int nfssvc_encode_diropres(struct svc_rqst *, u32 *, struct nfsd_diropres *); -int nfssvc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd_readlinkres *); -int nfssvc_encode_readres(struct svc_rqst *, u32 *, struct nfsd_readres *); -int nfssvc_encode_statfsres(struct svc_rqst *, u32 *, struct nfsd_statfsres *); -int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *); +int nfssvc_encode_void(struct svc_rqst *, __be32 *, void *); +int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd_attrstat *); +int nfssvc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd_diropres *); +int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd_readlinkres *); +int nfssvc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd_readres *); +int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *, struct nfsd_statfsres *); +int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd_readdirres *); int nfssvc_encode_entry(struct readdir_cd *, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int); -int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); +int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *); /* Helper functions for NFSv2 ACL code */ -u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp); -u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp); +__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp); +__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp); #endif /* LINUX_NFSD_H */ -- cgit v1.2.3-71-gd317 From 91f07168cef8e99dd16f608fbc703e7a5af0237f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:57 -0700 Subject: [PATCH] xdr annotations: NFSv3 server Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs3acl.c | 10 ++-- fs/nfsd/nfs3xdr.c | 126 +++++++++++++++++++++++----------------------- include/linux/nfsd/xdr3.h | 114 ++++++++++++++++++++--------------------- 3 files changed, 125 insertions(+), 125 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index ed6e2c27b5e8..78b2c83d00c5 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -122,7 +122,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, /* * XDR decode functions */ -static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclargs *args) { if (!(p = nfs3svc_decode_fh(p, &args->fh))) @@ -133,7 +133,7 @@ static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, } -static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_setaclargs *args) { struct kvec *head = rqstp->rq_arg.head; @@ -163,7 +163,7 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, */ /* GETACL */ -static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { struct dentry *dentry = resp->fh.fh_dentry; @@ -208,7 +208,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, } /* SETACL */ -static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); @@ -219,7 +219,7 @@ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, /* * XDR release functions */ -static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p, +static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { fh_put(&resp->fh); diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 247d518248bf..b4baca3053c3 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -42,23 +42,23 @@ static u32 nfs3_ftypes[] = { /* * XDR functions for basic NFS types */ -static inline u32 * -encode_time3(u32 *p, struct timespec *time) +static inline __be32 * +encode_time3(__be32 *p, struct timespec *time) { *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); return p; } -static inline u32 * -decode_time3(u32 *p, struct timespec *time) +static inline __be32 * +decode_time3(__be32 *p, struct timespec *time) { time->tv_sec = ntohl(*p++); time->tv_nsec = ntohl(*p++); return p; } -static inline u32 * -decode_fh(u32 *p, struct svc_fh *fhp) +static inline __be32 * +decode_fh(__be32 *p, struct svc_fh *fhp) { unsigned int size; fh_init(fhp, NFS3_FHSIZE); @@ -72,13 +72,13 @@ decode_fh(u32 *p, struct svc_fh *fhp) } /* Helper function for NFSv3 ACL code */ -u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp) +__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp) { return decode_fh(p, fhp); } -static inline u32 * -encode_fh(u32 *p, struct svc_fh *fhp) +static inline __be32 * +encode_fh(__be32 *p, struct svc_fh *fhp) { unsigned int size = fhp->fh_handle.fh_size; *p++ = htonl(size); @@ -91,8 +91,8 @@ encode_fh(u32 *p, struct svc_fh *fhp) * Decode a file name and make sure that the path contains * no slashes or null bytes. */ -static inline u32 * -decode_filename(u32 *p, char **namp, int *lenp) +static inline __be32 * +decode_filename(__be32 *p, char **namp, int *lenp) { char *name; int i; @@ -107,8 +107,8 @@ decode_filename(u32 *p, char **namp, int *lenp) return p; } -static inline u32 * -decode_sattr3(u32 *p, struct iattr *iap) +static inline __be32 * +decode_sattr3(__be32 *p, struct iattr *iap) { u32 tmp; @@ -153,8 +153,8 @@ decode_sattr3(u32 *p, struct iattr *iap) return p; } -static inline u32 * -encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, +static inline __be32 * +encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) { struct dentry *dentry = fhp->fh_dentry; @@ -186,8 +186,8 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, return p; } -static inline u32 * -encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +static inline __be32 * +encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct inode *inode = fhp->fh_dentry->d_inode; @@ -224,8 +224,8 @@ encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) * The inode may be NULL if the call failed because of a stale file * handle. In this case, no attributes are returned. */ -static u32 * -encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +static __be32 * +encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct dentry *dentry = fhp->fh_dentry; if (dentry && dentry->d_inode != NULL) { @@ -243,8 +243,8 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) } /* Helper for NFSv3 ACLs */ -u32 * -nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +__be32 * +nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { return encode_post_op_attr(rqstp, p, fhp); } @@ -252,8 +252,8 @@ nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) /* * Enocde weak cache consistency data */ -static u32 * -encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +static __be32 * +encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct dentry *dentry = fhp->fh_dentry; @@ -278,7 +278,7 @@ encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) * XDR decode functions */ int -nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args) +nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args) { if (!(p = decode_fh(p, &args->fh))) return 0; @@ -286,7 +286,7 @@ nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args } int -nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_sattrargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -303,7 +303,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_diropargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -314,7 +314,7 @@ nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -325,7 +325,7 @@ nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readargs *args) { unsigned int len; @@ -355,7 +355,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_writeargs *args) { unsigned int len, v, hdr; @@ -393,7 +393,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_createargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -417,7 +417,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p, return xdr_argsize_check(rqstp, p); } int -nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_createargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -429,7 +429,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_symlinkargs *args) { unsigned int len; @@ -481,7 +481,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_mknodargs *args) { if (!(p = decode_fh(p, &args->fh)) @@ -505,7 +505,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_renameargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -518,7 +518,7 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readlinkargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -530,7 +530,7 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_linkargs *args) { if (!(p = decode_fh(p, &args->ffh)) @@ -542,7 +542,7 @@ nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readdirargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -562,7 +562,7 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readdirargs *args) { int len, pn; @@ -590,7 +590,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p, +nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_commitargs *args) { if (!(p = decode_fh(p, &args->fh))) @@ -609,14 +609,14 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p, * will work properly. */ int -nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } /* GETATTR */ int -nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { if (resp->status == 0) @@ -626,7 +626,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, /* SETATTR, REMOVE, RMDIR */ int -nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { p = encode_wcc_data(rqstp, p, &resp->fh); @@ -635,7 +635,7 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p, /* LOOKUP */ int -nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_diropres *resp) { if (resp->status == 0) { @@ -648,7 +648,7 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p, /* ACCESS */ int -nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_accessres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -659,7 +659,7 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p, /* READLINK */ int -nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readlinkres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -680,7 +680,7 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, /* READ */ int -nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -704,7 +704,7 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p, /* WRITE */ int -nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_writeres *resp) { p = encode_wcc_data(rqstp, p, &resp->fh); @@ -719,7 +719,7 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p, /* CREATE, MKDIR, SYMLINK, MKNOD */ int -nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_diropres *resp) { if (resp->status == 0) { @@ -733,7 +733,7 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p, /* RENAME */ int -nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_renameres *resp) { p = encode_wcc_data(rqstp, p, &resp->ffh); @@ -743,7 +743,7 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p, /* LINK */ int -nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_linkres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -753,7 +753,7 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p, /* READDIR */ int -nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_readdirres *resp) { p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -776,8 +776,8 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, return xdr_ressize_check(rqstp, p); } -static inline u32 * -encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name, +static inline __be32 * +encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, ino_t ino) { *p++ = xdr_one; /* mark entry present */ @@ -790,8 +790,8 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name, return p; } -static inline u32 * -encode_entryplus_baggage(struct nfsd3_readdirres *cd, u32 *p, +static inline __be32 * +encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, struct svc_fh *fhp) { p = encode_post_op_attr(cd->rqstp, p, fhp); @@ -853,7 +853,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, { struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, common); - u32 *p = cd->buffer; + __be32 *p = cd->buffer; caddr_t curr_page_addr = NULL; int pn; /* current page number */ int slen; /* string (name) length */ @@ -919,7 +919,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, } else if (cd->rqstp->rq_respages[pn+1] != NULL) { /* temporarily encode entry into next page, then move back to * current and next page in rq_respages[] */ - u32 *p1, *tmp; + __be32 *p1, *tmp; int len1, len2; /* grab next page for temporary storage of entry */ @@ -1009,7 +1009,7 @@ nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name, /* FSSTAT */ int -nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_fsstatres *resp) { struct kstatfs *s = &resp->stats; @@ -1031,7 +1031,7 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, /* FSINFO */ int -nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_fsinfores *resp) { *p++ = xdr_zero; /* no post_op_attr */ @@ -1055,7 +1055,7 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p, /* PATHCONF */ int -nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_pathconfres *resp) { *p++ = xdr_zero; /* no post_op_attr */ @@ -1074,7 +1074,7 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p, /* COMMIT */ int -nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p, +nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_commitres *resp) { p = encode_wcc_data(rqstp, p, &resp->fh); @@ -1090,7 +1090,7 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p, * XDR release functions */ int -nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p, +nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { fh_put(&resp->fh); @@ -1098,7 +1098,7 @@ nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p, } int -nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p, +nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_fhandle_pair *resp) { fh_put(&resp->fh1); diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index 474d882dc2f3..79963867b0d7 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -51,7 +51,7 @@ struct nfsd3_createargs { int len; int createmode; struct iattr attrs; - __u32 * verf; + __be32 * verf; }; struct nfsd3_mknodargs { @@ -98,8 +98,8 @@ struct nfsd3_readdirargs { __u64 cookie; __u32 dircount; __u32 count; - __u32 * verf; - u32 * buffer; + __be32 * verf; + __be32 * buffer; }; struct nfsd3_commitargs { @@ -122,79 +122,79 @@ struct nfsd3_setaclargs { }; struct nfsd3_attrstat { - __u32 status; + __be32 status; struct svc_fh fh; struct kstat stat; }; /* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */ struct nfsd3_diropres { - __u32 status; + __be32 status; struct svc_fh dirfh; struct svc_fh fh; }; struct nfsd3_accessres { - __u32 status; + __be32 status; struct svc_fh fh; __u32 access; }; struct nfsd3_readlinkres { - __u32 status; + __be32 status; struct svc_fh fh; __u32 len; }; struct nfsd3_readres { - __u32 status; + __be32 status; struct svc_fh fh; unsigned long count; int eof; }; struct nfsd3_writeres { - __u32 status; + __be32 status; struct svc_fh fh; unsigned long count; int committed; }; struct nfsd3_renameres { - __u32 status; + __be32 status; struct svc_fh ffh; struct svc_fh tfh; }; struct nfsd3_linkres { - __u32 status; + __be32 status; struct svc_fh tfh; struct svc_fh fh; }; struct nfsd3_readdirres { - __u32 status; + __be32 status; struct svc_fh fh; int count; - __u32 verf[2]; + __be32 verf[2]; struct readdir_cd common; - u32 * buffer; + __be32 * buffer; int buflen; - u32 * offset; - u32 * offset1; + __be32 * offset; + __be32 * offset1; struct svc_rqst * rqstp; }; struct nfsd3_fsstatres { - __u32 status; + __be32 status; struct kstatfs stats; __u32 invarsec; }; struct nfsd3_fsinfores { - __u32 status; + __be32 status; __u32 f_rtmax; __u32 f_rtpref; __u32 f_rtmult; @@ -207,7 +207,7 @@ struct nfsd3_fsinfores { }; struct nfsd3_pathconfres { - __u32 status; + __be32 status; __u32 p_link_max; __u32 p_name_max; __u32 p_no_trunc; @@ -217,12 +217,12 @@ struct nfsd3_pathconfres { }; struct nfsd3_commitres { - __u32 status; + __be32 status; struct svc_fh fh; }; struct nfsd3_getaclres { - __u32 status; + __be32 status; struct svc_fh fh; int mask; struct posix_acl *acl_access; @@ -266,70 +266,70 @@ union nfsd3_xdrstore { #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) -int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); -int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *); +int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *, struct nfsd3_sattrargs *); -int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *, struct nfsd3_diropargs *); -int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *, struct nfsd3_accessargs *); -int nfs3svc_decode_readargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *, struct nfsd3_readargs *); -int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *, struct nfsd3_writeargs *); -int nfs3svc_decode_createargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *, struct nfsd3_createargs *); -int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *, struct nfsd3_createargs *); -int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *, struct nfsd3_mknodargs *); -int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *, struct nfsd3_renameargs *); -int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *, struct nfsd3_readlinkargs *); -int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *, struct nfsd3_linkargs *); -int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *, struct nfsd3_symlinkargs *); -int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *, struct nfsd3_readdirargs *); -int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *, struct nfsd3_readdirargs *); -int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *, +int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *, struct nfsd3_commitargs *); -int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *); -int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *, +int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *, void *); +int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd3_attrstat *); -int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *, +int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *, struct nfsd3_attrstat *); -int nfs3svc_encode_diropres(struct svc_rqst *, u32 *, +int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd3_diropres *); -int nfs3svc_encode_accessres(struct svc_rqst *, u32 *, +int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *, struct nfsd3_accessres *); -int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *, +int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd3_readlinkres *); -int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *); -int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *); -int nfs3svc_encode_createres(struct svc_rqst *, u32 *, +int nfs3svc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd3_readres *); +int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *, struct nfsd3_writeres *); +int nfs3svc_encode_createres(struct svc_rqst *, __be32 *, struct nfsd3_diropres *); -int nfs3svc_encode_renameres(struct svc_rqst *, u32 *, +int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *, struct nfsd3_renameres *); -int nfs3svc_encode_linkres(struct svc_rqst *, u32 *, +int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *, struct nfsd3_linkres *); -int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *, +int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd3_readdirres *); -int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *, +int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *, struct nfsd3_fsstatres *); -int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *, +int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *, struct nfsd3_fsinfores *); -int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *, +int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *, struct nfsd3_pathconfres *); -int nfs3svc_encode_commitres(struct svc_rqst *, u32 *, +int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *, struct nfsd3_commitres *); -int nfs3svc_release_fhandle(struct svc_rqst *, u32 *, +int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd3_attrstat *); -int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *, +int nfs3svc_release_fhandle2(struct svc_rqst *, __be32 *, struct nfsd3_fhandle_pair *); int nfs3svc_encode_entry(struct readdir_cd *, const char *name, int namlen, loff_t offset, ino_t ino, @@ -338,9 +338,9 @@ int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int); /* Helper functions for NFSv3 ACL code */ -u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, +__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp); -u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp); +__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp); #endif /* _LINUX_NFSD_XDR3_H */ -- cgit v1.2.3-71-gd317 From 2ebbc012a9433a252be7ab4ce54e94bf7b21e506 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:58 -0700 Subject: [PATCH] xdr annotations: NFSv4 server Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4xdr.c | 66 +++++++++++++++++++++++------------------------ include/linux/nfsd/xdr4.h | 24 ++++++++--------- 3 files changed, 46 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 795ad6c5cb2c..ca6414248527 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -664,7 +664,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ static int nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify) { - u32 *buf, *p; + __be32 *buf, *p; int count; int status; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 77be0c4785e6..3419d99aeb1a 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -94,7 +94,7 @@ check_filename(char *str, int len, int err) * consistent with the style used in NFSv2/v3... */ #define DECODE_HEAD \ - u32 *p; \ + __be32 *p; \ int status #define DECODE_TAIL \ status = 0; \ @@ -144,13 +144,13 @@ xdr_error: \ } \ } while (0) -static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) +static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) { /* We want more bytes than seem to be available. * Maybe we need a new page, maybe we have just run out */ int avail = (char*)argp->end - (char*)argp->p; - u32 *p; + __be32 *p; if (avail + argp->pagelen < nbytes) return NULL; if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */ @@ -197,7 +197,7 @@ defer_free(struct nfsd4_compoundargs *argp, return 0; } -static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) +static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) { void *new = NULL; if (p == argp->tmp) { @@ -951,8 +951,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) argp->pagelen -= len; } } - argp->end = (u32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); - argp->p = (u32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); + argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); + argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); argp->rqstp->rq_vec[v].iov_len = len; write->wr_vlen = v+1; @@ -1179,7 +1179,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define ENCODE_HEAD u32 *p +#define ENCODE_HEAD __be32 *p #define WRITE32(n) *p++ = htonl(n) #define WRITE64(n) do { \ @@ -1209,8 +1209,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) * Header routine to setup seqid operation replay cache */ #define ENCODE_SEQID_OP_HEAD \ - u32 *p; \ - u32 *save; \ + __be32 *p; \ + __be32 *save; \ \ save = resp->p; @@ -1235,10 +1235,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) * seperated @sep. */ static int nfsd4_encode_components(char sep, char *components, - u32 **pp, int *buflen) + __be32 **pp, int *buflen) { - u32 *p = *pp; - u32 *countp = p; + __be32 *p = *pp; + __be32 *countp = p; int strlen, count=0; char *str, *end; @@ -1272,10 +1272,10 @@ static int nfsd4_encode_components(char sep, char *components, * encode a location element of a fs_locations structure */ static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, - u32 **pp, int *buflen) + __be32 **pp, int *buflen) { int status; - u32 *p = *pp; + __be32 *p = *pp; status = nfsd4_encode_components(':', location->hosts, &p, buflen); if (status) @@ -1320,11 +1320,11 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, u32 *sta */ static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp, struct svc_export *exp, - u32 **pp, int *buflen) + __be32 **pp, int *buflen) { u32 status; int i; - u32 *p = *pp; + __be32 *p = *pp; struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; char *root = nfsd4_path(rqstp, exp, &status); @@ -1355,7 +1355,7 @@ static u32 nfs4_ftypes[16] = { static int nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, - u32 **p, int *buflen) + __be32 **p, int *buflen) { int status; @@ -1376,20 +1376,20 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, } static inline int -nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen) +nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); } static inline int -nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen) +nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); } static inline int nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, - u32 **p, int *buflen) + __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); } @@ -1423,7 +1423,7 @@ static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) */ int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, - struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval, + struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, struct svc_rqst *rqstp) { u32 bmval0 = bmval[0]; @@ -1432,11 +1432,11 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct svc_fh tempfh; struct kstatfs statfs; int buflen = *countp << 2; - u32 *attrlenp; + __be32 *attrlenp; u32 dummy; u64 dummy64; u32 rdattr_err = 0; - u32 *p = buffer; + __be32 *p = buffer; int status; int aclsupport = 0; struct nfs4_acl *acl = NULL; @@ -1831,7 +1831,7 @@ out_serverfault: static int nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, - const char *name, int namlen, u32 *p, int *buflen) + const char *name, int namlen, __be32 *p, int *buflen) { struct svc_export *exp = cd->rd_fhp->fh_export; struct dentry *dentry; @@ -1864,10 +1864,10 @@ out_put: return nfserr; } -static u32 * -nfsd4_encode_rdattr_error(u32 *p, int buflen, int nfserr) +static __be32 * +nfsd4_encode_rdattr_error(__be32 *p, int buflen, int nfserr) { - u32 *attrlenp; + __be32 *attrlenp; if (buflen < 6) return NULL; @@ -1887,7 +1887,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, { struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); int buflen; - u32 *p = cd->buffer; + __be32 *p = cd->buffer; int nfserr = nfserr_toosmall; /* In nfsv4, "." and ".." never make it onto the wire.. */ @@ -2321,7 +2321,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re { int maxcount; loff_t offset; - u32 *page, *savep, *tailbase; + __be32 *page, *savep, *tailbase; ENCODE_HEAD; if (nfserr) @@ -2479,7 +2479,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_writ void nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) { - u32 *statp; + __be32 *statp; ENCODE_HEAD; RESERVE_SPACE(8); @@ -2617,7 +2617,7 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) */ int -nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) +nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); } @@ -2639,7 +2639,7 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) } int -nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args) +nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) { int status; @@ -2660,7 +2660,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoun } int -nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundres *resp) +nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp) { /* * All that remains is to write the tag and operation count... diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 66e642762a07..003193fe6fc6 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -258,9 +258,9 @@ struct nfsd4_readdir { struct svc_fh * rd_fhp; /* response */ struct readdir_cd common; - u32 * buffer; + __be32 * buffer; int buflen; - u32 * offset; + __be32 * offset; }; struct nfsd4_release_lockowner { @@ -371,12 +371,12 @@ struct nfsd4_op { struct nfsd4_compoundargs { /* scratch variables for XDR decode */ - u32 * p; - u32 * end; + __be32 * p; + __be32 * end; struct page ** pagelist; int pagelen; - u32 tmp[8]; - u32 * tmpp; + __be32 tmp[8]; + __be32 * tmpp; struct tmpbuf { struct tmpbuf *next; void (*release)(const void *); @@ -395,15 +395,15 @@ struct nfsd4_compoundargs { struct nfsd4_compoundres { /* scratch variables for XDR encode */ - u32 * p; - u32 * end; + __be32 * p; + __be32 * end; struct xdr_buf * xbuf; struct svc_rqst * rqstp; u32 taglen; char * tag; u32 opcnt; - u32 * tagp; /* where to encode tag and opcount */ + __be32 * tagp; /* where to encode tag and opcount */ }; #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) @@ -419,10 +419,10 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec; } -int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *); -int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *, +int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); +int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, struct nfsd4_compoundargs *); -int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *, +int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, struct nfsd4_compoundres *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); -- cgit v1.2.3-71-gd317 From 6264d69d7df654ca64f625e9409189a0e50734e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:58 -0700 Subject: [PATCH] nfsd: vfs.c endianness annotations don't use the same variable to store NFS and host error values Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/vfs.c | 299 ++++++++++++++++++++++++---------------------- include/linux/nfsd/nfsd.h | 38 +++--- 2 files changed, 176 insertions(+), 161 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 1141bd29e4e3..f21e917bb8ed 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -110,7 +110,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, struct dentry *dentry = *dpp; struct vfsmount *mnt = mntget(exp->ex_mnt); struct dentry *mounts = dget(dentry); - int err = nfs_ok; + int err = 0; while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); @@ -148,14 +148,15 @@ out: * clients and is explicitly disallowed for NFSv3 * NeilBrown */ -int +__be32 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, int len, struct svc_fh *resfh) { struct svc_export *exp; struct dentry *dparent; struct dentry *dentry; - int err; + __be32 err; + int host_err; dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); @@ -193,7 +194,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, exp2 = exp_parent(exp->ex_client, mnt, dentry, &rqstp->rq_chandle); if (IS_ERR(exp2)) { - err = PTR_ERR(exp2); + host_err = PTR_ERR(exp2); dput(dentry); mntput(mnt); goto out_nfserr; @@ -210,14 +211,14 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, } else { fh_lock(fhp); dentry = lookup_one_len(name, dparent, len); - err = PTR_ERR(dentry); + host_err = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_nfserr; /* * check if we have crossed a mount point ... */ if (d_mountpoint(dentry)) { - if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { + if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { dput(dentry); goto out_nfserr; } @@ -236,7 +237,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -244,7 +245,7 @@ out_nfserr: * Set various file attributes. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int check_guard, time_t guardtime) { @@ -253,7 +254,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int accmode = MAY_SATTR; int ftype = 0; int imode; - int err; + __be32 err; + int host_err; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) @@ -319,19 +321,19 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, * If we are changing the size of the file, then * we need to break all leases. */ - err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); - if (err == -EWOULDBLOCK) - err = -ETIMEDOUT; - if (err) /* ENOMEM or EWOULDBLOCK */ + host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); + if (host_err == -EWOULDBLOCK) + host_err = -ETIMEDOUT; + if (host_err) /* ENOMEM or EWOULDBLOCK */ goto out_nfserr; - err = get_write_access(inode); - if (err) + host_err = get_write_access(inode); + if (host_err) goto out_nfserr; size_change = 1; - err = locks_verify_truncate(inode, NULL, iap->ia_size); - if (err) { + host_err = locks_verify_truncate(inode, NULL, iap->ia_size); + if (host_err) { put_write_access(inode); goto out_nfserr; } @@ -357,8 +359,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, err = nfserr_notsync; if (!check_guard || guardtime == inode->i_ctime.tv_sec) { fh_lock(fhp); - err = notify_change(dentry, iap); - err = nfserrno(err); + host_err = notify_change(dentry, iap); + err = nfserrno(host_err); fh_unlock(fhp); } if (size_change) @@ -370,7 +372,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -420,11 +422,12 @@ out: return error; } -int +__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_acl *acl) { - int error; + __be32 error; + int host_error; struct dentry *dentry; struct inode *inode; struct posix_acl *pacl = NULL, *dpacl = NULL; @@ -440,20 +443,20 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, if (S_ISDIR(inode->i_mode)) flags = NFS4_ACL_DIR; - error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); - if (error == -EINVAL) { + host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); + if (host_error == -EINVAL) { error = nfserr_attrnotsupp; goto out; - } else if (error < 0) + } else if (host_error < 0) goto out_nfserr; - error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); - if (error < 0) + host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); + if (host_error < 0) goto out_nfserr; if (S_ISDIR(inode->i_mode)) { - error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); - if (error < 0) + host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); + if (host_error < 0) goto out_nfserr; } @@ -464,7 +467,7 @@ out: posix_acl_release(dpacl); return (error); out_nfserr: - error = nfserrno(error); + error = nfserrno(host_error); goto out; } @@ -571,14 +574,14 @@ static struct accessmap nfs3_anyaccess[] = { { 0, 0 } }; -int +__be32 nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported) { struct accessmap *map; struct svc_export *export; struct dentry *dentry; u32 query, result = 0, sresult = 0; - unsigned int error; + __be32 error; error = fh_verify(rqstp, fhp, 0, MAY_NOP); if (error) @@ -598,7 +601,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor query = *access; for (; map->access; map++) { if (map->access & query) { - unsigned int err2; + __be32 err2; sresult |= map->access; @@ -637,13 +640,15 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor * The access argument indicates the type of open (read/write/lock) * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access, struct file **filp) { struct dentry *dentry; struct inode *inode; - int flags = O_RDONLY|O_LARGEFILE, err; + int flags = O_RDONLY|O_LARGEFILE; + __be32 err; + int host_err; /* * If we get here, then the client has already done an "open", @@ -673,10 +678,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, * Check to see if there are any leases on this file. * This may block while leases are broken. */ - err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); - if (err == -EWOULDBLOCK) - err = -ETIMEDOUT; - if (err) /* NOMEM or WOULDBLOCK */ + host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); + if (host_err == -EWOULDBLOCK) + host_err = -ETIMEDOUT; + if (host_err) /* NOMEM or WOULDBLOCK */ goto out_nfserr; if (access & MAY_WRITE) { @@ -689,10 +694,9 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, } *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags); if (IS_ERR(*filp)) - err = PTR_ERR(*filp); + host_err = PTR_ERR(*filp); out_nfserr: - if (err) - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -830,14 +834,15 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset return size; } -static int +static __be32 nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long *count) { struct inode *inode; struct raparms *ra; mm_segment_t oldfs; - int err; + __be32 err; + int host_err; err = nfserr_perm; inode = file->f_dentry->d_inode; @@ -855,12 +860,12 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { rqstp->rq_resused = 1; - err = file->f_op->sendfile(file, &offset, *count, + host_err = file->f_op->sendfile(file, &offset, *count, nfsd_read_actor, rqstp); } else { oldfs = get_fs(); set_fs(KERNEL_DS); - err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); + host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); set_fs(oldfs); } @@ -874,13 +879,13 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, spin_unlock(&rab->pb_lock); } - if (err >= 0) { - nfsdstats.io_read += err; - *count = err; + if (host_err >= 0) { + nfsdstats.io_read += host_err; + *count = host_err; err = 0; fsnotify_access(file->f_dentry); } else - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -895,7 +900,7 @@ static void kill_suid(struct dentry *dentry) mutex_unlock(&dentry->d_inode->i_mutex); } -static int +static __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, int *stablep) @@ -904,7 +909,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; - int err = 0; + __be32 err = 0; + int host_err; int stable = *stablep; #ifdef MSNFS @@ -940,18 +946,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); - err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); + host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); set_fs(oldfs); - if (err >= 0) { + if (host_err >= 0) { nfsdstats.io_write += cnt; fsnotify_modify(file->f_dentry); } /* clear setuid/setgid flag after write */ - if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) + if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) kill_suid(dentry); - if (err >= 0 && stable) { + if (host_err >= 0 && stable) { static ino_t last_ino; static dev_t last_dev; @@ -977,7 +983,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (inode->i_state & I_DIRTY) { dprintk("nfsd: write sync %d\n", current->pid); - err=nfsd_sync(file); + host_err=nfsd_sync(file); } #if 0 wake_up(&inode->i_wait); @@ -987,11 +993,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, last_dev = inode->i_sb->s_dev; } - dprintk("nfsd: write complete err=%d\n", err); - if (err >= 0) + dprintk("nfsd: write complete host_err=%d\n", host_err); + if (host_err >= 0) err = 0; else - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -1001,12 +1007,12 @@ out: * on entry. On return, *count contains the number of bytes actually read. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long *count) { - int err; + __be32 err; if (file) { err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, @@ -1030,12 +1036,12 @@ out: * The stable flag requests synchronous writes. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, int *stablep) { - int err = 0; + __be32 err = 0; if (file) { err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, @@ -1067,12 +1073,12 @@ out: * Unfortunately we cannot lock the file to make sure we return full WCC * data to the client, as locking happens lower down in the filesystem. */ -int +__be32 nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, unsigned long count) { struct file *file; - int err; + __be32 err; if ((u64)count > ~(u64)offset) return nfserr_inval; @@ -1100,14 +1106,15 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, * * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp */ -int +__be32 nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, struct iattr *iap, int type, dev_t rdev, struct svc_fh *resfhp) { struct dentry *dentry, *dchild = NULL; struct inode *dirp; - int err; + __be32 err; + int host_err; err = nfserr_perm; if (!flen) @@ -1134,7 +1141,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ fh_lock_nested(fhp, I_MUTEX_PARENT); dchild = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(dchild); + host_err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); @@ -1173,22 +1180,22 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_perm; switch (type) { case S_IFREG: - err = vfs_create(dirp, dchild, iap->ia_mode, NULL); + host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); break; case S_IFDIR: - err = vfs_mkdir(dirp, dchild, iap->ia_mode); + host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); + host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); break; default: printk("nfsd: bad file type %o in nfsd_create\n", type); - err = -EINVAL; + host_err = -EINVAL; } - if (err < 0) + if (host_err < 0) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) { @@ -1203,7 +1210,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, * directories via NFS. */ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { - int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); + __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); if (err2) err = err2; } @@ -1218,7 +1225,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -1226,7 +1233,7 @@ out_nfserr: /* * NFSv3 version of nfsd_create */ -int +__be32 nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, struct iattr *iap, struct svc_fh *resfhp, int createmode, u32 *verifier, @@ -1234,7 +1241,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, { struct dentry *dentry, *dchild = NULL; struct inode *dirp; - int err; + __be32 err; + int host_err; __u32 v_mtime=0, v_atime=0; int v_mode=0; @@ -1264,7 +1272,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, * Compose the response file handle. */ dchild = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(dchild); + host_err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; @@ -1320,8 +1328,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } - err = vfs_create(dirp, dchild, iap->ia_mode, NULL); - if (err < 0) + host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); + if (host_err < 0) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) { @@ -1350,7 +1358,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, */ set_attr: if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) { - int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); + __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); if (err2) err = err2; } @@ -1368,7 +1376,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } #endif /* CONFIG_NFSD_V3 */ @@ -1378,13 +1386,14 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, * fits into the buffer. On return, it contains the true length. * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) { struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; - int err; + __be32 err; + int host_err; err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); if (err) @@ -1403,18 +1412,18 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) */ oldfs = get_fs(); set_fs(KERNEL_DS); - err = inode->i_op->readlink(dentry, buf, *lenp); + host_err = inode->i_op->readlink(dentry, buf, *lenp); set_fs(oldfs); - if (err < 0) + if (host_err < 0) goto out_nfserr; - *lenp = err; + *lenp = host_err; err = 0; out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -1422,7 +1431,7 @@ out_nfserr: * Create a symlink and look up its inode * N.B. After this call _both_ fhp and resfhp need an fh_put */ -int +__be32 nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, char *path, int plen, @@ -1430,7 +1439,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) { struct dentry *dentry, *dnew; - int err, cerr; + __be32 err, cerr; + int host_err; umode_t mode; err = nfserr_noent; @@ -1446,7 +1456,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, fh_lock(fhp); dentry = fhp->fh_dentry; dnew = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(dnew); + host_err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; @@ -1458,21 +1468,21 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (unlikely(path[plen] != 0)) { char *path_alloced = kmalloc(plen+1, GFP_KERNEL); if (path_alloced == NULL) - err = -ENOMEM; + host_err = -ENOMEM; else { strncpy(path_alloced, path, plen); path_alloced[plen] = 0; - err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); + host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); kfree(path_alloced); } } else - err = vfs_symlink(dentry->d_inode, dnew, path, mode); + host_err = vfs_symlink(dentry->d_inode, dnew, path, mode); - if (!err) + if (!host_err) { if (EX_ISSYNC(fhp->fh_export)) - err = nfsd_sync_dir(dentry); - if (err) - err = nfserrno(err); + host_err = nfsd_sync_dir(dentry); + } + err = nfserrno(host_err); fh_unlock(fhp); cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); @@ -1482,7 +1492,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out; } @@ -1490,13 +1500,14 @@ out_nfserr: * Create a hardlink * N.B. After this call _both_ ffhp and tfhp need an fh_put */ -int +__be32 nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *name, int len, struct svc_fh *tfhp) { struct dentry *ddir, *dnew, *dold; struct inode *dirp, *dest; - int err; + __be32 err; + int host_err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); if (err) @@ -1517,24 +1528,25 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, dirp = ddir->d_inode; dnew = lookup_one_len(name, ddir, len); - err = PTR_ERR(dnew); + host_err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; dold = tfhp->fh_dentry; dest = dold->d_inode; - err = vfs_link(dold, dirp, dnew); - if (!err) { + host_err = vfs_link(dold, dirp, dnew); + if (!host_err) { if (EX_ISSYNC(ffhp->fh_export)) { err = nfserrno(nfsd_sync_dir(ddir)); write_inode_now(dest, 1); } + err = 0; } else { - if (err == -EXDEV && rqstp->rq_vers == 2) + if (host_err == -EXDEV && rqstp->rq_vers == 2) err = nfserr_acces; else - err = nfserrno(err); + err = nfserrno(host_err); } dput(dnew); @@ -1544,7 +1556,7 @@ out: return err; out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); goto out_unlock; } @@ -1552,13 +1564,14 @@ out_nfserr: * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */ -int +__be32 nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, struct svc_fh *tfhp, char *tname, int tlen) { struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap; struct inode *fdir, *tdir; - int err; + __be32 err; + int host_err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); if (err) @@ -1589,22 +1602,22 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, fill_pre_wcc(tfhp); odentry = lookup_one_len(fname, fdentry, flen); - err = PTR_ERR(odentry); + host_err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_nfserr; - err = -ENOENT; + host_err = -ENOENT; if (!odentry->d_inode) goto out_dput_old; - err = -EINVAL; + host_err = -EINVAL; if (odentry == trap) goto out_dput_old; ndentry = lookup_one_len(tname, tdentry, tlen); - err = PTR_ERR(ndentry); + host_err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; - err = -ENOTEMPTY; + host_err = -ENOTEMPTY; if (ndentry == trap) goto out_dput_new; @@ -1612,14 +1625,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && ((atomic_read(&odentry->d_count) > 1) || (atomic_read(&ndentry->d_count) > 1))) { - err = -EPERM; + host_err = -EPERM; } else #endif - err = vfs_rename(fdir, odentry, tdir, ndentry); - if (!err && EX_ISSYNC(tfhp->fh_export)) { - err = nfsd_sync_dir(tdentry); - if (!err) - err = nfsd_sync_dir(fdentry); + host_err = vfs_rename(fdir, odentry, tdir, ndentry); + if (!host_err && EX_ISSYNC(tfhp->fh_export)) { + host_err = nfsd_sync_dir(tdentry); + if (!host_err) + host_err = nfsd_sync_dir(fdentry); } out_dput_new: @@ -1627,8 +1640,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, out_dput_old: dput(odentry); out_nfserr: - if (err) - err = nfserrno(err); + err = nfserrno(host_err); /* we cannot reply on fh_unlock on the two filehandles, * as that would do the wrong thing if the two directories @@ -1647,13 +1659,14 @@ out: * Unlink a file or directory * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, char *fname, int flen) { struct dentry *dentry, *rdentry; struct inode *dirp; - int err; + __be32 err; + int host_err; err = nfserr_acces; if (!flen || isdotent(fname, flen)) @@ -1667,7 +1680,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, dirp = dentry->d_inode; rdentry = lookup_one_len(fname, dentry, flen); - err = PTR_ERR(rdentry); + host_err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; @@ -1684,22 +1697,23 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, #ifdef MSNFS if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && (atomic_read(&rdentry->d_count) > 1)) { - err = -EPERM; + host_err = -EPERM; } else #endif - err = vfs_unlink(dirp, rdentry); + host_err = vfs_unlink(dirp, rdentry); } else { /* It's RMDIR */ - err = vfs_rmdir(dirp, rdentry); + host_err = vfs_rmdir(dirp, rdentry); } dput(rdentry); - if (err == 0 && - EX_ISSYNC(fhp->fh_export)) - err = nfsd_sync_dir(dentry); + if (host_err) + goto out_nfserr; + if (EX_ISSYNC(fhp->fh_export)) + host_err = nfsd_sync_dir(dentry); out_nfserr: - err = nfserrno(err); + err = nfserrno(host_err); out: return err; } @@ -1708,11 +1722,12 @@ out: * Read entries from a directory. * The NFSv3/4 verifier we ignore for now. */ -int +__be32 nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, struct readdir_cd *cdp, encode_dent_fn func) { - int err; + __be32 err; + int host_err; struct file *file; loff_t offset = *offsetp; @@ -1734,10 +1749,10 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, do { cdp->err = nfserr_eof; /* will be cleared on successful read */ - err = vfs_readdir(file, (filldir_t) func, cdp); - } while (err >=0 && cdp->err == nfs_ok); - if (err) - err = nfserrno(err); + host_err = vfs_readdir(file, (filldir_t) func, cdp); + } while (host_err >=0 && cdp->err == nfs_ok); + if (host_err) + err = nfserrno(host_err); else err = cdp->err; *offsetp = vfs_llseek(file, 0, 1); @@ -1754,10 +1769,10 @@ out: * Get file system stats * N.B. After this call fhp needs an fh_put */ -int +__be32 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) { - int err = fh_verify(rqstp, fhp, 0, MAY_NOP); + __be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP); if (!err && vfs_statfs(fhp->fh_dentry,stat)) err = nfserr_io; return err; @@ -1766,7 +1781,7 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) /* * Check for a user's access permissions to this inode. */ -int +__be32 nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) { struct inode *inode = dentry->d_inode; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 2f75160a5824..19a3c83d496e 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -72,57 +72,57 @@ int nfsd_racache_init(int); void nfsd_racache_shutdown(void); int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, struct svc_export **expp); -int nfsd_lookup(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); -int nfsd_setattr(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *, int, time_t); #ifdef CONFIG_NFSD_V4 -int nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, +__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, struct nfs4_acl *); int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); #endif /* CONFIG_NFSD_V4 */ -int nfsd_create(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, int type, dev_t rdev, struct svc_fh *res); #ifdef CONFIG_NFSD_V3 -int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); -int nfsd_create_v3(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); +__be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode, u32 *verifier, int *truncp); -int nfsd_commit(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, loff_t, unsigned long); #endif /* CONFIG_NFSD_V3 */ -int nfsd_open(struct svc_rqst *, struct svc_fh *, int, +__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int, int, struct file **); void nfsd_close(struct file *); -int nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, +__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, loff_t, struct kvec *, int, unsigned long *); -int nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, +__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, loff_t, struct kvec *,int, unsigned long, int *); -int nfsd_readlink(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *, char *, int *); -int nfsd_symlink(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *, char *name, int len, char *path, int plen, struct svc_fh *res, struct iattr *); -int nfsd_link(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_link(struct svc_rqst *, struct svc_fh *, char *, int, struct svc_fh *); -int nfsd_rename(struct svc_rqst *, +__be32 nfsd_rename(struct svc_rqst *, struct svc_fh *, char *, int, struct svc_fh *, char *, int); -int nfsd_remove(struct svc_rqst *, +__be32 nfsd_remove(struct svc_rqst *, struct svc_fh *, char *, int); -int nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, +__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, char *name, int len); int nfsd_truncate(struct svc_rqst *, struct svc_fh *, unsigned long size); -int nfsd_readdir(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, loff_t *, struct readdir_cd *, encode_dent_fn); -int nfsd_statfs(struct svc_rqst *, struct svc_fh *, +__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, struct kstatfs *); int nfsd_notify_change(struct inode *, struct iattr *); -int nfsd_permission(struct svc_export *, struct dentry *, int); +__be32 nfsd_permission(struct svc_export *, struct dentry *, int); int nfsd_sync_dir(struct dentry *dp); #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) -- cgit v1.2.3-71-gd317 From b37ad28bcaa7c486a4ff0fb6c3bdaaacd67b86ce Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:28:59 -0700 Subject: [PATCH] nfsd: nfs4 code returns error values in net-endian Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4proc.c | 82 ++++++++++++------------- fs/nfsd/nfs4recover.c | 14 ++--- fs/nfsd/nfs4state.c | 96 ++++++++++++++--------------- fs/nfsd/nfs4xdr.c | 150 ++++++++++++++++++++++----------------------- include/linux/nfsd/state.h | 10 +-- include/linux/nfsd/xdr4.h | 30 ++++----- 6 files changed, 191 insertions(+), 191 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ca6414248527..63823945f972 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -67,10 +67,10 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src) *dst = *src; } -static int +static __be32 do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode) { - int status; + __be32 status; if (open->op_truncate && !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) @@ -88,11 +88,11 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs return status; } -static int +static __be32 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { struct svc_fh resfh; - int status; + __be32 status; fh_init(&resfh, NFS4_FHSIZE); open->op_truncate = 0; @@ -131,10 +131,10 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o return status; } -static int +static __be32 do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { - int status; + __be32 status; /* Only reclaims from previously confirmed clients are valid */ if ((status = nfs4_check_open_reclaim(&open->op_clientid))) @@ -161,10 +161,10 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ } -static inline int +static inline __be32 nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", (int)open->op_fname.len, open->op_fname.data, open->op_stateowner); @@ -261,7 +261,7 @@ out: /* * filehandle-manipulating ops. */ -static inline int +static inline __be32 nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh) { if (!current_fh->fh_dentry) @@ -271,7 +271,7 @@ nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh) return nfs_ok; } -static inline int +static inline __be32 nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh) { fh_put(current_fh); @@ -280,10 +280,10 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putf return fh_verify(rqstp, current_fh, 0, MAY_NOP); } -static inline int +static inline __be32 nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) { - int status; + __be32 status; fh_put(current_fh); status = exp_pseudoroot(rqstp->rq_client, current_fh, @@ -291,7 +291,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) return status; } -static inline int +static inline __be32 nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh) { if (!save_fh->fh_dentry) @@ -301,7 +301,7 @@ nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh) return nfs_ok; } -static inline int +static inline __be32 nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh) { if (!current_fh->fh_dentry) @@ -314,7 +314,7 @@ nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh) /* * misc nfsv4 ops */ -static inline int +static inline __be32 nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access) { if (access->ac_req_access & ~NFS3_ACCESS_FULL) @@ -324,10 +324,10 @@ nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_acc return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported); } -static inline int +static inline __be32 nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit) { - int status; + __be32 status; u32 *p = (u32 *)commit->co_verf.data; *p++ = nfssvc_boot.tv_sec; @@ -339,11 +339,11 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com return status; } -static int +static __be32 nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create) { struct svc_fh resfh; - int status; + __be32 status; dev_t rdev; fh_init(&resfh, NFS4_FHSIZE); @@ -423,10 +423,10 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre return status; } -static inline int +static inline __be32 nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr) { - int status; + __be32 status; status = fh_verify(rqstp, current_fh, 0, MAY_NOP); if (status) @@ -442,11 +442,11 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ge return nfs_ok; } -static inline int +static inline __be32 nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct svc_fh *save_fh, struct nfsd4_link *link) { - int status = nfserr_nofilehandle; + __be32 status = nfserr_nofilehandle; if (!save_fh->fh_dentry) return status; @@ -456,11 +456,11 @@ nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, return status; } -static int +static __be32 nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) { struct svc_fh tmp_fh; - int ret; + __be32 ret; fh_init(&tmp_fh, NFS4_FHSIZE); if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, @@ -474,16 +474,16 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh); } -static inline int +static inline __be32 nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup) { return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh); } -static inline int +static inline __be32 nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) { - int status; + __be32 status; /* no need to check permission - this will be done in nfsd_read() */ @@ -508,7 +508,7 @@ out: return status; } -static inline int +static inline __be32 nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir) { u64 cookie = readdir->rd_cookie; @@ -531,7 +531,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_re return nfs_ok; } -static inline int +static inline __be32 nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink) { readlink->rl_rqstp = rqstp; @@ -539,10 +539,10 @@ nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_r return nfs_ok; } -static inline int +static inline __be32 nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove) { - int status; + __be32 status; if (nfs4_in_grace()) return nfserr_grace; @@ -556,11 +556,11 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem return status; } -static inline int +static inline __be32 nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct svc_fh *save_fh, struct nfsd4_rename *rename) { - int status = nfserr_nofilehandle; + __be32 status = nfserr_nofilehandle; if (!save_fh->fh_dentry) return status; @@ -589,10 +589,10 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, return status; } -static inline int +static inline __be32 nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) { - int status = nfs_ok; + __be32 status = nfs_ok; if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { nfs4_lock_state(); @@ -614,13 +614,13 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se return status; } -static inline int +static inline __be32 nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) { stateid_t *stateid = &write->wr_stateid; struct file *filp = NULL; u32 *p; - int status = nfs_ok; + __be32 status = nfs_ok; /* no need to check permission - this will be done in nfsd_write() */ @@ -661,12 +661,12 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ * attributes matched. VERIFY is implemented by mapping NFSERR_SAME * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. */ -static int +static __be32 nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify) { __be32 *buf, *p; int count; - int status; + __be32 status; status = fh_verify(rqstp, current_fh, 0, MAY_NOP); if (status) @@ -741,7 +741,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, struct svc_fh *save_fh = NULL; struct nfs4_stateowner *replay_owner = NULL; int slack_space; /* in words, not bytes! */ - int status; + __be32 status; status = nfserr_resource; current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL); diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 1cbd2e4ee122..e9d07704680e 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -83,13 +83,13 @@ md5_to_hex(char *out, char *md5) *out = '\0'; } -int +__be32 nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) { struct xdr_netobj cksum; struct hash_desc desc; struct scatterlist sg[1]; - int status = nfserr_resource; + __be32 status = nfserr_resource; dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", clname->len, clname->data); @@ -193,7 +193,7 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen, struct dentry_list *child; if (name && isdotent(name, namlen)) - return nfs_ok; + return 0; dentry = lookup_one_len(name, parent, namlen); if (IS_ERR(dentry)) return PTR_ERR(dentry); @@ -333,14 +333,14 @@ purge_old(struct dentry *parent, struct dentry *child) int status; if (nfs4_has_reclaimed_state(child->d_name.name)) - return nfs_ok; + return 0; status = nfsd4_clear_clid_dir(parent, child); if (status) printk("failed to remove client recovery directory %s\n", child->d_name.name); /* Keep trying, success or failure: */ - return nfs_ok; + return 0; } void @@ -365,10 +365,10 @@ load_recdir(struct dentry *parent, struct dentry *child) printk("nfsd4: illegal name %s in recovery directory\n", child->d_name.name); /* Keep trying; maybe the others are OK: */ - return nfs_ok; + return 0; } nfs4_client_to_reclaim(child->d_name.name); - return nfs_ok; + return 0; } int diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ebcf226a9e4a..e5ca6d7028df 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -710,7 +710,7 @@ out_err: * as described above. * */ -int +__be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) { u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; @@ -721,7 +721,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) nfs4_verifier clverifier = setclid->se_verf; unsigned int strhashval; struct nfs4_client *conf, *unconf, *new; - int status; + __be32 status; char dname[HEXDIR_LEN]; if (!check_name(clname)) @@ -875,14 +875,14 @@ out: * * NOTE: callback information will be processed here in a future patch */ -int +__be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) { u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct nfs4_client *conf, *unconf; nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; - int status; + __be32 status; if (STALE_CLIENTID(clid)) return nfserr_stale_clientid; @@ -1280,13 +1280,13 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { * Called to check deny when READ with all zero stateid or * WRITE with all zero or all one stateid */ -static int +static __be32 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) { struct inode *ino = current_fh->fh_dentry->d_inode; struct nfs4_file *fp; struct nfs4_stateid *stp; - int ret; + __be32 ret; dprintk("NFSD: nfs4_share_conflict\n"); @@ -1444,7 +1444,7 @@ static struct lock_manager_operations nfsd_lease_mng_ops = { }; -int +__be32 nfsd4_process_open1(struct nfsd4_open *open) { clientid_t *clientid = &open->op_clientid; @@ -1501,7 +1501,7 @@ renew: return nfs_ok; } -static inline int +static inline __be32 nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) { if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) @@ -1522,12 +1522,12 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid) return NULL; } -static int +static __be32 nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_delegation **dp) { int flags; - int status = nfserr_bad_stateid; + __be32 status = nfserr_bad_stateid; *dp = find_delegation_file(fp, &open->op_delegate_stateid); if (*dp == NULL) @@ -1546,11 +1546,11 @@ out: return nfs_ok; } -static int +static __be32 nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) { struct nfs4_stateid *local; - int status = nfserr_share_denied; + __be32 status = nfserr_share_denied; struct nfs4_stateowner *sop = open->op_stateowner; list_for_each_entry(local, &fp->fi_stateids, st_perfile) { @@ -1575,7 +1575,7 @@ nfs4_alloc_stateid(void) return kmem_cache_alloc(stateid_slab, GFP_KERNEL); } -static int +static __be32 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, struct nfs4_delegation *dp, struct svc_fh *cur_fh, int flags) @@ -1590,7 +1590,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, get_file(dp->dl_vfs_file); stp->st_vfs_file = dp->dl_vfs_file; } else { - int status; + __be32 status; status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file); if (status) { @@ -1604,7 +1604,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, return 0; } -static inline int +static inline __be32 nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, struct nfsd4_open *open) { @@ -1619,22 +1619,22 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); } -static int +static __be32 nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) { struct file *filp = stp->st_vfs_file; struct inode *inode = filp->f_dentry->d_inode; unsigned int share_access, new_writer; - int status; + __be32 status; set_access(&share_access, stp->st_access_bmap); new_writer = (~share_access) & open->op_share_access & NFS4_SHARE_ACCESS_WRITE; if (new_writer) { - status = get_write_access(inode); - if (status) - return nfserrno(status); + int err = get_write_access(inode); + if (err) + return nfserrno(err); } status = nfsd4_truncate(rqstp, cur_fh, open); if (status) { @@ -1738,14 +1738,14 @@ out: /* * called with nfs4_lock_state() held. */ -int +__be32 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { struct nfs4_file *fp = NULL; struct inode *ino = current_fh->fh_dentry->d_inode; struct nfs4_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; - int status; + __be32 status; status = nfserr_inval; if (!access_valid(open->op_share_access) @@ -1833,11 +1833,11 @@ static struct work_struct laundromat_work; static void laundromat_main(void *); static DECLARE_WORK(laundromat_work, laundromat_main, NULL); -int +__be32 nfsd4_renew(clientid_t *clid) { struct nfs4_client *clp; - int status; + __be32 status; nfs4_lock_state(); dprintk("process_renew(%08x/%08x): starting\n", @@ -1996,9 +1996,9 @@ access_permit_write(unsigned long access_bmap) } static -int nfs4_check_openmode(struct nfs4_stateid *stp, int flags) +__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) { - int status = nfserr_openmode; + __be32 status = nfserr_openmode; if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) goto out; @@ -2009,7 +2009,7 @@ out: return status; } -static inline int +static inline __be32 check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) { /* Trying to call delegreturn with a special stateid? Yuch: */ @@ -2043,14 +2043,14 @@ io_during_grace_disallowed(struct inode *inode, int flags) /* * Checks for stateid operations */ -int +__be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp) { struct nfs4_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; stateid_t *stidp; struct inode *ino = current_fh->fh_dentry->d_inode; - int status; + __be32 status; dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n", stateid->si_boot, stateid->si_stateownerid, @@ -2125,7 +2125,7 @@ setlkflg (int type) /* * Checks for sequence id mutating operations. */ -static int +static __be32 nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock) { struct nfs4_stateid *stp; @@ -2169,7 +2169,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei clientid_t *lockclid = &lock->v.new.clientid; struct nfs4_client *clp = sop->so_client; int lkflg = 0; - int status; + __be32 status; lkflg = setlkflg(lock->lk_type); @@ -2241,10 +2241,10 @@ check_replay: return nfserr_bad_seqid; } -int +__be32 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; struct nfs4_stateowner *sop; struct nfs4_stateid *stp; @@ -2310,10 +2310,10 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) } } -int +__be32 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; struct nfs4_stateid *stp; unsigned int share_access; @@ -2365,10 +2365,10 @@ out: /* * nfs4_unlock_state() called after encode */ -int +__be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner) { - int status; + __be32 status; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_close on file %.*s\n", @@ -2404,10 +2404,10 @@ out: return status; } -int +__be32 nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr) { - int status; + __be32 status; if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) goto out; @@ -2635,7 +2635,7 @@ check_lock_length(u64 offset, u64 length) /* * LOCK operation */ -int +__be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner) { struct nfs4_stateowner *open_sop = NULL; @@ -2644,7 +2644,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock struct file *filp; struct file_lock file_lock; struct file_lock conflock; - int status = 0; + __be32 status = 0; unsigned int strhashval; dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", @@ -2793,14 +2793,14 @@ out: /* * LOCKT operation */ -int +__be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt) { struct inode *inode; struct file file; struct file_lock file_lock; struct file_lock conflock; - int status; + __be32 status; if (nfs4_in_grace()) return nfserr_grace; @@ -2873,13 +2873,13 @@ out: return status; } -int +__be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner) { struct nfs4_stateid *stp; struct file *filp = NULL; struct file_lock file_lock; - int status; + __be32 status; dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", (long long) locku->lu_offset, @@ -2965,7 +2965,7 @@ out: return status; } -int +__be32 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) { clientid_t *clid = &rlockowner->rl_clientid; @@ -2974,7 +2974,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * struct xdr_netobj *owner = &rlockowner->rl_owner; struct list_head matches; int i; - int status; + __be32 status; dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", clid->cl_boot, clid->cl_id); @@ -3111,7 +3111,7 @@ nfs4_find_reclaim_client(clientid_t *clid) /* * Called from OPEN. Look for clientid in reclaim list. */ -int +__be32 nfs4_check_open_reclaim(clientid_t *clid) { return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 3419d99aeb1a..d7b630f1a9ae 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -68,8 +68,8 @@ #define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL -static int -check_filename(char *str, int len, int err) +static __be32 +check_filename(char *str, int len, __be32 err) { int i; @@ -95,7 +95,7 @@ check_filename(char *str, int len, int err) */ #define DECODE_HEAD \ __be32 *p; \ - int status + __be32 status #define DECODE_TAIL \ status = 0; \ out: \ @@ -217,7 +217,7 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) } -static int +static __be32 nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) { u32 bmlen; @@ -240,7 +240,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr, struct nfs4_acl **acl) { @@ -418,7 +418,7 @@ out_nfserr: goto out; } -static int +static __be32 nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access) { DECODE_HEAD; @@ -429,7 +429,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access DECODE_TAIL; } -static int +static __be32 nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) { DECODE_HEAD; @@ -444,7 +444,7 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) } -static int +static __be32 nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) { DECODE_HEAD; @@ -456,7 +456,7 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit DECODE_TAIL; } -static int +static __be32 nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) { DECODE_HEAD; @@ -496,7 +496,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create DECODE_TAIL; } -static inline int +static inline __be32 nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) { DECODE_HEAD; @@ -508,13 +508,13 @@ nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegretu DECODE_TAIL; } -static inline int +static inline __be32 nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) { return nfsd4_decode_bitmap(argp, getattr->ga_bmval); } -static int +static __be32 nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) { DECODE_HEAD; @@ -529,7 +529,7 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) { DECODE_HEAD; @@ -568,7 +568,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) { DECODE_HEAD; @@ -587,7 +587,7 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) { DECODE_HEAD; @@ -606,7 +606,7 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) { DECODE_HEAD; @@ -621,7 +621,7 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup DECODE_TAIL; } -static int +static __be32 nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) { DECODE_HEAD; @@ -699,7 +699,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) { DECODE_HEAD; @@ -713,7 +713,7 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con DECODE_TAIL; } -static int +static __be32 nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) { DECODE_HEAD; @@ -729,7 +729,7 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d DECODE_TAIL; } -static int +static __be32 nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) { DECODE_HEAD; @@ -744,7 +744,7 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) { DECODE_HEAD; @@ -758,7 +758,7 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) { DECODE_HEAD; @@ -774,7 +774,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read DECODE_TAIL; } -static int +static __be32 nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) { DECODE_HEAD; @@ -789,7 +789,7 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove DECODE_TAIL; } -static int +static __be32 nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) { DECODE_HEAD; @@ -809,7 +809,7 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename DECODE_TAIL; } -static int +static __be32 nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) { DECODE_HEAD; @@ -820,7 +820,7 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) { DECODE_HEAD; @@ -834,7 +834,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta DECODE_TAIL; } -static int +static __be32 nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) { DECODE_HEAD; @@ -859,7 +859,7 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient DECODE_TAIL; } -static int +static __be32 nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) { DECODE_HEAD; @@ -872,7 +872,7 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s } /* Also used for NVERIFY */ -static int +static __be32 nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) { #if 0 @@ -908,7 +908,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify DECODE_TAIL; } -static int +static __be32 nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) { int avail; @@ -959,7 +959,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) DECODE_TAIL; } -static int +static __be32 nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) { DECODE_HEAD; @@ -973,7 +973,7 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel DECODE_TAIL; } -static int +static __be32 nfsd4_decode_compound(struct nfsd4_compoundargs *argp) { DECODE_HEAD; @@ -1234,7 +1234,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) /* Encode as an array of strings the string given with components * seperated @sep. */ -static int nfsd4_encode_components(char sep, char *components, +static __be32 nfsd4_encode_components(char sep, char *components, __be32 **pp, int *buflen) { __be32 *p = *pp; @@ -1271,10 +1271,10 @@ static int nfsd4_encode_components(char sep, char *components, /* * encode a location element of a fs_locations structure */ -static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, +static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, __be32 **pp, int *buflen) { - int status; + __be32 status; __be32 *p = *pp; status = nfsd4_encode_components(':', location->hosts, &p, buflen); @@ -1292,7 +1292,7 @@ static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, * Returned string is safe to use as long as the caller holds a reference * to @exp. */ -static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, u32 *stat) +static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) { struct svc_fh tmp_fh; char *path, *rootpath; @@ -1318,11 +1318,11 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, u32 *sta /* * encode a fs_locations structure */ -static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp, +static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, struct svc_export *exp, __be32 **pp, int *buflen) { - u32 status; + __be32 status; int i; __be32 *p = *pp; struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; @@ -1353,7 +1353,7 @@ static u32 nfs4_ftypes[16] = { NF4SOCK, NF4BAD, NF4LNK, NF4BAD, }; -static int +static __be32 nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, __be32 **p, int *buflen) { @@ -1375,19 +1375,19 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, return 0; } -static inline int +static inline __be32 nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); } -static inline int +static inline __be32 nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) { return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); } -static inline int +static inline __be32 nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, __be32 **p, int *buflen) { @@ -1398,7 +1398,7 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, FATTR4_WORD0_RDATTR_ERROR) #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID -static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) +static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) { /* As per referral draft: */ if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || @@ -1421,7 +1421,7 @@ static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) * @countp is the buffer size in _words_; upon successful return this becomes * replaced with the number of words written. */ -int +__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, struct svc_rqst *rqstp) @@ -1437,7 +1437,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, u64 dummy64; u32 rdattr_err = 0; __be32 *p = buffer; - int status; + __be32 status; int aclsupport = 0; struct nfs4_acl *acl = NULL; @@ -1829,13 +1829,13 @@ out_serverfault: goto out; } -static int +static __be32 nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, const char *name, int namlen, __be32 *p, int *buflen) { struct svc_export *exp = cd->rd_fhp->fh_export; struct dentry *dentry; - int nfserr; + __be32 nfserr; dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); if (IS_ERR(dentry)) @@ -1865,7 +1865,7 @@ out_put: } static __be32 * -nfsd4_encode_rdattr_error(__be32 *p, int buflen, int nfserr) +nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr) { __be32 *attrlenp; @@ -1888,7 +1888,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); int buflen; __be32 *p = cd->buffer; - int nfserr = nfserr_toosmall; + __be32 nfserr = nfserr_toosmall; /* In nfsv4, "." and ".." never make it onto the wire.. */ if (name && isdotent(name, namlen)) { @@ -1944,7 +1944,7 @@ fail: } static void -nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_access *access) +nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) { ENCODE_HEAD; @@ -1957,7 +1957,7 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_acc } static void -nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_close *close) +nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) { ENCODE_SEQID_OP_HEAD; @@ -1972,7 +1972,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_clos static void -nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_commit *commit) +nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) { ENCODE_HEAD; @@ -1984,7 +1984,7 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_com } static void -nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_create *create) +nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) { ENCODE_HEAD; @@ -1998,8 +1998,8 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_cre } } -static int -nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_getattr *getattr) +static __be32 +nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) { struct svc_fh *fhp = getattr->ga_fhp; int buflen; @@ -2017,7 +2017,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ge } static void -nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fhp) +nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp) { unsigned int len; ENCODE_HEAD; @@ -2057,7 +2057,7 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie } static void -nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock) +nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) { ENCODE_SEQID_OP_HEAD; @@ -2073,14 +2073,14 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock } static void -nfsd4_encode_lockt(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lockt *lockt) +nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) { if (nfserr == nfserr_denied) nfsd4_encode_lock_denied(resp, &lockt->lt_denied); } static void -nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_locku *locku) +nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) { ENCODE_SEQID_OP_HEAD; @@ -2096,7 +2096,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock static void -nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link) +nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) { ENCODE_HEAD; @@ -2109,7 +2109,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link static void -nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open *open) +nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) { ENCODE_SEQID_OP_HEAD; @@ -2174,7 +2174,7 @@ out: } static void -nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_confirm *oc) +nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) { ENCODE_SEQID_OP_HEAD; @@ -2189,7 +2189,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfs } static void -nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_downgrade *od) +nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) { ENCODE_SEQID_OP_HEAD; @@ -2203,8 +2203,8 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct n ENCODE_SEQID_OP_TAIL(od->od_stateowner); } -static int -nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, +static __be32 +nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read) { u32 eof; @@ -2268,8 +2268,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, return 0; } -static int -nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readlink *readlink) +static __be32 +nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) { int maxcount; char *page; @@ -2316,8 +2316,8 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r return 0; } -static int -nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir) +static __be32 +nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir) { int maxcount; loff_t offset; @@ -2396,7 +2396,7 @@ err_no_verf: } static void -nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_remove *remove) +nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) { ENCODE_HEAD; @@ -2408,7 +2408,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rem } static void -nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rename *rename) +nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) { ENCODE_HEAD; @@ -2425,7 +2425,7 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ren * regardless of the error status. */ static void -nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setattr *setattr) +nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) { ENCODE_HEAD; @@ -2444,7 +2444,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_se } static void -nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setclientid *scd) +nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) { ENCODE_HEAD; @@ -2463,7 +2463,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd } static void -nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_write *write) +nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) { ENCODE_HEAD; @@ -2641,7 +2641,7 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) int nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) { - int status; + __be32 status; args->p = p; args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 8bf23cf8b603..a597e2e72469 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -164,7 +164,7 @@ update_stateid(stateid_t *stateid) * is cached. */ struct nfs4_replay { - u32 rp_status; + __be32 rp_status; unsigned int rp_buflen; char *rp_buf; unsigned intrp_allocated; @@ -273,19 +273,19 @@ struct nfs4_stateid { ((err) != nfserr_stale_stateid) && \ ((err) != nfserr_bad_stateid)) -extern int nfsd4_renew(clientid_t *clid); -extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh, +extern __be32 nfsd4_renew(clientid_t *clid); +extern __be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filp); extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); extern int nfs4_in_grace(void); -extern int nfs4_check_open_reclaim(clientid_t *clid); +extern __be32 nfs4_check_open_reclaim(clientid_t *clid); extern void put_nfs4_client(struct nfs4_client *clp); extern void nfs4_free_stateowner(struct kref *kref); extern void nfsd4_probe_callback(struct nfs4_client *clp); extern void nfsd4_cb_recall(struct nfs4_delegation *dp); extern void nfs4_put_delegation(struct nfs4_delegation *dp); -extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); +extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); extern void nfsd4_init_recdir(char *recdir_name); extern int nfsd4_recdir_load(void); extern void nfsd4_shutdown_recdir(void); diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 003193fe6fc6..45ca01b5f844 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -334,7 +334,7 @@ struct nfsd4_write { struct nfsd4_op { int opnum; - int status; + __be32 status; union { struct nfsd4_access access; struct nfsd4_close close; @@ -426,38 +426,38 @@ int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, struct nfsd4_compoundres *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); -int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, - struct dentry *dentry, u32 *buffer, int *countp, +__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, + struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, struct svc_rqst *); -extern int nfsd4_setclientid(struct svc_rqst *rqstp, +extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid); -extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, +extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm); -extern int nfsd4_process_open1(struct nfsd4_open *open); -extern int nfsd4_process_open2(struct svc_rqst *rqstp, +extern __be32 nfsd4_process_open1(struct nfsd4_open *open); +extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open); -extern int nfsd4_open_confirm(struct svc_rqst *rqstp, +extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **); -extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner); -extern int nfsd4_open_downgrade(struct svc_rqst *rqstp, +extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner); -extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner); -extern int nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt); -extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, +extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner); -extern int +extern __be32 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner); extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *); -extern int nfsd4_delegreturn(struct svc_rqst *rqstp, +extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr); #endif -- cgit v1.2.3-71-gd317 From c7afef1f963bec198b186cc34b9e8c9b9ce2e266 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:02 -0700 Subject: [PATCH] nfsd: misc endianness annotations Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/export.c | 4 ++-- fs/nfsd/lockd.c | 2 +- fs/nfsd/nfs4callback.c | 2 +- fs/nfsd/nfs4state.c | 4 ++-- fs/nfsd/nfscache.c | 8 ++++---- fs/nfsd/nfssvc.c | 2 +- include/linux/nfsd/cache.h | 6 +++--- include/linux/nfsd/export.h | 2 +- include/linux/nfsd/nfsd.h | 2 +- include/linux/nfsd/nfsfh.h | 2 +- include/linux/nfsd/state.h | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index e13fa23bd108..f37df46d2eaa 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1148,12 +1148,12 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, * for a given NFSv4 client. The root is defined to be the * export point with fsid==0 */ -int +__be32 exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, struct cache_req *creq) { struct svc_export *exp; - int rv; + __be32 rv; u32 fsidv[2]; mk_fsid_v1(fsidv, 0); diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 9b9e7e127c03..11fdaf7721b4 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -25,7 +25,7 @@ static u32 nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) { - u32 nfserr; + __be32 nfserr; struct svc_fh fh; /* must initialize before using! but maxsize doesn't matter */ diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 8497ed4862b2..f57655a7a2b6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -461,7 +461,7 @@ nfs4_cb_null(struct rpc_task *task, void *dummy) { struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; struct nfs4_callback *cb = &clp->cl_callback; - u32 addr = htonl(cb->cb_addr); + __be32 addr = htonl(cb->cb_addr); dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ae1d47715b90..2e468c9e64d9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -713,7 +713,7 @@ out_err: __be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) { - u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; + __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct xdr_netobj clname = { .len = setclid->se_namelen, .data = setclid->se_name, @@ -878,7 +878,7 @@ out: __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) { - u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; + __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct nfs4_client *conf, *unconf; nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index fdf7cf3dfadc..6100bbe27432 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -29,7 +29,7 @@ */ #define CACHESIZE 1024 #define HASHSIZE 64 -#define REQHASH(xid) ((((xid) >> 24) ^ (xid)) & (HASHSIZE-1)) +#define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1)) static struct hlist_head * hash_list; static struct list_head lru_head; @@ -127,8 +127,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) struct hlist_node *hn; struct hlist_head *rh; struct svc_cacherep *rp; - u32 xid = rqstp->rq_xid, - proto = rqstp->rq_prot, + __be32 xid = rqstp->rq_xid; + u32 proto = rqstp->rq_prot, vers = rqstp->rq_vers, proc = rqstp->rq_proc; unsigned long age; @@ -258,7 +258,7 @@ found_entry: * In this case, nfsd_cache_update is called with statp == NULL. */ void -nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, u32 *statp) +nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) { struct svc_cacherep *rp; struct kvec *resv = &rqstp->rq_res.head[0], *cachv; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 8067118b1c0c..0aaccb03bf76 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -491,7 +491,7 @@ out: } int -nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) +nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) { struct svc_procedure *proc; kxdrproc_t xdr; diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h index c3a3557c2a5b..007480cd6a60 100644 --- a/include/linux/nfsd/cache.h +++ b/include/linux/nfsd/cache.h @@ -26,14 +26,14 @@ struct svc_cacherep { c_type, /* status, buffer */ c_secure : 1; /* req came from port < 1024 */ struct sockaddr_in c_addr; - u32 c_xid; + __be32 c_xid; u32 c_prot; u32 c_proc; u32 c_vers; unsigned long c_timestamp; union { struct kvec u_vec; - u32 u_status; + __be32 u_status; } c_u; }; @@ -75,7 +75,7 @@ enum { void nfsd_cache_init(void); void nfsd_cache_shutdown(void); int nfsd_cache_lookup(struct svc_rqst *, int); -void nfsd_cache_update(struct svc_rqst *, int, u32 *); +void nfsd_cache_update(struct svc_rqst *, int, __be32 *); #endif /* __KERNEL__ */ #endif /* NFSCACHE_H */ diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 27666f5b8b53..045e38cdbe64 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -117,7 +117,7 @@ struct svc_export * exp_parent(struct auth_domain *clp, struct cache_req *reqp); int exp_rootfh(struct auth_domain *, char *path, struct knfsd_fh *, int maxsize); -int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); +__be32 exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); __be32 nfserrno(int errno); extern struct cache_detail svc_export_cache; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 19a3c83d496e..68d29b66c6e2 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -64,7 +64,7 @@ extern struct svc_serv *nfsd_serv; * Function prototypes. */ int nfsd_svc(unsigned short port, int nrservs); -int nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp); +int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); /* nfsd/vfs.c */ int fh_lock_parent(struct svc_fh *, struct dentry *); diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 749bad1ca16f..f3b51d62ec7d 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -157,7 +157,7 @@ typedef struct svc_fh { __u64 fh_post_size; /* i_size */ unsigned long fh_post_blocks; /* i_blocks */ unsigned long fh_post_blksize;/* i_blksize */ - __u32 fh_post_rdev[2];/* i_rdev */ + __be32 fh_post_rdev[2];/* i_rdev */ struct timespec fh_post_atime; /* i_atime */ struct timespec fh_post_mtime; /* i_mtime */ struct timespec fh_post_ctime; /* i_ctime */ diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index a597e2e72469..c3673f487e84 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -125,7 +125,7 @@ struct nfs4_client { char cl_recdir[HEXDIR_LEN]; /* recovery dir */ nfs4_verifier cl_verifier; /* generated by client */ time_t cl_time; /* time of last lease renewal */ - u32 cl_addr; /* client ipaddress */ + __be32 cl_addr; /* client ipaddress */ struct svc_cred cl_cred; /* setclientid principal */ clientid_t cl_clientid; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */ -- cgit v1.2.3-71-gd317 From a90b061c0bf712961cea40d9c916b300073d12e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Oct 2006 23:29:03 -0700 Subject: [PATCH] nfsd: nfs_replay_me We are using NFS_REPLAY_ME as a special error value that is never leaked to clients. That works fine; the only problem is mixing host- and network- endian values in the same objects. Network-endian equivalent would work just as fine; switch to it. Signed-off-by: Al Viro Acked-by: Trond Myklebust Acked-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs4proc.c | 6 +++--- fs/nfsd/nfs4state.c | 4 ++-- include/linux/nfsd/nfsd.h | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 63823945f972..0a7bbdc4a10a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -177,7 +177,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open /* check seqid for replay. set nfs4_owner */ status = nfsd4_process_open1(open); - if (status == NFSERR_REPLAY_ME) { + if (status == nfserr_replay_me) { struct nfs4_replay *rp = &open->op_stateowner->so_replay; fh_put(current_fh); current_fh->fh_handle.fh_size = rp->rp_openfh_len; @@ -188,7 +188,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open dprintk("nfsd4_open: replay failed" " restoring previous filehandle\n"); else - status = NFSERR_REPLAY_ME; + status = nfserr_replay_me; } if (status) goto out; @@ -937,7 +937,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, } encode_op: - if (op->status == NFSERR_REPLAY_ME) { + if (op->status == nfserr_replay_me) { op->replay = &replay_owner->so_replay; nfsd4_encode_replay(resp, op); status = op->status = op->replay->rp_status; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2e468c9e64d9..293b6495829f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1477,7 +1477,7 @@ nfsd4_process_open1(struct nfsd4_open *open) } if (open->op_seqid == sop->so_seqid - 1) { if (sop->so_replay.rp_buflen) - return NFSERR_REPLAY_ME; + return nfserr_replay_me; /* The original OPEN failed so spectacularly * that we don't even have replay data saved! * Therefore, we have no choice but to continue @@ -2233,7 +2233,7 @@ check_replay: if (seqid == sop->so_seqid - 1) { dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); /* indicate replay to calling function */ - return NFSERR_REPLAY_ME; + return nfserr_replay_me; } printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", sop->so_seqid, seqid); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 68d29b66c6e2..eb231143d579 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -238,6 +238,7 @@ void nfsd_lockd_shutdown(void); #define nfserr_badname __constant_htonl(NFSERR_BADNAME) #define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN) #define nfserr_locked __constant_htonl(NFSERR_LOCKED) +#define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME) /* error codes for internal use */ /* if a request fails due to kmalloc failure, it gets dropped. -- cgit v1.2.3-71-gd317 From 690a973f48b6ba2954465992c08e65059c8374fe Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Sat, 21 Oct 2006 18:37:01 +0200 Subject: [PATCH] x86-64: Speed up dwarf2 unwinder This changes the dwarf2 unwinder to do a binary search for CIEs instead of a linear work. The linker is unfortunately not able to build a proper lookup table at link time, instead it creates one at runtime as soon as the bootmem allocator is usable (so you'll continue using the linear lookup for the first [hopefully] few calls). The code should be ready to utilize a build-time created table once a fixed linker becomes available. Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen --- Makefile | 1 + include/asm-generic/vmlinux.lds.h | 16 ++ include/linux/unwind.h | 2 + init/main.c | 1 + kernel/unwind.c | 318 +++++++++++++++++++++++++++++++++----- 5 files changed, 299 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/Makefile b/Makefile index 62a1343cf327..389ff0cca9a7 100644 --- a/Makefile +++ b/Makefile @@ -499,6 +499,7 @@ endif ifdef CONFIG_UNWIND_INFO CFLAGS += -fasynchronous-unwind-tables +LDFLAGS_vmlinux += --eh-frame-hdr endif ifdef CONFIG_DEBUG_INFO diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 69240b52f8e1..9d0d11c180d9 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -125,6 +125,10 @@ *(__param) \ VMLINUX_SYMBOL(__stop___param) = .; \ } \ + \ + /* Unwind data binary search table */ \ + EH_FRAME_HDR \ + \ __end_rodata = .; \ . = ALIGN(4096); @@ -157,6 +161,18 @@ *(.kprobes.text) \ VMLINUX_SYMBOL(__kprobes_text_end) = .; +#ifdef CONFIG_STACK_UNWIND + /* Unwind data binary search table */ +#define EH_FRAME_HDR \ + .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_unwind_hdr) = .; \ + *(.eh_frame_hdr) \ + VMLINUX_SYMBOL(__end_unwind_hdr) = .; \ + } +#else +#define EH_FRAME_HDR +#endif + /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ diff --git a/include/linux/unwind.h b/include/linux/unwind.h index 73e1751d03dd..749928c161fb 100644 --- a/include/linux/unwind.h +++ b/include/linux/unwind.h @@ -26,6 +26,7 @@ struct module; * Initialize unwind support. */ extern void unwind_init(void); +extern void unwind_setup(void); #ifdef CONFIG_MODULES @@ -73,6 +74,7 @@ extern int unwind_to_user(struct unwind_frame_info *); struct unwind_frame_info {}; static inline void unwind_init(void) {} +static inline void unwind_setup(void) {} #ifdef CONFIG_MODULES diff --git a/init/main.c b/init/main.c index ee123243fb53..36f608a7cfba 100644 --- a/init/main.c +++ b/init/main.c @@ -503,6 +503,7 @@ asmlinkage void __init start_kernel(void) printk(KERN_NOTICE); printk(linux_banner); setup_arch(&command_line); + unwind_setup(); setup_per_cpu_areas(); smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ diff --git a/kernel/unwind.c b/kernel/unwind.c index 2e2368607aab..f7e50d16dbf6 100644 --- a/kernel/unwind.c +++ b/kernel/unwind.c @@ -11,13 +11,15 @@ #include #include -#include +#include +#include #include #include #include #include extern char __start_unwind[], __end_unwind[]; +extern const u8 __start_unwind_hdr[], __end_unwind_hdr[]; #define MAX_STACK_DEPTH 8 @@ -100,6 +102,8 @@ static struct unwind_table { } core, init; const void *address; unsigned long size; + const unsigned char *header; + unsigned long hdrsz; struct unwind_table *link; const char *name; } root_table; @@ -145,6 +149,10 @@ static struct unwind_table *find_table(unsigned long pc) return table; } +static unsigned long read_pointer(const u8 **pLoc, + const void *end, + signed ptrType); + static void init_unwind_table(struct unwind_table *table, const char *name, const void *core_start, @@ -152,14 +160,30 @@ static void init_unwind_table(struct unwind_table *table, const void *init_start, unsigned long init_size, const void *table_start, - unsigned long table_size) + unsigned long table_size, + const u8 *header_start, + unsigned long header_size) { + const u8 *ptr = header_start + 4; + const u8 *end = header_start + header_size; + table->core.pc = (unsigned long)core_start; table->core.range = core_size; table->init.pc = (unsigned long)init_start; table->init.range = init_size; table->address = table_start; table->size = table_size; + /* See if the linker provided table looks valid. */ + if (header_size <= 4 + || header_start[0] != 1 + || (void *)read_pointer(&ptr, end, header_start[1]) != table_start + || header_start[2] == DW_EH_PE_omit + || read_pointer(&ptr, end, header_start[2]) <= 0 + || header_start[3] == DW_EH_PE_omit) + header_start = NULL; + table->hdrsz = header_size; + smp_wmb(); + table->header = header_start; table->link = NULL; table->name = name; } @@ -169,7 +193,143 @@ void __init unwind_init(void) init_unwind_table(&root_table, "kernel", _text, _end - _text, NULL, 0, - __start_unwind, __end_unwind - __start_unwind); + __start_unwind, __end_unwind - __start_unwind, + __start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr); +} + +static const u32 bad_cie, not_fde; +static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *); +static signed fde_pointer_type(const u32 *cie); + +struct eh_frame_hdr_table_entry { + unsigned long start, fde; +}; + +static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2) +{ + const struct eh_frame_hdr_table_entry *e1 = p1; + const struct eh_frame_hdr_table_entry *e2 = p2; + + return (e1->start > e2->start) - (e1->start < e2->start); +} + +static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size) +{ + struct eh_frame_hdr_table_entry *e1 = p1; + struct eh_frame_hdr_table_entry *e2 = p2; + unsigned long v; + + v = e1->start; + e1->start = e2->start; + e2->start = v; + v = e1->fde; + e1->fde = e2->fde; + e2->fde = v; +} + +static void __init setup_unwind_table(struct unwind_table *table, + void *(*alloc)(unsigned long)) +{ + const u8 *ptr; + unsigned long tableSize = table->size, hdrSize; + unsigned n; + const u32 *fde; + struct { + u8 version; + u8 eh_frame_ptr_enc; + u8 fde_count_enc; + u8 table_enc; + unsigned long eh_frame_ptr; + unsigned int fde_count; + struct eh_frame_hdr_table_entry table[]; + } __attribute__((__packed__)) *header; + + if (table->header) + return; + + if (table->hdrsz) + printk(KERN_WARNING ".eh_frame_hdr for '%s' present but unusable\n", + table->name); + + if (tableSize & (sizeof(*fde) - 1)) + return; + + for (fde = table->address, n = 0; + tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; + tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { + const u32 *cie = cie_for_fde(fde, table); + signed ptrType; + + if (cie == ¬_fde) + continue; + if (cie == NULL + || cie == &bad_cie + || (ptrType = fde_pointer_type(cie)) < 0) + return; + ptr = (const u8 *)(fde + 2); + if (!read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType)) + return; + ++n; + } + + if (tableSize || !n) + return; + + hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) + + 2 * n * sizeof(unsigned long); + header = alloc(hdrSize); + if (!header) + return; + header->version = 1; + header->eh_frame_ptr_enc = DW_EH_PE_abs|DW_EH_PE_native; + header->fde_count_enc = DW_EH_PE_abs|DW_EH_PE_data4; + header->table_enc = DW_EH_PE_abs|DW_EH_PE_native; + put_unaligned((unsigned long)table->address, &header->eh_frame_ptr); + BUILD_BUG_ON(offsetof(typeof(*header), fde_count) + % __alignof(typeof(header->fde_count))); + header->fde_count = n; + + BUILD_BUG_ON(offsetof(typeof(*header), table) + % __alignof(typeof(*header->table))); + for (fde = table->address, tableSize = table->size, n = 0; + tableSize; + tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { + const u32 *cie = fde + 1 - fde[1] / sizeof(*fde); + + if (!fde[1]) + continue; /* this is a CIE */ + ptr = (const u8 *)(fde + 2); + header->table[n].start = read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + fde_pointer_type(cie)); + header->table[n].fde = (unsigned long)fde; + ++n; + } + WARN_ON(n != header->fde_count); + + sort(header->table, + n, + sizeof(*header->table), + cmp_eh_frame_hdr_table_entries, + swap_eh_frame_hdr_table_entries); + + table->hdrsz = hdrSize; + smp_wmb(); + table->header = (const void *)header; +} + +static void *__init balloc(unsigned long sz) +{ + return __alloc_bootmem_nopanic(sz, + sizeof(unsigned int), + __pa(MAX_DMA_ADDRESS)); +} + +void __init unwind_setup(void) +{ + setup_unwind_table(&root_table, balloc); } #ifdef CONFIG_MODULES @@ -193,7 +353,8 @@ void *unwind_add_table(struct module *module, init_unwind_table(table, module->name, module->module_core, module->core_size, module->module_init, module->init_size, - table_start, table_size); + table_start, table_size, + NULL, 0); if (last_table) last_table->link = table; @@ -303,6 +464,26 @@ static sleb128_t get_sleb128(const u8 **pcur, const u8 *end) return value; } +static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table) +{ + const u32 *cie; + + if (!*fde || (*fde & (sizeof(*fde) - 1))) + return &bad_cie; + if (!fde[1]) + return ¬_fde; /* this is a CIE */ + if ((fde[1] & (sizeof(*fde) - 1)) + || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) + return NULL; /* this is not a valid FDE */ + cie = fde + 1 - fde[1] / sizeof(*fde); + if (*cie <= sizeof(*cie) + 4 + || *cie >= fde[1] - sizeof(*fde) + || (*cie & (sizeof(*cie) - 1)) + || cie[1]) + return NULL; /* this is not a (valid) CIE */ + return cie; +} + static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrType) @@ -610,49 +791,108 @@ int unwind(struct unwind_frame_info *frame) unsigned i; signed ptrType = -1; uleb128_t retAddrReg = 0; - struct unwind_table *table; + const struct unwind_table *table; struct unwind_state state; if (UNW_PC(frame) == 0) return -EINVAL; if ((table = find_table(pc)) != NULL && !(table->size & (sizeof(*fde) - 1))) { - unsigned long tableSize = table->size; - - for (fde = table->address; - tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; - tableSize -= sizeof(*fde) + *fde, - fde += 1 + *fde / sizeof(*fde)) { - if (!*fde || (*fde & (sizeof(*fde) - 1))) - break; - if (!fde[1]) - continue; /* this is a CIE */ - if ((fde[1] & (sizeof(*fde) - 1)) - || fde[1] > (unsigned long)(fde + 1) - - (unsigned long)table->address) - continue; /* this is not a valid FDE */ - cie = fde + 1 - fde[1] / sizeof(*fde); - if (*cie <= sizeof(*cie) + 4 - || *cie >= fde[1] - sizeof(*fde) - || (*cie & (sizeof(*cie) - 1)) - || cie[1] - || (ptrType = fde_pointer_type(cie)) < 0) { - cie = NULL; /* this is not a (valid) CIE */ - continue; + const u8 *hdr = table->header; + unsigned long tableSize; + + smp_rmb(); + if (hdr && hdr[0] == 1) { + switch(hdr[3] & DW_EH_PE_FORM) { + case DW_EH_PE_native: tableSize = sizeof(unsigned long); break; + case DW_EH_PE_data2: tableSize = 2; break; + case DW_EH_PE_data4: tableSize = 4; break; + case DW_EH_PE_data8: tableSize = 8; break; + default: tableSize = 0; break; + } + ptr = hdr + 4; + end = hdr + table->hdrsz; + if (tableSize + && read_pointer(&ptr, end, hdr[1]) + == (unsigned long)table->address + && (i = read_pointer(&ptr, end, hdr[2])) > 0 + && i == (end - ptr) / (2 * tableSize) + && !((end - ptr) % (2 * tableSize))) { + do { + const u8 *cur = ptr + (i / 2) * (2 * tableSize); + + startLoc = read_pointer(&cur, + cur + tableSize, + hdr[3]); + if (pc < startLoc) + i /= 2; + else { + ptr = cur - tableSize; + i = (i + 1) / 2; + } + } while (startLoc && i > 1); + if (i == 1 + && (startLoc = read_pointer(&ptr, + ptr + tableSize, + hdr[3])) != 0 + && pc >= startLoc) + fde = (void *)read_pointer(&ptr, + ptr + tableSize, + hdr[3]); } + } + + if (fde != NULL) { + cie = cie_for_fde(fde, table); ptr = (const u8 *)(fde + 2); - startLoc = read_pointer(&ptr, - (const u8 *)(fde + 1) + *fde, - ptrType); - endLoc = startLoc - + read_pointer(&ptr, - (const u8 *)(fde + 1) + *fde, - ptrType & DW_EH_PE_indirect - ? ptrType - : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); - if (pc >= startLoc && pc < endLoc) - break; - cie = NULL; + if(cie != NULL + && cie != &bad_cie + && cie != ¬_fde + && (ptrType = fde_pointer_type(cie)) >= 0 + && read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType) == startLoc) { + if (!(ptrType & DW_EH_PE_indirect)) + ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; + endLoc = startLoc + + read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType); + if(pc >= endLoc) + fde = NULL; + } else + fde = NULL; + } + if (fde == NULL) { + for (fde = table->address, tableSize = table->size; + cie = NULL, tableSize > sizeof(*fde) + && tableSize - sizeof(*fde) >= *fde; + tableSize -= sizeof(*fde) + *fde, + fde += 1 + *fde / sizeof(*fde)) { + cie = cie_for_fde(fde, table); + if (cie == &bad_cie) { + cie = NULL; + break; + } + if (cie == NULL + || cie == ¬_fde + || (ptrType = fde_pointer_type(cie)) < 0) + continue; + ptr = (const u8 *)(fde + 2); + startLoc = read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType); + if (!startLoc) + continue; + if (!(ptrType & DW_EH_PE_indirect)) + ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; + endLoc = startLoc + + read_pointer(&ptr, + (const u8 *)(fde + 1) + *fde, + ptrType); + if (pc >= startLoc && pc < endLoc) + break; + } } } if (cie != NULL) { -- cgit v1.2.3-71-gd317 From a1bae67243512ca30ceda48e3e24e25b543f8ab7 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 21 Oct 2006 18:37:02 +0200 Subject: [PATCH] i386: Disable nmi watchdog on all ThinkPads Even newer Thinkpads have bugs in SMM code that causes hangs with NMI watchdog. Signed-off-by: Andi Kleen --- arch/i386/kernel/nmi.c | 10 +++++----- drivers/firmware/dmi_scan.c | 20 ++++++++++++++++++++ include/linux/dmi.h | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 3e8e3adb0489..eaafe233a5da 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -219,11 +219,11 @@ static int __init check_nmi_watchdog(void) int cpu; /* Enable NMI watchdog for newer systems. - Actually it should be safe for most systems before 2004 too except - for some IBM systems that corrupt registers when NMI happens - during SMM. Unfortunately we don't have more exact information - on these and use this coarse check. */ - if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004) + Probably safe on most older systems too, but let's be careful. + IBM ThinkPads use INT10 inside SMM and that allows early NMI inside SMM + which hangs the system. Disable watchdog for all thinkpads */ + if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004 && + !dmi_name_in_vendors("ThinkPad")) nmi_watchdog = NMI_LOCAL_APIC; if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DEFAULT)) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index b8b596d5778d..37deee6c0c1c 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -326,6 +326,26 @@ char *dmi_get_system_info(int field) } EXPORT_SYMBOL(dmi_get_system_info); + +/** + * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. + * @str: Case sensitive Name + */ +int dmi_name_in_vendors(char *str) +{ + static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, + DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE }; + int i; + for (i = 0; fields[i] != DMI_NONE; i++) { + int f = fields[i]; + if (dmi_ident[f] && strstr(dmi_ident[f], str)) + return 1; + } + return 0; +} +EXPORT_SYMBOL(dmi_name_in_vendors); + /** * dmi_find_device - find onboard device by type/name * @type: device type or %DMI_DEV_TYPE_ANY to match all device types diff --git a/include/linux/dmi.h b/include/linux/dmi.h index 38dc403be70b..904bf3d2d90b 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -69,6 +69,7 @@ extern struct dmi_device * dmi_find_device(int type, const char *name, struct dmi_device *from); extern void dmi_scan_machine(void); extern int dmi_get_year(int field); +extern int dmi_name_in_vendors(char *str); #else @@ -77,6 +78,7 @@ static inline char * dmi_get_system_info(int field) { return NULL; } static inline struct dmi_device * dmi_find_device(int type, const char *name, struct dmi_device *from) { return NULL; } static inline int dmi_get_year(int year) { return 0; } +static inline int dmi_name_in_vendors(char *s) { return 0; } #endif -- cgit v1.2.3-71-gd317 From 3343571d9f88a0de542d33aea9ab881f00ff866d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 19 Oct 2006 14:44:53 +0900 Subject: [PATCH] libata: typo fix Typo fix in commment. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index d0a7ad5ed518..b03d5a340dc8 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -143,7 +143,7 @@ enum { ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ - ATA_DFLAG_NCQ_OFF = (1 << 9), /* devied limited to non-NCQ mode */ + ATA_DFLAG_NCQ_OFF = (1 << 9), /* device limited to non-NCQ mode */ ATA_DFLAG_SUSPENDED = (1 << 10), /* device suspended */ ATA_DFLAG_INIT_MASK = (1 << 16) - 1, -- cgit v1.2.3-71-gd317 From da3ed32fe568148ede256975d40825ffcdac767b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 21 Oct 2006 10:24:08 -0700 Subject: [PATCH] md: add another COMPAT_IOCTL for md .. so that you can use bitmaps with 32bit userspace on a 64 bit kernel. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compat_ioctl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index cfdb4f6a89d4..c26c3adcfacf 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -131,6 +131,7 @@ COMPATIBLE_IOCTL(RUN_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) +COMPATIBLE_IOCTL(GET_BITMAP_FILE) ULONG_IOCTL(SET_BITMAP_FILE) /* DM */ COMPATIBLE_IOCTL(DM_VERSION_32) -- cgit v1.2.3-71-gd317 From 1c05b4bc22cd640d3a534bd2851a8413d5df3709 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 21 Oct 2006 10:24:08 -0700 Subject: [PATCH] md: endian annotation for v1 superblock access Includes a couple of bugfixes found by sparse. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 13 ++++++----- include/linux/raid/md_p.h | 56 +++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index f7f19088f3be..7daa7b1e145f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -974,12 +974,13 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) * version 1 superblock */ -static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) +static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb) { - unsigned int disk_csum, csum; + __le32 disk_csum; + u32 csum; unsigned long long newcsum; int size = 256 + le32_to_cpu(sb->max_dev)*2; - unsigned int *isuper = (unsigned int*)sb; + __le32 *isuper = (__le32*)sb; int i; disk_csum = sb->sb_csum; @@ -989,7 +990,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) newcsum += le32_to_cpu(*isuper++); if (size == 2) - newcsum += le16_to_cpu(*(unsigned short*) isuper); + newcsum += le16_to_cpu(*(__le16*) isuper); csum = (newcsum & 0xffffffff) + (newcsum >> 32); sb->sb_csum = disk_csum; @@ -1106,7 +1107,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) if (le32_to_cpu(sb->chunksize)) rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1); - if (le32_to_cpu(sb->size) > rdev->size*2) + if (le64_to_cpu(sb->size) > rdev->size*2) return -EINVAL; return ret; } @@ -1228,7 +1229,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) else sb->resync_offset = cpu_to_le64(0); - sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors); + sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors)); sb->raid_disks = cpu_to_le32(mddev->raid_disks); sb->size = cpu_to_le64(mddev->size<<1); diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index b6ebc69bae54..3f2cd98c508b 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h @@ -206,52 +206,52 @@ static inline __u64 md_event(mdp_super_t *sb) { */ struct mdp_superblock_1 { /* constant array information - 128 bytes */ - __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ - __u32 major_version; /* 1 */ - __u32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */ - __u32 pad0; /* always set to 0 when writing */ + __le32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ + __le32 major_version; /* 1 */ + __le32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */ + __le32 pad0; /* always set to 0 when writing */ __u8 set_uuid[16]; /* user-space generated. */ char set_name[32]; /* set and interpreted by user-space */ - __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ - __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ - __u32 layout; /* only for raid5 and raid10 currently */ - __u64 size; /* used size of component devices, in 512byte sectors */ + __le64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ + __le32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ + __le32 layout; /* only for raid5 and raid10 currently */ + __le64 size; /* used size of component devices, in 512byte sectors */ - __u32 chunksize; /* in 512byte sectors */ - __u32 raid_disks; - __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts + __le32 chunksize; /* in 512byte sectors */ + __le32 raid_disks; + __le32 bitmap_offset; /* sectors after start of superblock that bitmap starts * NOTE: signed, so bitmap can be before superblock * only meaningful of feature_map[0] is set. */ /* These are only valid with feature bit '4' */ - __u32 new_level; /* new level we are reshaping to */ - __u64 reshape_position; /* next address in array-space for reshape */ - __u32 delta_disks; /* change in number of raid_disks */ - __u32 new_layout; /* new layout */ - __u32 new_chunk; /* new chunk size (bytes) */ + __le32 new_level; /* new level we are reshaping to */ + __le64 reshape_position; /* next address in array-space for reshape */ + __le32 delta_disks; /* change in number of raid_disks */ + __le32 new_layout; /* new layout */ + __le32 new_chunk; /* new chunk size (bytes) */ __u8 pad1[128-124]; /* set to 0 when written */ /* constant this-device information - 64 bytes */ - __u64 data_offset; /* sector start of data, often 0 */ - __u64 data_size; /* sectors in this device that can be used for data */ - __u64 super_offset; /* sector start of this superblock */ - __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ - __u32 dev_number; /* permanent identifier of this device - not role in raid */ - __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ + __le64 data_offset; /* sector start of data, often 0 */ + __le64 data_size; /* sectors in this device that can be used for data */ + __le64 super_offset; /* sector start of this superblock */ + __le64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + __le32 dev_number; /* permanent identifier of this device - not role in raid */ + __le32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ __u8 devflags; /* per-device flags. Only one defined...*/ #define WriteMostly1 1 /* mask for writemostly flag in above */ __u8 pad2[64-57]; /* set to 0 when writing */ /* array state information - 64 bytes */ - __u64 utime; /* 40 bits second, 24 btes microseconds */ - __u64 events; /* incremented when superblock updated */ - __u64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ - __u32 sb_csum; /* checksum upto devs[max_dev] */ - __u32 max_dev; /* size of devs[] array to consider */ + __le64 utime; /* 40 bits second, 24 btes microseconds */ + __le64 events; /* incremented when superblock updated */ + __le64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ + __le32 sb_csum; /* checksum upto devs[max_dev] */ + __le32 max_dev; /* size of devs[] array to consider */ __u8 pad3[64-32]; /* set to 0 when writing */ /* device state information. Indexed by dev_number. @@ -260,7 +260,7 @@ struct mdp_superblock_1 { * into the 'roles' value. If a device is spare or faulty, then it doesn't * have a meaningful role. */ - __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ + __le16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ }; /* feature_map bits */ -- cgit v1.2.3-71-gd317 From 4f2e639af4bd5e152fc79256e333643d3dd6c10f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 21 Oct 2006 10:24:09 -0700 Subject: [PATCH] md: endian annotations for the bitmap superblock And a couple of bug fixes found by sparse. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/bitmap.c | 10 +++++----- include/linux/raid/bitmap.h | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index d47d38ac71b1..d6f614738bbd 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -536,7 +536,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) " "-- forcing full recovery\n", bmname(bitmap), events, (unsigned long long) bitmap->mddev->events); - sb->state |= BITMAP_STALE; + sb->state |= cpu_to_le32(BITMAP_STALE); } success: /* assign fields using values from superblock */ @@ -544,11 +544,11 @@ success: bitmap->daemon_sleep = daemon_sleep; bitmap->daemon_lastrun = jiffies; bitmap->max_write_behind = write_behind; - bitmap->flags |= sb->state; + bitmap->flags |= le32_to_cpu(sb->state); if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN) bitmap->flags |= BITMAP_HOSTENDIAN; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); - if (sb->state & BITMAP_STALE) + if (sb->state & cpu_to_le32(BITMAP_STALE)) bitmap->events_cleared = bitmap->mddev->events; err = 0; out: @@ -578,9 +578,9 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, spin_unlock_irqrestore(&bitmap->lock, flags); sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); switch (op) { - case MASK_SET: sb->state |= bits; + case MASK_SET: sb->state |= cpu_to_le32(bits); break; - case MASK_UNSET: sb->state &= ~bits; + case MASK_UNSET: sb->state &= cpu_to_le32(~bits); break; default: BUG(); } diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index 84d887751855..ebd42a3710b4 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -146,16 +146,16 @@ enum bitmap_state { /* the superblock at the front of the bitmap file -- little endian */ typedef struct bitmap_super_s { - __u32 magic; /* 0 BITMAP_MAGIC */ - __u32 version; /* 4 the bitmap major for now, could change... */ - __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */ - __u64 events; /* 24 event counter for the bitmap (1)*/ - __u64 events_cleared;/*32 event counter when last bit cleared (2) */ - __u64 sync_size; /* 40 the size of the md device's sync range(3) */ - __u32 state; /* 48 bitmap state information */ - __u32 chunksize; /* 52 the bitmap chunk size in bytes */ - __u32 daemon_sleep; /* 56 seconds between disk flushes */ - __u32 write_behind; /* 60 number of outstanding write-behind writes */ + __le32 magic; /* 0 BITMAP_MAGIC */ + __le32 version; /* 4 the bitmap major for now, could change... */ + __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */ + __le64 events; /* 24 event counter for the bitmap (1)*/ + __le64 events_cleared;/*32 event counter when last bit cleared (2) */ + __le64 sync_size; /* 40 the size of the md device's sync range(3) */ + __le32 state; /* 48 bitmap state information */ + __le32 chunksize; /* 52 the bitmap chunk size in bytes */ + __le32 daemon_sleep; /* 56 seconds between disk flushes */ + __le32 write_behind; /* 60 number of outstanding write-behind writes */ __u8 pad[256 - 64]; /* set to zero */ } bitmap_super_t; -- cgit v1.2.3-71-gd317 From d42552c3ace1fa1f16ae02ce642f4c733cec40ca Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 21 Oct 2006 10:24:12 -0700 Subject: [PATCH] pci: declare pci_get_device_reverse() We seem to have lost the declaration of pci_get_device_reverse(), if we ever had one. Add a CONFIG_PCI=0 stub too. Acked-by: Alan Cox Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pci.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 4689e2a699c0..09be0f81b27b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -455,7 +455,11 @@ int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); int pci_find_ext_capability (struct pci_dev *dev, int cap); struct pci_bus *pci_find_next_bus(const struct pci_bus *from); -struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from); +struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, + struct pci_dev *from); +struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device, + struct pci_dev *from); + struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from); @@ -660,7 +664,12 @@ static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) { return NULL; } -static inline struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from) +static inline struct pci_dev *pci_get_device(unsigned int vendor, + unsigned int device, struct pci_dev *from) +{ return NULL; } + +static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor, + unsigned int device, struct pci_dev *from) { return NULL; } static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, -- cgit v1.2.3-71-gd317 From 7516795739bd53175629b90fab0ad488d7a6a9f7 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Sat, 21 Oct 2006 10:24:14 -0700 Subject: [PATCH] Reintroduce NODES_SPAN_OTHER_NODES for powerpc Reintroduce NODES_SPAN_OTHER_NODES for powerpc Revert "[PATCH] Remove SPAN_OTHER_NODES config definition" This reverts commit f62859bb6871c5e4a8e591c60befc8caaf54db8c. Revert "[PATCH] mm: remove arch independent NODES_SPAN_OTHER_NODES" This reverts commit a94b3ab7eab4edcc9b2cb474b188f774c331adf7. Also update the comments to indicate that this is still required and where its used. Signed-off-by: Andy Whitcroft Cc: Paul Mackerras Cc: Mike Kravetz Cc: Benjamin Herrenschmidt Acked-by: Mel Gorman Acked-by: Will Schmidt Cc: Christoph Lameter Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/Kconfig | 9 +++++++++ arch/powerpc/configs/pseries_defconfig | 1 + include/linux/mmzone.h | 6 ++++++ mm/page_alloc.c | 2 ++ 4 files changed, 18 insertions(+) (limited to 'include/linux') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 8b6910465578..2bd9b7fb0f6c 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -751,6 +751,15 @@ config ARCH_MEMORY_PROBE def_bool y depends on MEMORY_HOTPLUG +# Some NUMA nodes have memory ranges that span +# other nodes. Even though a pfn is valid and +# between a node's start and end pfns, it may not +# reside on that node. See memmap_init_zone() +# for details. +config NODES_SPAN_OTHER_NODES + def_bool y + depends on NEED_MULTIPLE_NODES + config PPC_64K_PAGES bool "64k page size" depends on PPC64 diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 9828663652e9..d2833c1a1f3d 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -184,6 +184,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y CONFIG_RESOURCES_64BIT=y CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_NODES_SPAN_OTHER_NODES=y # CONFIG_PPC_64K_PAGES is not set CONFIG_SCHED_SMT=y CONFIG_PROC_DEVICETREE=y diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 59855b8718a0..ed0762b283a9 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -674,6 +674,12 @@ void sparse_init(void); #define sparse_index_init(_sec, _nid) do {} while (0) #endif /* CONFIG_SPARSEMEM */ +#ifdef CONFIG_NODES_SPAN_OTHER_NODES +#define early_pfn_in_nid(pfn, nid) (early_pfn_to_nid(pfn) == (nid)) +#else +#define early_pfn_in_nid(pfn, nid) (1) +#endif + #ifndef early_pfn_valid #define early_pfn_valid(pfn) (1) #endif diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ebd425c2e2a7..f5fc45472d5c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1689,6 +1689,8 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, for (pfn = start_pfn; pfn < end_pfn; pfn++) { if (!early_pfn_valid(pfn)) continue; + if (!early_pfn_in_nid(pfn, nid)) + continue; page = pfn_to_page(pfn); set_page_links(page, zone, nid, pfn); init_page_count(page); -- cgit v1.2.3-71-gd317 From faf6bbcf94caee10ba34adb86db4ecca96bfd3bf Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sat, 21 Oct 2006 10:24:17 -0700 Subject: [PATCH] cpuset: mempolicy migration typo fix Mistyped an ifdef CONFIG_CPUSETS - fixed. I doubt that anyone ever noticed. The impact of this typo was that if someone: 1) was using MPOL_BIND to force off node allocations 2) while using cpusets to constrain memory placement 3) when that cpuset was migrating that jobs memory 4) while the tasks in that job were actively forking then there was a rare chance that future allocations using that MPOL_BIND policy would be node local, not off node. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mempolicy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 09f0f575ddff..daabb3aa1ec6 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -150,7 +150,7 @@ extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new); extern void mpol_fix_fork_child_flag(struct task_struct *p); #define set_cpuset_being_rebound(x) (cpuset_being_rebound = (x)) -#ifdef CONFIG_CPUSET +#ifdef CONFIG_CPUSETS #define current_cpuset_is_being_rebound() \ (cpuset_being_rebound == current->cpuset) #else -- cgit v1.2.3-71-gd317 From 04fed361dadb7921507a470947ac23d2f26352cf Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 22 Oct 2006 15:57:18 +0100 Subject: [PATCH] Remove __must_check for device_for_each_child() Eliminate more __must_check madness. The return code from device_for_each_child() depends on the values which the helper function returns. If the helper function always returns zero, it's utterly pointless to check the return code from device_for_each_child(). The only code which knows if the return value should be checked is the caller itself, so forcing the return code to always be checked is silly. Hence, remove the __must_check annotation. Signed-off-by: Russell King Signed-off-by: Linus Torvalds --- include/linux/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/device.h b/include/linux/device.h index 662e6a10144e..9d4f6a963936 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -393,7 +393,7 @@ extern void device_unregister(struct device * dev); extern void device_initialize(struct device * dev); extern int __must_check device_add(struct device * dev); extern void device_del(struct device * dev); -extern int __must_check device_for_each_child(struct device *, void *, +extern int device_for_each_child(struct device *, void *, int (*fn)(struct device *, void *)); extern int device_rename(struct device *dev, char *new_name); -- cgit v1.2.3-71-gd317 From 735a7ffb739b6efeaeb1e720306ba308eaaeb20e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 27 Oct 2006 11:42:37 -0700 Subject: [PATCH] drivers: wait for threaded probes between initcall levels The multithreaded-probing code has a problem: after one initcall level (eg, core_initcall) has been processed, we will then start processing the next level (postcore_initcall) while the kernel threads which are handling core_initcall are still executing. This breaks the guarantees which the layered initcalls previously gave us. IOW, we want to be multithreaded _within_ an initcall level, but not between different levels. Fix that up by causing the probing code to wait for all outstanding probes at one level to complete before we start processing the next level. Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/dd.c | 30 ++++++++++++++++++++++++++++++ include/asm-generic/vmlinux.lds.h | 9 ++++++++- include/linux/init.h | 28 +++++++++++++++++++--------- 3 files changed, 57 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index db01b95a47a5..c5d6bb4290ad 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -70,6 +71,8 @@ struct stupid_thread_structure { }; static atomic_t probe_count = ATOMIC_INIT(0); +static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); + static int really_probe(void *void_data) { struct stupid_thread_structure *data = void_data; @@ -121,6 +124,7 @@ probe_failed: done: kfree(data); atomic_dec(&probe_count); + wake_up(&probe_waitqueue); return ret; } @@ -337,6 +341,32 @@ void driver_detach(struct device_driver * drv) } } +#ifdef CONFIG_PCI_MULTITHREAD_PROBE +static int __init wait_for_probes(void) +{ + DEFINE_WAIT(wait); + + printk(KERN_INFO "%s: waiting for %d threads\n", __FUNCTION__, + atomic_read(&probe_count)); + if (!atomic_read(&probe_count)) + return 0; + while (atomic_read(&probe_count)) { + prepare_to_wait(&probe_waitqueue, &wait, TASK_UNINTERRUPTIBLE); + if (atomic_read(&probe_count)) + schedule(); + } + finish_wait(&probe_waitqueue, &wait); + return 0; +} + +core_initcall_sync(wait_for_probes); +postcore_initcall_sync(wait_for_probes); +arch_initcall_sync(wait_for_probes); +subsys_initcall_sync(wait_for_probes); +fs_initcall_sync(wait_for_probes); +device_initcall_sync(wait_for_probes); +late_initcall_sync(wait_for_probes); +#endif EXPORT_SYMBOL_GPL(device_bind_driver); EXPORT_SYMBOL_GPL(device_release_driver); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index e3e83bcaf710..9d873163a7ab 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -216,10 +216,17 @@ #define INITCALLS \ *(.initcall1.init) \ + *(.initcall1s.init) \ *(.initcall2.init) \ + *(.initcall2s.init) \ *(.initcall3.init) \ + *(.initcall3s.init) \ *(.initcall4.init) \ + *(.initcall4s.init) \ *(.initcall5.init) \ + *(.initcall5s.init) \ *(.initcall6.init) \ - *(.initcall7.init) + *(.initcall6s.init) \ + *(.initcall7.init) \ + *(.initcall7s.init) diff --git a/include/linux/init.h b/include/linux/init.h index e92b1455d7af..ff40ea118e3a 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -84,19 +84,29 @@ extern void setup_arch(char **); * by link order. * For backwards compatibility, initcall() puts the call in * the device init subsection. + * + * The `id' arg to __define_initcall() is needed so that multiple initcalls + * can point at the same handler without causing duplicate-symbol build errors. */ -#define __define_initcall(level,fn) \ - static initcall_t __initcall_##fn __attribute_used__ \ +#define __define_initcall(level,fn,id) \ + static initcall_t __initcall_##fn##id __attribute_used__ \ __attribute__((__section__(".initcall" level ".init"))) = fn -#define core_initcall(fn) __define_initcall("1",fn) -#define postcore_initcall(fn) __define_initcall("2",fn) -#define arch_initcall(fn) __define_initcall("3",fn) -#define subsys_initcall(fn) __define_initcall("4",fn) -#define fs_initcall(fn) __define_initcall("5",fn) -#define device_initcall(fn) __define_initcall("6",fn) -#define late_initcall(fn) __define_initcall("7",fn) +#define core_initcall(fn) __define_initcall("1",fn,1) +#define core_initcall_sync(fn) __define_initcall("1s",fn,1s) +#define postcore_initcall(fn) __define_initcall("2",fn,2) +#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s) +#define arch_initcall(fn) __define_initcall("3",fn,3) +#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s) +#define subsys_initcall(fn) __define_initcall("4",fn,4) +#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s) +#define fs_initcall(fn) __define_initcall("5",fn,5) +#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s) +#define device_initcall(fn) __define_initcall("6",fn,6) +#define device_initcall_sync(fn) __define_initcall("6s",fn,6s) +#define late_initcall(fn) __define_initcall("7",fn,7) +#define late_initcall_sync(fn) __define_initcall("7s",fn,7s) #define __initcall(fn) device_initcall(fn) -- cgit v1.2.3-71-gd317 From 2ae88149a27cadf2840e0ab8155bef13be285c03 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sat, 28 Oct 2006 10:38:23 -0700 Subject: [PATCH] mm: clean up pagecache allocation - Consolidate page_cache_alloc - Fix splice: only the pagecache pages and filesystem data need to use mapping_gfp_mask. - Fix grab_cache_page_nowait: same as splice, also honour NUMA placement. Signed-off-by: Nick Piggin Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/splice.c | 9 ++++----- include/linux/pagemap.h | 14 +++++++++----- mm/filemap.c | 24 ++++++------------------ 3 files changed, 19 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/fs/splice.c b/fs/splice.c index 49fb9f129938..8d705954d294 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -74,7 +74,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, wait_on_page_writeback(page); if (PagePrivate(page)) - try_to_release_page(page, mapping_gfp_mask(mapping)); + try_to_release_page(page, GFP_KERNEL); /* * If we succeeded in removing the mapping, set LRU flag @@ -333,7 +333,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, break; error = add_to_page_cache_lru(page, mapping, index, - mapping_gfp_mask(mapping)); + GFP_KERNEL); if (unlikely(error)) { page_cache_release(page); if (error == -EEXIST) @@ -557,7 +557,6 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, { struct file *file = sd->file; struct address_space *mapping = file->f_mapping; - gfp_t gfp_mask = mapping_gfp_mask(mapping); unsigned int offset, this_len; struct page *page; pgoff_t index; @@ -591,7 +590,7 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, goto find_page; page = buf->page; - if (add_to_page_cache(page, mapping, index, gfp_mask)) { + if (add_to_page_cache(page, mapping, index, GFP_KERNEL)) { unlock_page(page); goto find_page; } @@ -613,7 +612,7 @@ find_page: * This will also lock the page */ ret = add_to_page_cache_lru(page, mapping, index, - gfp_mask); + GFP_KERNEL); if (unlikely(ret)) goto out; } diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 64f950925151..c3e255bf8594 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -52,19 +52,23 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask) void release_pages(struct page **pages, int nr, int cold); #ifdef CONFIG_NUMA -extern struct page *page_cache_alloc(struct address_space *x); -extern struct page *page_cache_alloc_cold(struct address_space *x); +extern struct page *__page_cache_alloc(gfp_t gfp); #else +static inline struct page *__page_cache_alloc(gfp_t gfp) +{ + return alloc_pages(gfp, 0); +} +#endif + static inline struct page *page_cache_alloc(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x), 0); + return __page_cache_alloc(mapping_gfp_mask(x)); } static inline struct page *page_cache_alloc_cold(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); + return __page_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD); } -#endif typedef int filler_t(void *, struct page *); diff --git a/mm/filemap.c b/mm/filemap.c index cb26e33fd0ff..7b84dc814347 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -467,25 +467,15 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping, } #ifdef CONFIG_NUMA -struct page *page_cache_alloc(struct address_space *x) +struct page *__page_cache_alloc(gfp_t gfp) { if (cpuset_do_page_mem_spread()) { int n = cpuset_mem_spread_node(); - return alloc_pages_node(n, mapping_gfp_mask(x), 0); + return alloc_pages_node(n, gfp, 0); } - return alloc_pages(mapping_gfp_mask(x), 0); + return alloc_pages(gfp, 0); } -EXPORT_SYMBOL(page_cache_alloc); - -struct page *page_cache_alloc_cold(struct address_space *x) -{ - if (cpuset_do_page_mem_spread()) { - int n = cpuset_mem_spread_node(); - return alloc_pages_node(n, mapping_gfp_mask(x)|__GFP_COLD, 0); - } - return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); -} -EXPORT_SYMBOL(page_cache_alloc_cold); +EXPORT_SYMBOL(__page_cache_alloc); #endif static int __sleep_on_page_lock(void *word) @@ -826,7 +816,6 @@ struct page * grab_cache_page_nowait(struct address_space *mapping, unsigned long index) { struct page *page = find_get_page(mapping, index); - gfp_t gfp_mask; if (page) { if (!TestSetPageLocked(page)) @@ -834,9 +823,8 @@ grab_cache_page_nowait(struct address_space *mapping, unsigned long index) page_cache_release(page); return NULL; } - gfp_mask = mapping_gfp_mask(mapping) & ~__GFP_FS; - page = alloc_pages(gfp_mask, 0); - if (page && add_to_page_cache_lru(page, mapping, index, gfp_mask)) { + page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~__GFP_FS); + if (page && add_to_page_cache_lru(page, mapping, index, GFP_KERNEL)) { page_cache_release(page); page = NULL; } -- cgit v1.2.3-71-gd317 From 3bb1a852ab6c9cdf211a2f4a2f502340c8c38eca Mon Sep 17 00:00:00 2001 From: Martin Bligh Date: Sat, 28 Oct 2006 10:38:24 -0700 Subject: [PATCH] vmscan: Fix temp_priority race The temp_priority field in zone is racy, as we can walk through a reclaim path, and just before we copy it into prev_priority, it can be overwritten (say with DEF_PRIORITY) by another reclaimer. The same bug is contained in both try_to_free_pages and balance_pgdat, but it is fixed slightly differently. In balance_pgdat, we keep a separate priority record per zone in a local array. In try_to_free_pages there is no need to do this, as the priority level is the same for all zones that we reclaim from. Impact of this bug is that temp_priority is copied into prev_priority, and setting this artificially high causes reclaimers to set distress artificially low. They then fail to reclaim mapped pages, when they are, in fact, under severe memory pressure (their priority may be as low as 0). This causes the OOM killer to fire incorrectly. From: Andrew Morton __zone_reclaim() isn't modifying zone->prev_priority. But zone->prev_priority is used in the decision whether or not to bring mapped pages onto the inactive list. Hence there's a risk here that __zone_reclaim() will fail because zone->prev_priority ir large (ie: low urgency) and lots of mapped pages end up stuck on the active list. Fix that up by decreasing (ie making more urgent) zone->prev_priority as __zone_reclaim() scans the zone's pages. This bug perhaps explains why ZONE_RECLAIM_PRIORITY was created. It should be possible to remove that now, and to just start out at DEF_PRIORITY? Cc: Nick Piggin Cc: Christoph Lameter Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 6 +----- mm/page_alloc.c | 2 +- mm/vmscan.c | 55 +++++++++++++++++++++++++++++++++++++------------- mm/vmstat.c | 2 -- 4 files changed, 43 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index ed0762b283a9..e06683e2bea3 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -218,13 +218,9 @@ struct zone { * under - it drives the swappiness decision: whether to unmap mapped * pages. * - * temp_priority is used to remember the scanning priority at which - * this zone was successfully refilled to free_pages == pages_high. - * - * Access to both these fields is quite racy even on uniprocessor. But + * Access to both this field is quite racy even on uniprocessor. But * it is expected to average out OK. */ - int temp_priority; int prev_priority; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f5fc45472d5c..ecf853b5e30e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2407,7 +2407,7 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, zone->zone_pgdat = pgdat; zone->free_pages = 0; - zone->temp_priority = zone->prev_priority = DEF_PRIORITY; + zone->prev_priority = DEF_PRIORITY; zone_pcp_init(zone); INIT_LIST_HEAD(&zone->active_list); diff --git a/mm/vmscan.c b/mm/vmscan.c index f05527bf792b..b32560ead5c0 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -723,6 +723,20 @@ done: return nr_reclaimed; } +/* + * We are about to scan this zone at a certain priority level. If that priority + * level is smaller (ie: more urgent) than the previous priority, then note + * that priority level within the zone. This is done so that when the next + * process comes in to scan this zone, it will immediately start out at this + * priority level rather than having to build up its own scanning priority. + * Here, this priority affects only the reclaim-mapped threshold. + */ +static inline void note_zone_scanning_priority(struct zone *zone, int priority) +{ + if (priority < zone->prev_priority) + zone->prev_priority = priority; +} + static inline int zone_is_near_oom(struct zone *zone) { return zone->pages_scanned >= (zone->nr_active + zone->nr_inactive)*3; @@ -972,9 +986,7 @@ static unsigned long shrink_zones(int priority, struct zone **zones, if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) continue; - zone->temp_priority = priority; - if (zone->prev_priority > priority) - zone->prev_priority = priority; + note_zone_scanning_priority(zone, priority); if (zone->all_unreclaimable && priority != DEF_PRIORITY) continue; /* Let kswapd poll it */ @@ -1024,7 +1036,6 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) continue; - zone->temp_priority = DEF_PRIORITY; lru_pages += zone->nr_active + zone->nr_inactive; } @@ -1065,13 +1076,22 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) if (!sc.all_unreclaimable) ret = 1; out: + /* + * Now that we've scanned all the zones at this priority level, note + * that level within the zone so that the next thread which performs + * scanning of this zone will immediately start out at this priority + * level. This affects only the decision whether or not to bring + * mapped pages onto the inactive list. + */ + if (priority < 0) + priority = 0; for (i = 0; zones[i] != 0; i++) { struct zone *zone = zones[i]; if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) continue; - zone->prev_priority = zone->temp_priority; + zone->prev_priority = priority; } return ret; } @@ -1111,6 +1131,11 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order) .swap_cluster_max = SWAP_CLUSTER_MAX, .swappiness = vm_swappiness, }; + /* + * temp_priority is used to remember the scanning priority at which + * this zone was successfully refilled to free_pages == pages_high. + */ + int temp_priority[MAX_NR_ZONES]; loop_again: total_scanned = 0; @@ -1118,11 +1143,8 @@ loop_again: sc.may_writepage = !laptop_mode; count_vm_event(PAGEOUTRUN); - for (i = 0; i < pgdat->nr_zones; i++) { - struct zone *zone = pgdat->node_zones + i; - - zone->temp_priority = DEF_PRIORITY; - } + for (i = 0; i < pgdat->nr_zones; i++) + temp_priority[i] = DEF_PRIORITY; for (priority = DEF_PRIORITY; priority >= 0; priority--) { int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */ @@ -1183,10 +1205,9 @@ scan: if (!zone_watermark_ok(zone, order, zone->pages_high, end_zone, 0)) all_zones_ok = 0; - zone->temp_priority = priority; - if (zone->prev_priority > priority) - zone->prev_priority = priority; + temp_priority[i] = priority; sc.nr_scanned = 0; + note_zone_scanning_priority(zone, priority); nr_reclaimed += shrink_zone(priority, zone, &sc); reclaim_state->reclaimed_slab = 0; nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL, @@ -1226,10 +1247,15 @@ scan: break; } out: + /* + * Note within each zone the priority level at which this zone was + * brought into a happy state. So that the next thread which scans this + * zone will start out at that priority level. + */ for (i = 0; i < pgdat->nr_zones; i++) { struct zone *zone = pgdat->node_zones + i; - zone->prev_priority = zone->temp_priority; + zone->prev_priority = temp_priority[i]; } if (!all_zones_ok) { cond_resched(); @@ -1614,6 +1640,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) */ priority = ZONE_RECLAIM_PRIORITY; do { + note_zone_scanning_priority(zone, priority); nr_reclaimed += shrink_zone(priority, zone, &sc); priority--; } while (priority >= 0 && nr_reclaimed < nr_pages); diff --git a/mm/vmstat.c b/mm/vmstat.c index 45b124e012f5..8614e8f6743b 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -587,11 +587,9 @@ static int zoneinfo_show(struct seq_file *m, void *arg) seq_printf(m, "\n all_unreclaimable: %u" "\n prev_priority: %i" - "\n temp_priority: %i" "\n start_pfn: %lu", zone->all_unreclaimable, zone->prev_priority, - zone->temp_priority, zone->zone_start_pfn); spin_unlock_irqrestore(&zone->lock, flags); seq_putc(m, '\n'); -- cgit v1.2.3-71-gd317 From 52fd24ca1db3a741f144bbc229beefe044202cac Mon Sep 17 00:00:00 2001 From: Giridhar Pemmasani Date: Sat, 28 Oct 2006 10:38:34 -0700 Subject: [PATCH] __vmalloc with GFP_ATOMIC causes 'sleeping from invalid context' If __vmalloc is called to allocate memory with GFP_ATOMIC in atomic context, the chain of calls results in __get_vm_area_node allocating memory for vm_struct with GFP_KERNEL, causing the 'sleeping from invalid context' warning. This patch fixes it by passing the gfp flags along so __get_vm_area_node allocates memory for vm_struct with the same flags. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 3 ++- mm/vmalloc.c | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index ce5f1482e6be..dc9a29d84abc 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -60,7 +60,8 @@ extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end); extern struct vm_struct *get_vm_area_node(unsigned long size, - unsigned long flags, int node); + unsigned long flags, int node, + gfp_t gfp_mask); extern struct vm_struct *remove_vm_area(void *addr); extern int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 1133dd3aafcf..6d381df7c9b3 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -160,13 +160,15 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages) return err; } -struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, - unsigned long start, unsigned long end, int node) +static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, + unsigned long start, unsigned long end, + int node, gfp_t gfp_mask) { struct vm_struct **p, *tmp, *area; unsigned long align = 1; unsigned long addr; + BUG_ON(in_interrupt()); if (flags & VM_IOREMAP) { int bit = fls(size); @@ -180,7 +182,7 @@ struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, addr = ALIGN(start, align); size = PAGE_ALIGN(size); - area = kmalloc_node(sizeof(*area), GFP_KERNEL, node); + area = kmalloc_node(sizeof(*area), gfp_mask, node); if (unlikely(!area)) return NULL; @@ -236,7 +238,7 @@ out: struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end) { - return __get_vm_area_node(size, flags, start, end, -1); + return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL); } /** @@ -253,9 +255,11 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags) return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); } -struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node) +struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, + int node, gfp_t gfp_mask) { - return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node); + return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node, + gfp_mask); } /* Caller must hold vmlist_lock */ @@ -487,7 +491,7 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL; - area = get_vm_area_node(size, VM_ALLOC, node); + area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask); if (!area) return NULL; -- cgit v1.2.3-71-gd317 From 5fa3839a64203b2ab727dcb37da9b2d7079fca28 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sat, 28 Oct 2006 10:38:46 -0700 Subject: [PATCH] Constify compat_get_bitmap argument This means we can call it when the bitmap we want to fetch is declared const. Signed-off-by: Stephen Rothwell Cc: Christoph Lameter Cc: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compat.h | 2 +- kernel/compat.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compat.h b/include/linux/compat.h index f4ebf96f5308..f1553196826f 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -196,7 +196,7 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, #define BITS_TO_COMPAT_LONGS(bits) \ (((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG) -long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask, +long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size); long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, unsigned long bitmap_size); diff --git a/kernel/compat.c b/kernel/compat.c index 75573e5d27b0..d4898aad6cfa 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -678,7 +678,7 @@ int get_compat_sigevent(struct sigevent *event, ? -EFAULT : 0; } -long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask, +long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size) { int i, j; -- cgit v1.2.3-71-gd317 From 093a8e8aecd77b2799934996a55a6838e1e2b8f3 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 28 Oct 2006 10:38:51 -0700 Subject: [PATCH] taskstats_tgid_free: fix usage taskstats_tgid_free() is called on copy_process's error path. This is wrong. IF (clone_flags & CLONE_THREAD) We should not clear ->signal->taskstats, current uses it, it probably has a valid accumulated info. ELSE taskstats_tgid_init() set ->signal->taskstats = NULL, there is nothing to free. Move the callsite to __exit_signal(). We don't need any locking, entire thread group is exiting, nobody should have a reference to soon to be released ->signal. Signed-off-by: Oleg Nesterov Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats_kern.h | 13 ++----------- kernel/exit.c | 1 + kernel/fork.c | 1 - 3 files changed, 3 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index 16894b7edcc8..a437ca0d226b 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -49,17 +49,8 @@ static inline void taskstats_tgid_alloc(struct signal_struct *sig) static inline void taskstats_tgid_free(struct signal_struct *sig) { - struct taskstats *stats = NULL; - unsigned long flags; - - spin_lock_irqsave(&sig->stats_lock, flags); - if (sig->stats) { - stats = sig->stats; - sig->stats = NULL; - } - spin_unlock_irqrestore(&sig->stats_lock, flags); - if (stats) - kmem_cache_free(taskstats_cache, stats); + if (sig->stats) + kmem_cache_free(taskstats_cache, sig->stats); } extern void taskstats_exit_alloc(struct taskstats **, unsigned int *); diff --git a/kernel/exit.c b/kernel/exit.c index f250a5e3e281..06de6c4e8ca3 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -128,6 +128,7 @@ static void __exit_signal(struct task_struct *tsk) flush_sigqueue(&tsk->pending); if (sig) { flush_sigqueue(&sig->shared_pending); + taskstats_tgid_free(sig); __cleanup_signal(sig); } } diff --git a/kernel/fork.c b/kernel/fork.c index 29ebb30850ed..213326609bac 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -897,7 +897,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts void __cleanup_signal(struct signal_struct *sig) { exit_thread_group_keys(sig); - taskstats_tgid_free(sig); kmem_cache_free(signal_cachep, sig); } -- cgit v1.2.3-71-gd317 From 17b02695b254aa2ef0e53df9c8e6548f86e66a9d Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 28 Oct 2006 10:38:52 -0700 Subject: [PATCH] taskstats_tgid_alloc: optimization Every subthread (except first) does unneeded kmem_cache_alloc/kmem_cache_free. Signed-off-by: Oleg Nesterov Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/taskstats_kern.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index a437ca0d226b..664224008fb2 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -32,6 +32,9 @@ static inline void taskstats_tgid_alloc(struct signal_struct *sig) struct taskstats *stats; unsigned long flags; + if (sig->stats != NULL) + return; + stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL); if (!stats) return; -- cgit v1.2.3-71-gd317 From b8534d7bd89df0cd41cd47bcd6733a05ea9a691a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 28 Oct 2006 10:38:53 -0700 Subject: [PATCH] taskstats: kill ->taskstats_lock in favor of ->siglock signal_struct is (mostly) protected by ->sighand->siglock, I think we don't need ->taskstats_lock to protect ->stats. This also allows us to simplify the locking in fill_tgid(). Signed-off-by: Oleg Nesterov Cc: Shailabh Nagar Cc: Balbir Singh Cc: Jay Lan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 - include/linux/taskstats_kern.h | 15 ++++++--------- kernel/fork.c | 2 +- kernel/taskstats.c | 16 ++++++---------- 4 files changed, 13 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 6735c1cf334c..eafe4a7b8237 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -466,7 +466,6 @@ struct signal_struct { struct pacct_struct pacct; /* per-process accounting information */ #endif #ifdef CONFIG_TASKSTATS - spinlock_t stats_lock; struct taskstats *stats; #endif }; diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h index 664224008fb2..6562a2050a25 100644 --- a/include/linux/taskstats_kern.h +++ b/include/linux/taskstats_kern.h @@ -23,28 +23,26 @@ static inline void taskstats_exit_free(struct taskstats *tidstats) static inline void taskstats_tgid_init(struct signal_struct *sig) { - spin_lock_init(&sig->stats_lock); sig->stats = NULL; } -static inline void taskstats_tgid_alloc(struct signal_struct *sig) +static inline void taskstats_tgid_alloc(struct task_struct *tsk) { + struct signal_struct *sig = tsk->signal; struct taskstats *stats; - unsigned long flags; if (sig->stats != NULL) return; + /* No problem if kmem_cache_zalloc() fails */ stats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL); - if (!stats) - return; - spin_lock_irqsave(&sig->stats_lock, flags); + spin_lock_irq(&tsk->sighand->siglock); if (!sig->stats) { sig->stats = stats; stats = NULL; } - spin_unlock_irqrestore(&sig->stats_lock, flags); + spin_unlock_irq(&tsk->sighand->siglock); if (stats) kmem_cache_free(taskstats_cache, stats); @@ -59,7 +57,6 @@ static inline void taskstats_tgid_free(struct signal_struct *sig) extern void taskstats_exit_alloc(struct taskstats **, unsigned int *); extern void taskstats_exit_send(struct task_struct *, struct taskstats *, int, unsigned int); extern void taskstats_init_early(void); -extern void taskstats_tgid_alloc(struct signal_struct *); #else static inline void taskstats_exit_alloc(struct taskstats **ptidstats, unsigned int *mycpu) {} @@ -71,7 +68,7 @@ static inline void taskstats_exit_send(struct task_struct *tsk, {} static inline void taskstats_tgid_init(struct signal_struct *sig) {} -static inline void taskstats_tgid_alloc(struct signal_struct *sig) +static inline void taskstats_tgid_alloc(struct task_struct *tsk) {} static inline void taskstats_tgid_free(struct signal_struct *sig) {} diff --git a/kernel/fork.c b/kernel/fork.c index 213326609bac..3da978eec791 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -830,7 +830,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts if (clone_flags & CLONE_THREAD) { atomic_inc(¤t->signal->count); atomic_inc(¤t->signal->live); - taskstats_tgid_alloc(current->signal); + taskstats_tgid_alloc(current); return 0; } sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 9aeee511a463..b2efda94615a 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -241,11 +241,11 @@ static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk, tsk = first; read_lock(&tasklist_lock); /* Start with stats from dead tasks */ - if (first->signal) { - spin_lock_irqsave(&first->signal->stats_lock, flags); + if (first->sighand) { + spin_lock_irqsave(&first->sighand->siglock, flags); if (first->signal->stats) memcpy(stats, first->signal->stats, sizeof(*stats)); - spin_unlock_irqrestore(&first->signal->stats_lock, flags); + spin_unlock_irqrestore(&first->sighand->siglock, flags); } do { @@ -276,7 +276,7 @@ static void fill_tgid_exit(struct task_struct *tsk) { unsigned long flags; - spin_lock_irqsave(&tsk->signal->stats_lock, flags); + spin_lock_irqsave(&tsk->sighand->siglock, flags); if (!tsk->signal->stats) goto ret; @@ -288,7 +288,7 @@ static void fill_tgid_exit(struct task_struct *tsk) */ delayacct_add_tsk(tsk->signal->stats, tsk); ret: - spin_unlock_irqrestore(&tsk->signal->stats_lock, flags); + spin_unlock_irqrestore(&tsk->sighand->siglock, flags); return; } @@ -464,15 +464,10 @@ void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, size_t size; int is_thread_group; struct nlattr *na; - unsigned long flags; if (!family_registered || !tidstats) return; - spin_lock_irqsave(&tsk->signal->stats_lock, flags); - is_thread_group = tsk->signal->stats ? 1 : 0; - spin_unlock_irqrestore(&tsk->signal->stats_lock, flags); - rc = 0; /* * Size includes space for nested attributes @@ -480,6 +475,7 @@ void taskstats_exit_send(struct task_struct *tsk, struct taskstats *tidstats, size = nla_total_size(sizeof(u32)) + nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); + is_thread_group = (tsk->signal->stats != NULL); if (is_thread_group) size = 2 * size; /* PID + STATS + TGID + STATS */ -- cgit v1.2.3-71-gd317 From 7259f0d05d595b73ef312a082e628627c6414969 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 29 Oct 2006 22:46:36 -0800 Subject: [PATCH] lockdep: annotate DECLARE_WAIT_QUEUE_HEAD kernel: INFO: trying to register non-static key. kernel: the code is fine but needs lockdep annotation. kernel: turning off the locking correctness validator. kernel: [] show_trace_log_lvl+0x58/0x16a kernel: [] show_trace+0xd/0x10 kernel: [] dump_stack+0x19/0x1b kernel: [] __lock_acquire+0xf0/0x90d kernel: [] lock_acquire+0x4b/0x6b kernel: [] _spin_lock_irqsave+0x22/0x32 kernel: [] prepare_to_wait+0x17/0x4b kernel: [] lpfc_do_work+0xdd/0xcc2 [lpfc] kernel: [] kthread+0xc3/0xf2 kernel: [] kernel_thread_helper+0x5/0xb Another case of non-static lockdep keys; duplicate the paradigm set by DECLARE_COMPLETION_ONSTACK and introduce DECLARE_WAIT_QUEUE_HEAD_ONSTACK. Signed-off-by: Peter Zijlstra Cc: Greg KH Cc: Markus Lidel Acked-by: Ingo Molnar Cc: Arjan van de Ven Cc: James Bottomley Cc: Marcel Holtmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bluecard_cs.c | 2 +- drivers/message/i2o/exec-osm.c | 2 +- drivers/scsi/dpt/dpti_i2o.h | 2 +- drivers/scsi/imm.c | 2 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 4 ++-- drivers/scsi/ppa.c | 2 +- drivers/usb/net/usbnet.c | 2 +- include/linux/wait.h | 9 +++++++++ 9 files changed, 18 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 845b8680032a..cbc07250b898 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -282,7 +282,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info) clear_bit(ready_bit, &(info->tx_state)); if (bt_cb(skb)->pkt_type & 0x80) { - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); DEFINE_WAIT(wait); unsigned char baud_reg; diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 01a5a702b037..a2350640384b 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -124,7 +124,7 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait) int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg, unsigned long timeout, struct i2o_dma *dma) { - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); struct i2o_exec_wait *wait; static u32 tcntxt = 0x80000000; unsigned long flags; diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h index b3fa7ed71faf..5a49216fe4cf 100644 --- a/drivers/scsi/dpt/dpti_i2o.h +++ b/drivers/scsi/dpt/dpti_i2o.h @@ -49,7 +49,7 @@ #include typedef wait_queue_head_t adpt_wait_queue_head_t; -#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait) +#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait) typedef wait_queue_t adpt_wait_queue_t; /* diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 2d95ac9c32c1..e31f6122106f 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1153,7 +1153,7 @@ static int __imm_attach(struct parport *pb) { struct Scsi_Host *host; imm_struct *dev; - DECLARE_WAIT_QUEUE_HEAD(waiting); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); DEFINE_WAIT(wait); int ports; int modes, ppb; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index d586c3d3b0d0..19c79a0549a7 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -305,7 +305,7 @@ lpfc_do_work(void *p) { struct lpfc_hba *phba = p; int rc; - DECLARE_WAIT_QUEUE_HEAD(work_waitq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq); set_user_nice(current, -20); phba->work_wait = &work_waitq; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 24a1779b9af4..582f5ea4e84e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2983,7 +2983,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, struct lpfc_iocbq * prspiocbq, uint32_t timeout) { - DECLARE_WAIT_QUEUE_HEAD(done_q); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); long timeleft, timeout_req = 0; int retval = IOCB_SUCCESS; uint32_t creg_val; @@ -3061,7 +3061,7 @@ int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, uint32_t timeout) { - DECLARE_WAIT_QUEUE_HEAD(done_q); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); DECLARE_WAITQUEUE(wq_entry, current); uint32_t timeleft = 0; int retval; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index b0eba39f208a..89a2a9f11e41 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -1012,7 +1012,7 @@ static LIST_HEAD(ppa_hosts); static int __ppa_attach(struct parport *pb) { struct Scsi_Host *host; - DECLARE_WAIT_QUEUE_HEAD(waiting); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); DEFINE_WAIT(wait); ppa_struct *dev; int ports; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index cf3d20eb781c..40873635d80e 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -554,7 +554,7 @@ static int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); int temp; - DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); netif_stop_queue (net); diff --git a/include/linux/wait.h b/include/linux/wait.h index b3b9048421d8..e820d00e1383 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -79,6 +79,15 @@ struct task_struct; extern void init_waitqueue_head(wait_queue_head_t *q); +#ifdef CONFIG_LOCKDEP +# define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \ + ({ init_waitqueue_head(&name); name; }) +# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) \ + wait_queue_head_t name = __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) +#else +# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) DECLARE_WAIT_QUEUE_HEAD(name) +#endif + static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p) { q->flags = 0; -- cgit v1.2.3-71-gd317 From 351edd240d0ba8620789ca9e24f5a38b62157f23 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 29 Oct 2006 22:46:40 -0800 Subject: [PATCH] MTD: fix last kernel-doc warning Fix the last current kernel-doc warning: Warning(/var/linsrc/linux-2619-rc3g5//include/linux/mtd/nand.h:416): No description found for parameter 'write_page' Signed-off-by: Randy Dunlap Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mtd/nand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 70420bbae82b..8b3ef4187219 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -355,7 +355,7 @@ struct nand_buffers { * @priv: [OPTIONAL] pointer to private chip date * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks * (determine if errors are correctable) - * @write_page [REPLACEABLE] High-level page write function + * @write_page: [REPLACEABLE] High-level page write function */ struct nand_chip { -- cgit v1.2.3-71-gd317 From 6e42acc4115bc376b8523acbcba2b2b7cc27d016 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 27 Oct 2006 19:08:42 -0700 Subject: [PATCH] libata: unexport ata_dev_revalidate() ata_dev_revalidate() isn't used outside of libata core. Unexport it. Signed-off-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 - drivers/ata/libata.h | 1 + include/linux/libata.h | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 83728a9457ad..a8fd0c3e59b3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6122,7 +6122,6 @@ EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); -EXPORT_SYMBOL_GPL(ata_dev_revalidate); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_port_disable); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a5ecb71390a9..0ed263be652a 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -53,6 +53,7 @@ extern unsigned ata_exec_internal(struct ata_device *dev, extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int post_reset, u16 *id); +extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); extern int ata_dev_configure(struct ata_device *dev, int print_info); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); diff --git a/include/linux/libata.h b/include/linux/libata.h index b03d5a340dc8..abd2debebca2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -702,7 +702,6 @@ extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); -extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); #ifdef CONFIG_PCI -- cgit v1.2.3-71-gd317 From 4fa2eeeac5e13a8579ee45bc172eed690d28fbb7 Mon Sep 17 00:00:00 2001 From: Peer Chen Date: Thu, 2 Nov 2006 18:55:48 -0500 Subject: pci_ids.h: Add NVIDIA PCI ID Signed-off-by: Jeff Garzik --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f3a168f3c9df..fa4e1d799782 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1213,6 +1213,7 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 #define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452 #define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_TT128 0x9128 -- cgit v1.2.3-71-gd317 From 86f4f0f9ba6e35fbbc409dfc3d8615c1a9822482 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 2 Nov 2006 22:07:05 -0800 Subject: [PATCH] fix UFS superblock alignment issues ufs2 fails to mount on x86_64, claiming bad magic. This is because ufs_super_block_third's fs_un1 member is padded out by 4 bytes for 8-byte alignment, pushing down the rest of the struct. Forcing this to be packed solves it. I took a quick look over other on-disk structures and didn't immediately find other problems. I was able to mount & ls a populated ufs2 filesystem w/ this change. Signed-off-by: Eric Sandeen Cc: Evgeniy Dushistov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ufs_fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index 61eef508b041..28967eda9d7b 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h @@ -908,7 +908,7 @@ struct ufs_super_block_third { __fs64 fs_csaddr; /* blk addr of cyl grp summary area */ __fs64 fs_pendingblocks;/* blocks in process of being freed */ __fs32 fs_pendinginodes;/*inodes in process of being freed */ - } fs_u2; + } __attribute__ ((packed)) fs_u2; } fs_un1; union { struct { -- cgit v1.2.3-71-gd317 From f46c483357c2d87606bbefb511321e3efd4baae0 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 2 Nov 2006 22:07:16 -0800 Subject: [PATCH] Add printk_timed_ratelimit() printk_ratelimit() has global state which makes it not useful for callers which wish to perform ratelimiting at a particular frequency. Add a printk_timed_ratelimit() which utilises caller-provided state storage to permit more flexibility. This function can in fact be used for things other than printk ratelimiting and is perhaps poorly named. Cc: Ulrich Drepper Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 2 ++ kernel/printk.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 80f39cab470a..24b611147adb 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -171,6 +171,8 @@ __attribute_const__ roundup_pow_of_two(unsigned long x) extern int printk_ratelimit(void); extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst); +extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msec); static inline void console_silent(void) { diff --git a/kernel/printk.c b/kernel/printk.c index f7d427ef5038..66426552fbfe 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -1101,3 +1102,23 @@ int printk_ratelimit(void) printk_ratelimit_burst); } EXPORT_SYMBOL(printk_ratelimit); + +/** + * printk_timed_ratelimit - caller-controlled printk ratelimiting + * @caller_jiffies: pointer to caller's state + * @interval_msecs: minimum interval between prints + * + * printk_timed_ratelimit() returns true if more than @interval_msecs + * milliseconds have elapsed since the last time printk_timed_ratelimit() + * returned true. + */ +bool printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msecs) +{ + if (*caller_jiffies == 0 || time_after(jiffies, *caller_jiffies)) { + *caller_jiffies = jiffies + msecs_to_jiffies(interval_msecs); + return true; + } + return false; +} +EXPORT_SYMBOL(printk_timed_ratelimit); -- cgit v1.2.3-71-gd317 From b918f6e62cd46774f9fc0a3fbba6bd10ad85ee14 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 2 Nov 2006 22:07:19 -0800 Subject: [PATCH] swsusp: debugging Add a swsusp debugging mode. This does everything that's needed for a suspend except for actually suspending. So we can look in the log messages and work out a) what code is being slow and b) which drivers are misbehaving. (1) # echo testproc > /sys/power/disk # echo disk > /sys/power/state This should turn off the non-boot CPU, freeze all processes, wait for 5 seconds and then thaw the processes and the CPU. (2) # echo test > /sys/power/disk # echo disk > /sys/power/state This should turn off the non-boot CPU, freeze all processes, shrink memory, suspend all devices, wait for 5 seconds, resume the devices etc. Cc: Pavel Machek Cc: Stefan Seyfried Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-power | 17 +++++++++++++++- Documentation/power/interface.txt | 13 ++++++++++++ include/linux/pm.h | 4 +++- kernel/power/disk.c | 37 ++++++++++++++++++++++++++--------- 4 files changed, 60 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index d882f8093871..dcff4d0623ad 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -21,7 +21,7 @@ Description: these states. What: /sys/power/disk -Date: August 2006 +Date: September 2006 Contact: Rafael J. Wysocki Description: The /sys/power/disk file controls the operating mode of the @@ -39,6 +39,19 @@ Description: 'reboot' - the memory image will be saved by the kernel and the system will be rebooted. + Additionally, /sys/power/disk can be used to turn on one of the + two testing modes of the suspend-to-disk mechanism: 'testproc' + or 'test'. If the suspend-to-disk mechanism is in the + 'testproc' mode, writing 'disk' to /sys/power/state will cause + the kernel to disable nonboot CPUs and freeze tasks, wait for 5 + seconds, unfreeze tasks and enable nonboot CPUs. If it is in + the 'test' mode, writing 'disk' to /sys/power/state will cause + the kernel to disable nonboot CPUs and freeze tasks, shrink + memory, suspend devices, wait for 5 seconds, resume devices, + unfreeze tasks and enable nonboot CPUs. Then, we are able to + look in the log messages and work out, for example, which code + is being slow and which device drivers are misbehaving. + The suspend-to-disk method may be chosen by writing to this file one of the accepted strings: @@ -46,6 +59,8 @@ Description: 'platform' 'shutdown' 'reboot' + 'testproc' + 'test' It will only change to 'firmware' or 'platform' if the system supports that. diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt index a66bec222b16..74311d7e0f3c 100644 --- a/Documentation/power/interface.txt +++ b/Documentation/power/interface.txt @@ -30,6 +30,17 @@ testing). The system will support either 'firmware' or 'platform', and that is known a priori. But, the user may choose 'shutdown' or 'reboot' as alternatives. +Additionally, /sys/power/disk can be used to turn on one of the two testing +modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the +suspend-to-disk mechanism is in the 'testproc' mode, writing 'disk' to +/sys/power/state will cause the kernel to disable nonboot CPUs and freeze +tasks, wait for 5 seconds, unfreeze tasks and enable nonboot CPUs. If it is +in the 'test' mode, writing 'disk' to /sys/power/state will cause the kernel +to disable nonboot CPUs and freeze tasks, shrink memory, suspend devices, wait +for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then, +we are able to look in the log messages and work out, for example, which code +is being slow and which device drivers are misbehaving. + Reading from this file will display what the mode is currently set to. Writing to this file will accept one of @@ -37,6 +48,8 @@ to. Writing to this file will accept one of 'platform' 'shutdown' 'reboot' + 'testproc' + 'test' It will only change to 'firmware' or 'platform' if the system supports it. diff --git a/include/linux/pm.h b/include/linux/pm.h index 6b27e07aef19..070394e846d0 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -116,7 +116,9 @@ typedef int __bitwise suspend_disk_method_t; #define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2) #define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3) #define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4) -#define PM_DISK_MAX ((__force suspend_disk_method_t) 5) +#define PM_DISK_TEST ((__force suspend_disk_method_t) 5) +#define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6) +#define PM_DISK_MAX ((__force suspend_disk_method_t) 7) struct pm_ops { suspend_disk_method_t pm_disk_mode; diff --git a/kernel/power/disk.c b/kernel/power/disk.c index d3a158a60312..b1fb7866b0b3 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -71,7 +71,7 @@ static inline void platform_finish(void) static int prepare_processes(void) { - int error; + int error = 0; pm_prepare_console(); @@ -84,6 +84,12 @@ static int prepare_processes(void) goto thaw; } + if (pm_disk_mode == PM_DISK_TESTPROC) { + printk("swsusp debug: Waiting for 5 seconds.\n"); + mdelay(5000); + goto thaw; + } + /* Free memory before shutting down devices. */ if (!(error = swsusp_shrink_memory())) return 0; @@ -120,13 +126,21 @@ int pm_suspend_disk(void) if (error) return error; + if (pm_disk_mode == PM_DISK_TESTPROC) + goto Thaw; + suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) { resume_console(); printk("Some devices failed to suspend\n"); - unprepare_processes(); - return error; + goto Thaw; + } + + if (pm_disk_mode == PM_DISK_TEST) { + printk("swsusp debug: Waiting for 5 seconds.\n"); + mdelay(5000); + goto Done; } pr_debug("PM: snapshotting memory.\n"); @@ -143,16 +157,17 @@ int pm_suspend_disk(void) power_down(pm_disk_mode); else { swsusp_free(); - unprepare_processes(); - return error; + goto Thaw; } - } else + } else { pr_debug("PM: Image restored successfully.\n"); + } swsusp_free(); Done: device_resume(); resume_console(); + Thaw: unprepare_processes(); return error; } @@ -249,6 +264,8 @@ static const char * const pm_disk_modes[] = { [PM_DISK_PLATFORM] = "platform", [PM_DISK_SHUTDOWN] = "shutdown", [PM_DISK_REBOOT] = "reboot", + [PM_DISK_TEST] = "test", + [PM_DISK_TESTPROC] = "testproc", }; /** @@ -303,17 +320,19 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n) } } if (mode) { - if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT) + if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT || + mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) { pm_disk_mode = mode; - else { + } else { if (pm_ops && pm_ops->enter && (mode == pm_ops->pm_disk_mode)) pm_disk_mode = mode; else error = -EINVAL; } - } else + } else { error = -EINVAL; + } pr_debug("PM: suspend-to-disk mode set to '%s'\n", pm_disk_modes[mode]); -- cgit v1.2.3-71-gd317 From 3fd593979802f81ff6452596ac61e3840f917589 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 2 Nov 2006 22:07:24 -0800 Subject: [PATCH] Create compat_sys_migrate_pages This is needed on bigendian 64bit architectures. Signed-off-by: Stephen Rothwell Acked-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compat.h | 4 ++++ kernel/compat.c | 33 +++++++++++++++++++++++++++++++++ kernel/sys_ni.c | 1 + 3 files changed, 38 insertions(+) (limited to 'include/linux') diff --git a/include/linux/compat.h b/include/linux/compat.h index f1553196826f..80b17f440ec1 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -230,5 +230,9 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); extern int compat_printk(const char *fmt, ...); extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); +asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, + compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, + const compat_ulong_t __user *new_nodes); + #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ diff --git a/kernel/compat.c b/kernel/compat.c index d4898aad6cfa..6952dd057300 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -982,4 +982,37 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, } return sys_move_pages(pid, nr_pages, pages, nodes, status, flags); } + +asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, + compat_ulong_t maxnode, + const compat_ulong_t __user *old_nodes, + const compat_ulong_t __user *new_nodes) +{ + unsigned long __user *old = NULL; + unsigned long __user *new = NULL; + nodemask_t tmp_mask; + unsigned long nr_bits; + unsigned long size; + + nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES); + size = ALIGN(nr_bits, BITS_PER_LONG) / 8; + if (old_nodes) { + if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits)) + return -EFAULT; + old = compat_alloc_user_space(new_nodes ? size * 2 : size); + if (new_nodes) + new = old + size / sizeof(unsigned long); + if (copy_to_user(old, nodes_addr(tmp_mask), size)) + return -EFAULT; + } + if (new_nodes) { + if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits)) + return -EFAULT; + if (new == NULL) + new = compat_alloc_user_space(size); + if (copy_to_user(new, nodes_addr(tmp_mask), size)) + return -EFAULT; + } + return sys_migrate_pages(pid, nr_bits + 1, old, new); +} #endif diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 0e53314b14de..d7306d0f3dfc 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -135,6 +135,7 @@ cond_syscall(sys_madvise); cond_syscall(sys_mremap); cond_syscall(sys_remap_file_pages); cond_syscall(compat_sys_move_pages); +cond_syscall(compat_sys_migrate_pages); /* block-layer dependent */ cond_syscall(sys_bdflush); -- cgit v1.2.3-71-gd317 From 4833ed094097323f5f219820f6ebdc8dd66f501f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 3 Nov 2006 00:27:06 -0800 Subject: [IPX]: Trivial parts of endianness annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/ipx.h | 14 +++++++------- include/net/ipx.h | 22 +++++++++++----------- net/ipx/af_ipx.c | 54 ++++++++++++++++++++++++++--------------------------- net/ipx/ipx_proc.c | 12 ++++++------ net/ipx/ipx_route.c | 10 +++++----- 5 files changed, 56 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipx.h b/include/linux/ipx.h index 4f29c60964c4..eb19b4ea84f4 100644 --- a/include/linux/ipx.h +++ b/include/linux/ipx.h @@ -7,8 +7,8 @@ struct sockaddr_ipx { sa_family_t sipx_family; - __u16 sipx_port; - __u32 sipx_network; + __be16 sipx_port; + __be32 sipx_network; unsigned char sipx_node[IPX_NODE_LEN]; __u8 sipx_type; unsigned char sipx_zero; /* 16 byte fill */ @@ -23,13 +23,13 @@ struct sockaddr_ipx { #define IPX_CRTITF 1 struct ipx_route_definition { - __u32 ipx_network; - __u32 ipx_router_network; + __be32 ipx_network; + __be32 ipx_router_network; unsigned char ipx_router_node[IPX_NODE_LEN]; }; struct ipx_interface_definition { - __u32 ipx_network; + __be32 ipx_network; unsigned char ipx_device[16]; unsigned char ipx_dlink_type; #define IPX_FRAME_NONE 0 @@ -55,8 +55,8 @@ struct ipx_config_data { */ struct ipx_route_def { - __u32 ipx_network; - __u32 ipx_router_network; + __be32 ipx_network; + __be32 ipx_router_network; #define IPX_ROUTE_NO_ROUTER 0 unsigned char ipx_router_node[IPX_NODE_LEN]; unsigned char ipx_device[16]; diff --git a/include/net/ipx.h b/include/net/ipx.h index 5c0cf33826c5..4a423d2695ba 100644 --- a/include/net/ipx.h +++ b/include/net/ipx.h @@ -15,9 +15,9 @@ #include struct ipx_address { - __u32 net; + __be32 net; __u8 node[IPX_NODE_LEN]; - __u16 sock; + __be16 sock; }; #define ipx_broadcast_node "\377\377\377\377\377\377" @@ -28,7 +28,7 @@ struct ipx_address { struct ipxhdr { __u16 ipx_checksum __attribute__ ((packed)); #define IPX_NO_CHECKSUM 0xFFFF - __u16 ipx_pktsize __attribute__ ((packed)); + __be16 ipx_pktsize __attribute__ ((packed)); __u8 ipx_tctrl; __u8 ipx_type; #define IPX_TYPE_UNKNOWN 0x00 @@ -48,14 +48,14 @@ static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb) struct ipx_interface { /* IPX address */ - __u32 if_netnum; + __be32 if_netnum; unsigned char if_node[IPX_NODE_LEN]; atomic_t refcnt; /* physical device info */ struct net_device *if_dev; struct datalink_proto *if_dlink; - unsigned short if_dlink_type; + __be16 if_dlink_type; /* socket support */ unsigned short if_sknum; @@ -71,7 +71,7 @@ struct ipx_interface { }; struct ipx_route { - __u32 ir_net; + __be32 ir_net; struct ipx_interface *ir_intrfc; unsigned char ir_routed; unsigned char ir_router_node[IPX_NODE_LEN]; @@ -82,10 +82,10 @@ struct ipx_route { #ifdef __KERNEL__ struct ipx_cb { u8 ipx_tctrl; - u32 ipx_dest_net; - u32 ipx_source_net; + __be32 ipx_dest_net; + __be32 ipx_source_net; struct { - u32 netnum; + __be32 netnum; int index; } last_hop; }; @@ -97,7 +97,7 @@ struct ipx_sock { struct sock sk; struct ipx_address dest_addr; struct ipx_interface *intrfc; - unsigned short port; + __be16 port; #ifdef CONFIG_IPX_INTERN unsigned char node[IPX_NODE_LEN]; #endif @@ -132,7 +132,7 @@ extern struct ipx_interface *ipx_primary_net; extern int ipx_proc_init(void); extern void ipx_proc_exit(void); -extern const char *ipx_frame_name(unsigned short); +extern const char *ipx_frame_name(__be16); extern const char *ipx_device_name(struct ipx_interface *intrfc); static __inline__ void ipxitf_hold(struct ipx_interface *intrfc) diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index bef3f61569f7..c272a38af325 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -83,13 +83,13 @@ DEFINE_SPINLOCK(ipx_interfaces_lock); struct ipx_interface *ipx_primary_net; struct ipx_interface *ipx_internal_net; -extern int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc, +extern int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc, unsigned char *node); extern void ipxrtr_del_routes(struct ipx_interface *intrfc); extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, struct iovec *iov, int len, int noblock); extern int ipxrtr_route_skb(struct sk_buff *skb); -extern struct ipx_route *ipxrtr_lookup(__u32 net); +extern struct ipx_route *ipxrtr_lookup(__be32 net); extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg); #undef IPX_REFCNT_DEBUG @@ -177,7 +177,7 @@ static void ipxitf_clear_primary_net(void) } static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev, - unsigned short datalink) + __be16 datalink) { struct ipx_interface *i; @@ -190,7 +190,7 @@ out: } static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev, - unsigned short datalink) + __be16 datalink) { struct ipx_interface *i; @@ -202,7 +202,7 @@ static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev, return i; } -struct ipx_interface *ipxitf_find_using_net(__u32 net) +struct ipx_interface *ipxitf_find_using_net(__be32 net) { struct ipx_interface *i; @@ -237,7 +237,7 @@ static void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk) /* caller must hold intrfc->if_sklist_lock */ static struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc, - unsigned short port) + __be16 port) { struct sock *s; struct hlist_node *node; @@ -252,7 +252,7 @@ found: /* caller must hold a reference to intrfc */ static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc, - unsigned short port) + __be16 port) { struct sock *s; @@ -268,7 +268,7 @@ static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc, #ifdef CONFIG_IPX_INTERN static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc, unsigned char *ipx_node, - unsigned short port) + __be16 port) { struct sock *s; struct hlist_node *node; @@ -600,10 +600,10 @@ int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node) /* see if we need to include the netnum in the route list */ if (IPX_SKB_CB(skb)->last_hop.index >= 0) { - u32 *last_hop = (u32 *)(((u8 *) skb->data) + + __be32 *last_hop = (__be32 *)(((u8 *) skb->data) + sizeof(struct ipxhdr) + IPX_SKB_CB(skb)->last_hop.index * - sizeof(u32)); + sizeof(__be32)); *last_hop = IPX_SKB_CB(skb)->last_hop.netnum; IPX_SKB_CB(skb)->last_hop.index = -1; } @@ -772,7 +772,7 @@ static void ipxitf_discover_netnum(struct ipx_interface *intrfc, } else { printk(KERN_WARNING "IPX: Network number collision " "%lx\n %s %s and %s %s\n", - (unsigned long) htonl(cb->ipx_source_net), + (unsigned long) ntohl(cb->ipx_source_net), ipx_device_name(i), ipx_frame_name(i->if_dlink_type), ipx_device_name(intrfc), @@ -812,7 +812,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) int i, rc = -EINVAL; struct ipx_interface *ifcs; char *c; - u32 *l; + __be32 *l; /* Illegal packet - too many hops or too short */ /* We decide to throw it away: no broadcasting, no local processing. @@ -833,7 +833,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) goto out; c = ((u8 *) ipx) + sizeof(struct ipxhdr); - l = (u32 *) c; + l = (__be32 *) c; /* Don't broadcast packet if already seen this net */ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) @@ -855,7 +855,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) /* That aren't in the list */ if (ifcs == intrfc) continue; - l = (__u32 *) c; + l = (__be32 *) c; /* don't consider the last entry in the packet list, * it is our netnum, and it is not there yet */ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) @@ -885,8 +885,8 @@ static void ipxitf_insert(struct ipx_interface *intrfc) ipx_primary_net = intrfc; } -static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum, - unsigned short dlink_type, +static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __be32 netnum, + __be16 dlink_type, struct datalink_proto *dlink, unsigned char internal, int ipx_offset) @@ -960,7 +960,7 @@ static __be16 ipx_map_frame_type(unsigned char type) static int ipxitf_create(struct ipx_interface_definition *idef) { struct net_device *dev; - unsigned short dlink_type = 0; + __be16 dlink_type = 0; struct datalink_proto *datalink = NULL; struct ipx_interface *intrfc; int rc; @@ -1073,7 +1073,7 @@ out: static int ipxitf_delete(struct ipx_interface_definition *idef) { struct net_device *dev = NULL; - unsigned short dlink_type = 0; + __be16 dlink_type = 0; struct ipx_interface *intrfc; int rc = 0; @@ -1110,7 +1110,7 @@ out: } static struct ipx_interface *ipxitf_auto_create(struct net_device *dev, - unsigned short dlink_type) + __be16 dlink_type) { struct ipx_interface *intrfc = NULL; struct datalink_proto *datalink; @@ -1122,7 +1122,7 @@ static struct ipx_interface *ipxitf_auto_create(struct net_device *dev, if (dev->addr_len > IPX_NODE_LEN) goto out; - switch (htons(dlink_type)) { + switch (ntohs(dlink_type)) { case ETH_P_IPX: datalink = pEII_datalink; break; case ETH_P_802_2: datalink = p8022_datalink; break; case ETH_P_SNAP: datalink = pSNAP_datalink; break; @@ -1266,7 +1266,7 @@ __u16 ipx_cksum(struct ipxhdr *packet, int length) return ~sum; } -const char *ipx_frame_name(unsigned short frame) +const char *ipx_frame_name(__be16 frame) { char* rc = "None"; @@ -1401,7 +1401,7 @@ out: /* caller must hold a reference to intrfc */ -static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc) +static __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc) { unsigned short socketNum = intrfc->if_sknum; @@ -1410,7 +1410,7 @@ static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc) if (socketNum < IPX_MIN_EPHEMERAL_SOCKET) socketNum = IPX_MIN_EPHEMERAL_SOCKET; - while (__ipxitf_find_socket(intrfc, ntohs(socketNum))) + while (__ipxitf_find_socket(intrfc, htons(socketNum))) if (socketNum > IPX_MAX_EPHEMERAL_SOCKET) socketNum = IPX_MIN_EPHEMERAL_SOCKET; else @@ -1419,7 +1419,7 @@ static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc) spin_unlock_bh(&intrfc->if_sklist_lock); intrfc->if_sknum = socketNum; - return ntohs(socketNum); + return htons(socketNum); } static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) @@ -1473,7 +1473,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ipxs->port)) { SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", - ntohs((int)addr->sipx_port)); + ntohs(addr->sipx_port)); goto out_put; } } else { @@ -1488,7 +1488,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (ipxitf_find_socket(intrfc, addr->sipx_port)) { SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", - ntohs((int)addr->sipx_port)); + ntohs(addr->sipx_port)); goto out_put; } } @@ -1665,7 +1665,7 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty intrfc = ipxitf_find_using_phys(dev, pt->type); if (!intrfc) { if (ipxcfg_auto_create_interfaces && - ntohl(IPX_SKB_CB(skb)->ipx_dest_net)) { + IPX_SKB_CB(skb)->ipx_dest_net) { intrfc = ipxitf_auto_create(dev, pt->type); if (intrfc) ipxitf_hold(intrfc); diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c index 4c0c71206e54..b7463dfca63e 100644 --- a/net/ipx/ipx_proc.c +++ b/net/ipx/ipx_proc.c @@ -260,22 +260,22 @@ static int ipx_seq_socket_show(struct seq_file *seq, void *v) ipxs = ipx_sk(s); #ifdef CONFIG_IPX_INTERN seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", - (unsigned long)htonl(ipxs->intrfc->if_netnum), + (unsigned long)ntohl(ipxs->intrfc->if_netnum), ipxs->node[0], ipxs->node[1], ipxs->node[2], ipxs->node[3], - ipxs->node[4], ipxs->node[5], htons(ipxs->port)); + ipxs->node[4], ipxs->node[5], ntohs(ipxs->port)); #else - seq_printf(seq, "%08lX:%04X ", (unsigned long) htonl(ipxs->intrfc->if_netnum), - htons(ipxs->port)); + seq_printf(seq, "%08lX:%04X ", (unsigned long) ntohl(ipxs->intrfc->if_netnum), + ntohs(ipxs->port)); #endif /* CONFIG_IPX_INTERN */ if (s->sk_state != TCP_ESTABLISHED) seq_printf(seq, "%-28s", "Not_Connected"); else { seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", - (unsigned long)htonl(ipxs->dest_addr.net), + (unsigned long)ntohl(ipxs->dest_addr.net), ipxs->dest_addr.node[0], ipxs->dest_addr.node[1], ipxs->dest_addr.node[2], ipxs->dest_addr.node[3], ipxs->dest_addr.node[4], ipxs->dest_addr.node[5], - htons(ipxs->dest_addr.sock)); + ntohs(ipxs->dest_addr.sock)); } seq_printf(seq, "%08X %08X %02X %03d\n", diff --git a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c index a30dbb1e08fb..8bfaefaf8841 100644 --- a/net/ipx/ipx_route.c +++ b/net/ipx/ipx_route.c @@ -20,16 +20,16 @@ DEFINE_RWLOCK(ipx_routes_lock); extern struct ipx_interface *ipx_internal_net; extern __u16 ipx_cksum(struct ipxhdr *packet, int length); -extern struct ipx_interface *ipxitf_find_using_net(__u32 net); +extern struct ipx_interface *ipxitf_find_using_net(__be32 net); extern int ipxitf_demux_socket(struct ipx_interface *intrfc, struct sk_buff *skb, int copy); extern int ipxitf_demux_socket(struct ipx_interface *intrfc, struct sk_buff *skb, int copy); extern int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node); -extern struct ipx_interface *ipxitf_find_using_net(__u32 net); +extern struct ipx_interface *ipxitf_find_using_net(__be32 net); -struct ipx_route *ipxrtr_lookup(__u32 net) +struct ipx_route *ipxrtr_lookup(__be32 net) { struct ipx_route *r; @@ -48,7 +48,7 @@ unlock: /* * Caller must hold a reference to intrfc */ -int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc, +int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc, unsigned char *node) { struct ipx_route *rt; @@ -118,7 +118,7 @@ out: return rc; } -static int ipxrtr_delete(__u32 net) +static int ipxrtr_delete(__be32 net) { struct ipx_route *r, *tmp; int rc; -- cgit v1.2.3-71-gd317 From d99f160ac53e51090f015a8f0617cea25f81a191 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 5 Nov 2006 23:52:12 -0800 Subject: [PATCH] sysctl: allow a zero ctl_name in the middle of a sysctl table Since it is becoming clear that there are just enough users of the binary sysctl interface that completely removing the binary interface from the kernel will not be an option for foreseeable future, we need to find a way to address the sysctl maintenance issues. The basic problem is that sysctl requires one central authority to allocate sysctl numbers, or else conflicts and ABI breakage occur. The proc interface to sysctl does not have that problem, as names are not densely allocated. By not terminating a sysctl table until I have neither a ctl_name nor a procname, it becomes simple to add sysctl entries that don't show up in the binary sysctl interface. Which allows people to avoid allocating a binary sysctl value when not needed. I have audited the kernel code and in my reading I have not found a single sysctl table that wasn't terminated by a completely zero filled entry. So this change in behavior should not affect anything. I think this mechanism eases the pain enough that combined with a little disciple we can solve the reoccurring sysctl ABI breakage. Signed-off-by: Eric W. Biederman Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sysctl.h | 9 ++++++--- kernel/sysctl.c | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 1b24bd45e080..c184732a70fc 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -961,8 +961,8 @@ extern ctl_handler sysctl_ms_jiffies; /* * Register a set of sysctl names by calling register_sysctl_table * with an initialised array of ctl_table's. An entry with zero - * ctl_name terminates the table. table->de will be set up by the - * registration and need not be initialised in advance. + * ctl_name and NULL procname terminates the table. table->de will be + * set up by the registration and need not be initialised in advance. * * sysctl names can be mirrored automatically under /proc/sys. The * procname supplied controls /proc naming. @@ -973,7 +973,10 @@ extern ctl_handler sysctl_ms_jiffies; * Leaf nodes in the sysctl tree will be represented by a single file * under /proc; non-leaf nodes will be represented by directories. A * null procname disables /proc mirroring at this node. - * + * + * sysctl entries with a zero ctl_name will not be available through + * the binary sysctl interface. + * * sysctl(2) can automatically manage read and write requests through * the sysctl table. The data and maxlen fields of the ctl_table * struct enable minimal validation of the values being written to be diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 0c8e805bbd6f..09e569f4792b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1315,7 +1315,9 @@ repeat: return -ENOTDIR; if (get_user(n, name)) return -EFAULT; - for ( ; table->ctl_name; table++) { + for ( ; table->ctl_name || table->procname; table++) { + if (!table->ctl_name) + continue; if (n == table->ctl_name || table->ctl_name == CTL_ANY) { int error; if (table->child) { @@ -1532,7 +1534,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, int len; mode_t mode; - for (; table->ctl_name; table++) { + for (; table->ctl_name || table->procname; table++) { /* Can't do anything without a proc name. */ if (!table->procname) continue; @@ -1579,7 +1581,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) { struct proc_dir_entry *de; - for (; table->ctl_name; table++) { + for (; table->ctl_name || table->procname; table++) { if (!(de = table->de)) continue; if (de->mode & S_IFDIR) { -- cgit v1.2.3-71-gd317 From 7cc13edc139108bb527b692f0548dce6bc648572 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 5 Nov 2006 23:52:13 -0800 Subject: [PATCH] sysctl: implement CTL_UNNUMBERED This patch takes the CTL_UNNUMBERD concept from NFS and makes it available to all new sysctl users. At the same time the sysctl binary interface maintenance documentation is updated to mention and to describe what is needed to successfully maintain the sysctl binary interface. Signed-off-by: Eric W. Biederman Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/svc.c | 3 --- fs/nfs/sysctl.c | 5 ----- include/linux/sysctl.h | 14 +++++++++++--- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 634139232aaf..8ca18085e68d 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -353,9 +353,6 @@ EXPORT_SYMBOL(lockd_down); * Sysctl parameters (same as module parameters, different interface). */ -/* Something that isn't CTL_ANY, CTL_NONE or a value that may clash. */ -#define CTL_UNNUMBERED -2 - static ctl_table nlm_sysctls[] = { { .ctl_name = CTL_UNNUMBERED, diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 2fe3403c2409..3ea50ac64820 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c @@ -18,11 +18,6 @@ static const int nfs_set_port_min = 0; static const int nfs_set_port_max = 65535; static struct ctl_table_header *nfs_callback_sysctl_table; -/* - * Something that isn't CTL_ANY, CTL_NONE or a value that may clash. - * Use the same values as fs/lockd/svc.c - */ -#define CTL_UNNUMBERED -2 static ctl_table nfs_cb_sysctls[] = { #ifdef CONFIG_NFS_V4 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index c184732a70fc..d98562f1df76 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -6,10 +6,17 @@ **************************************************************** **************************************************************** ** + ** WARNING: ** The values in this file are exported to user space via - ** the sysctl() binary interface. However this interface - ** is unstable and deprecated and will be removed in the future. - ** For a stable interface use /proc/sys. + ** the sysctl() binary interface. Do *NOT* change the + ** numbering of any existing values here, and do not change + ** any numbers within any one set of values. If you have to + ** have to redefine an existing interface, use a new number for it. + ** The kernel will then return -ENOTDIR to any application using + ** the old binary interface. + ** + ** For new interfaces unless you really need a binary number + ** please use CTL_UNNUMBERED. ** **************************************************************** **************************************************************** @@ -48,6 +55,7 @@ struct __sysctl_args { #ifdef __KERNEL__ #define CTL_ANY -1 /* Matches any name */ #define CTL_NONE 0 +#define CTL_UNNUMBERED CTL_NONE /* sysctl without a binary number */ #endif enum -- cgit v1.2.3-71-gd317 From 81ac95c5569d7a60ab5db6c1ccec56c12b3ebcb5 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 8 Nov 2006 17:44:40 -0800 Subject: [PATCH] nfsd4: fix open-create permissions In the case where an open creates the file, we shouldn't be rechecking permissions to open the file; the open succeeds regardless of what the new file's mode bits say. This patch fixes the problem, but only by introducing yet another parameter to nfsd_create_v3. This is ugly. This will be fixed by later patches. Signed-off-by: J. Bruce Fields Acked-by: Neil Brown Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfsd/nfs3proc.c | 2 +- fs/nfsd/nfs4proc.c | 6 ++++-- fs/nfsd/vfs.c | 4 +++- include/linux/nfsd/nfsd.h | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 64db601c2bd2..7f5bad0393b1 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -258,7 +258,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, /* Now create the file and set attributes */ nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len, attr, newfhp, - argp->createmode, argp->verf, NULL); + argp->createmode, argp->verf, NULL, NULL); RETURN_STATUS(nfserr); } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 4a73f5b2546f..50bc94243ca1 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -93,6 +93,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o { struct svc_fh resfh; __be32 status; + int created = 0; fh_init(&resfh, NFS4_FHSIZE); open->op_truncate = 0; @@ -105,7 +106,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &open->op_iattr, &resfh, open->op_createmode, - (u32 *)open->op_verf.data, &open->op_truncate); + (u32 *)open->op_verf.data, &open->op_truncate, &created); } else { status = nfsd_lookup(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &resfh); @@ -122,7 +123,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o memcpy(open->op_stateowner->so_replay.rp_openfh, &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size); - status = do_open_permission(rqstp, current_fh, open, MAY_NOP); + if (!created) + status = do_open_permission(rqstp, current_fh, open, MAY_NOP); out: fh_put(&resfh); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index f21e917bb8ed..1a7ad8c983d1 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1237,7 +1237,7 @@ __be32 nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, struct iattr *iap, struct svc_fh *resfhp, int createmode, u32 *verifier, - int *truncp) + int *truncp, int *created) { struct dentry *dentry, *dchild = NULL; struct inode *dirp; @@ -1331,6 +1331,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); if (host_err < 0) goto out_nfserr; + if (created) + *created = 1; if (EX_ISSYNC(fhp->fh_export)) { err = nfserrno(nfsd_sync_dir(dentry)); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index eb231143d579..edb54c3171b3 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -89,7 +89,7 @@ __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); __be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode, - u32 *verifier, int *truncp); + u32 *verifier, int *truncp, int *created); __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, loff_t, unsigned long); #endif /* CONFIG_NFSD_V3 */ -- cgit v1.2.3-71-gd317 From 46d52b09fa6a2d1e313cb75ca352d6f466e67bd1 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 8 Nov 2006 17:44:55 -0800 Subject: [PATCH] IPMI: retry messages on certain error returns Some more errors from the IPMI send message command are retryable, but are not being retried by the IPMI code. Make sure they get retried. Signed-off-by: Corey Minyard Cc: Frederic Lelievre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 4 +++- include/linux/ipmi_msgdefs.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e55a0d276729..0b07ca1b71fa 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3242,7 +3242,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, report the error immediately. */ if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) - && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)) + && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) + && (msg->rsp[2] != IPMI_BUS_ERR) + && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { int chan = msg->rsp[3] & 0xf; diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h index 22f5e2afda4f..4d04d8b58a0a 100644 --- a/include/linux/ipmi_msgdefs.h +++ b/include/linux/ipmi_msgdefs.h @@ -75,6 +75,8 @@ #define IPMI_INVALID_COMMAND_ERR 0xc1 #define IPMI_ERR_MSG_TRUNCATED 0xc6 #define IPMI_LOST_ARBITRATION_ERR 0x81 +#define IPMI_BUS_ERR 0x82 +#define IPMI_NAK_ON_WRITE_ERR 0x83 #define IPMI_ERR_UNSPECIFIED 0xff #define IPMI_CHANNEL_PROTOCOL_IPMB 1 -- cgit v1.2.3-71-gd317 From ec68307cc5a8dc499e48693843bb42f6b6028458 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 8 Nov 2006 17:44:57 -0800 Subject: [PATCH] htirq: refactor so we only have one function that writes to the chip This refactoring actually optimizes the code a little by caching the value that we think the device is programmed with instead of reading it back from the hardware. Which simplifies the code a little and should speed things up a bit. This patch introduces the concept of a ht_irq_msg and modifies the architecture read/write routines to update this code. There is a minor consistency fix here as well as x86_64 forgot to initialize the htirq as masked. Signed-off-by: Eric W. Biederman Cc: Andi Kleen Acked-by: Bryan O'Sullivan Cc: Cc: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 26 ++++++++-------- arch/x86_64/kernel/io_apic.c | 31 +++++++++---------- drivers/pci/htirq.c | 72 +++++++++++++++----------------------------- include/linux/htirq.h | 11 ++++--- 4 files changed, 58 insertions(+), 82 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 507983c513c3..ad84bc2802a6 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2624,18 +2624,16 @@ void arch_teardown_msi_irq(unsigned int irq) static void target_ht_irq(unsigned int irq, unsigned int dest) { - u32 low, high; - low = read_ht_irq_low(irq); - high = read_ht_irq_high(irq); + struct ht_irq_msg msg; + fetch_ht_irq_msg(irq, &msg); - low &= ~(HT_IRQ_LOW_DEST_ID_MASK); - high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); + msg.address_lo &= ~(HT_IRQ_LOW_DEST_ID_MASK); + msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); - low |= HT_IRQ_LOW_DEST_ID(dest); - high |= HT_IRQ_HIGH_DEST_ID(dest); + msg.address_lo |= HT_IRQ_LOW_DEST_ID(dest); + msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); } static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) @@ -2673,7 +2671,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) vector = assign_irq_vector(irq); if (vector >= 0) { - u32 low, high; + struct ht_irq_msg msg; unsigned dest; cpumask_t tmp; @@ -2681,9 +2679,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) cpu_set(vector >> 8, tmp); dest = cpu_mask_to_apicid(tmp); - high = HT_IRQ_HIGH_DEST_ID(dest); + msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); - low = HT_IRQ_LOW_BASE | + msg.address_lo = + HT_IRQ_LOW_BASE | HT_IRQ_LOW_DEST_ID(dest) | HT_IRQ_LOW_VECTOR(vector) | ((INT_DEST_MODE == 0) ? @@ -2695,8 +2694,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) HT_IRQ_LOW_MT_ARBITRATED) | HT_IRQ_LOW_IRQ_MASKED; - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &ht_irq_chip, handle_edge_irq, "edge"); diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 3b8f9c68ad3c..41bfc49301ad 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1955,18 +1955,16 @@ void arch_teardown_msi_irq(unsigned int irq) static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) { - u32 low, high; - low = read_ht_irq_low(irq); - high = read_ht_irq_high(irq); + struct ht_irq_msg msg; + fetch_ht_irq_msg(irq, &msg); - low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); - high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); + msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); + msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); - low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); - high |= HT_IRQ_HIGH_DEST_ID(dest); + msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); + msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); } static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) @@ -1987,7 +1985,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) dest = cpu_mask_to_apicid(tmp); - target_ht_irq(irq, dest, vector & 0xff); + target_ht_irq(irq, dest, vector); set_native_irq_info(irq, mask); } #endif @@ -2010,14 +2008,15 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); if (vector >= 0) { - u32 low, high; + struct ht_irq_msg msg; unsigned dest; dest = cpu_mask_to_apicid(tmp); - high = HT_IRQ_HIGH_DEST_ID(dest); + msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); - low = HT_IRQ_LOW_BASE | + msg.address_lo = + HT_IRQ_LOW_BASE | HT_IRQ_LOW_DEST_ID(dest) | HT_IRQ_LOW_VECTOR(vector) | ((INT_DEST_MODE == 0) ? @@ -2026,10 +2025,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) HT_IRQ_LOW_RQEOI_EDGE | ((INT_DELIVERY_MODE != dest_LowestPrio) ? HT_IRQ_LOW_MT_FIXED : - HT_IRQ_LOW_MT_ARBITRATED); + HT_IRQ_LOW_MT_ARBITRATED) | + HT_IRQ_LOW_IRQ_MASKED; - write_ht_irq_low(irq, low); - write_ht_irq_high(irq, high); + write_ht_irq_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &ht_irq_chip, handle_edge_irq, "edge"); diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 0e27f2404a83..e346fe31f97a 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -27,82 +27,55 @@ struct ht_irq_cfg { struct pci_dev *dev; unsigned pos; unsigned idx; + struct ht_irq_msg msg; }; -void write_ht_irq_low(unsigned int irq, u32 data) -{ - struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); -} - -void write_ht_irq_high(unsigned int irq, u32 data) -{ - struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); -} -u32 read_ht_irq_low(unsigned int irq) +void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { struct ht_irq_cfg *cfg = get_irq_data(irq); unsigned long flags; - u32 data; spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); + if (cfg->msg.address_lo != msg->address_lo) { + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); + pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_lo); + } + if (cfg->msg.address_hi != msg->address_hi) { + pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); + pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi); + } spin_unlock_irqrestore(&ht_irq_lock, flags); - return data; + cfg->msg = *msg; } -u32 read_ht_irq_high(unsigned int irq) +void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { struct ht_irq_cfg *cfg = get_irq_data(irq); - unsigned long flags; - u32 data; - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - spin_unlock_irqrestore(&ht_irq_lock, flags); - return data; + *msg = cfg->msg; } void mask_ht_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - unsigned long flags; - u32 data; + struct ht_irq_msg msg; cfg = get_irq_data(irq); - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - data |= 1; - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); + msg = cfg->msg; + msg.address_lo |= 1; + write_ht_irq_msg(irq, &msg); } void unmask_ht_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - unsigned long flags; - u32 data; + struct ht_irq_msg msg; cfg = get_irq_data(irq); - spin_lock_irqsave(&ht_irq_lock, flags); - pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); - pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); - data &= ~1; - pci_write_config_dword(cfg->dev, cfg->pos + 4, data); - spin_unlock_irqrestore(&ht_irq_lock, flags); + msg = cfg->msg; + msg.address_lo &= ~1; + write_ht_irq_msg(irq, &msg); } /** @@ -152,6 +125,9 @@ int ht_create_irq(struct pci_dev *dev, int idx) cfg->dev = dev; cfg->pos = pos; cfg->idx = 0x10 + (idx * 2); + /* Initialize msg to a value that will never match the first write. */ + cfg->msg.address_lo = 0xffffffff; + cfg->msg.address_hi = 0xffffffff; irq = create_irq(); if (irq < 0) { diff --git a/include/linux/htirq.h b/include/linux/htirq.h index 1f15ce279a23..108f0d91e11e 100644 --- a/include/linux/htirq.h +++ b/include/linux/htirq.h @@ -1,11 +1,14 @@ #ifndef LINUX_HTIRQ_H #define LINUX_HTIRQ_H +struct ht_irq_msg { + u32 address_lo; /* low 32 bits of the ht irq message */ + u32 address_hi; /* high 32 bits of the it irq message */ +}; + /* Helper functions.. */ -void write_ht_irq_low(unsigned int irq, u32 data); -void write_ht_irq_high(unsigned int irq, u32 data); -u32 read_ht_irq_low(unsigned int irq); -u32 read_ht_irq_high(unsigned int irq); +void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg); +void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg); void mask_ht_irq(unsigned int irq); void unmask_ht_irq(unsigned int irq); -- cgit v1.2.3-71-gd317 From 43539c38cd8edb915d1f0e1f55dcb70638b4cc8e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 8 Nov 2006 17:44:57 -0800 Subject: [PATCH] htirq: allow buggy drivers of buggy hardware to write the registers This patch adds a variant of ht_create_irq __ht_create_irq that takes an aditional parameter update that is a function that is called whenever we want to write to a drivers htirq configuration registers. This is needed to support the ipath_iba6110 because it's registers in the proper location are not actually conected to the hardware that controlls interrupt delivery. [bos@serpentine.com: fixes] Signed-off-by: Eric W. Biederman Cc: Andi Kleen Cc: Cc: Roland Dreier Signed-off-by: Bryan O'Sullivan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/htirq.c | 29 ++++++++++++++++++++++++----- include/linux/htirq.h | 5 +++++ 2 files changed, 29 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index e346fe31f97a..0a8d1cce9fa0 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(ht_irq_lock); struct ht_irq_cfg { struct pci_dev *dev; + /* Update callback used to cope with buggy hardware */ + ht_irq_update_t *update; unsigned pos; unsigned idx; struct ht_irq_msg msg; @@ -44,6 +46,8 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi); } + if (cfg->update) + cfg->update(cfg->dev, irq, msg); spin_unlock_irqrestore(&ht_irq_lock, flags); cfg->msg = *msg; } @@ -79,16 +83,14 @@ void unmask_ht_irq(unsigned int irq) } /** - * ht_create_irq - create an irq and attach it to a device. + * __ht_create_irq - create an irq and attach it to a device. * @dev: The hypertransport device to find the irq capability on. * @idx: Which of the possible irqs to attach to. - * - * ht_create_irq is needs to be called for all hypertransport devices - * that generate irqs. + * @update: Function to be called when changing the htirq message * * The irq number of the new irq or a negative error value is returned. */ -int ht_create_irq(struct pci_dev *dev, int idx) +int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) { struct ht_irq_cfg *cfg; unsigned long flags; @@ -123,6 +125,7 @@ int ht_create_irq(struct pci_dev *dev, int idx) return -ENOMEM; cfg->dev = dev; + cfg->update = update; cfg->pos = pos; cfg->idx = 0x10 + (idx * 2); /* Initialize msg to a value that will never match the first write. */ @@ -144,6 +147,21 @@ int ht_create_irq(struct pci_dev *dev, int idx) return irq; } +/** + * ht_create_irq - create an irq and attach it to a device. + * @dev: The hypertransport device to find the irq capability on. + * @idx: Which of the possible irqs to attach to. + * + * ht_create_irq needs to be called for all hypertransport devices + * that generate irqs. + * + * The irq number of the new irq or a negative error value is returned. + */ +int ht_create_irq(struct pci_dev *dev, int idx) +{ + return __ht_create_irq(dev, idx, NULL); +} + /** * ht_destroy_irq - destroy an irq created with ht_create_irq * @@ -162,5 +180,6 @@ void ht_destroy_irq(unsigned int irq) kfree(cfg); } +EXPORT_SYMBOL(__ht_create_irq); EXPORT_SYMBOL(ht_create_irq); EXPORT_SYMBOL(ht_destroy_irq); diff --git a/include/linux/htirq.h b/include/linux/htirq.h index 108f0d91e11e..c96ea46737d0 100644 --- a/include/linux/htirq.h +++ b/include/linux/htirq.h @@ -15,4 +15,9 @@ void unmask_ht_irq(unsigned int irq); /* The arch hook for getting things started */ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev); +/* For drivers of buggy hardware */ +typedef void (ht_irq_update_t)(struct pci_dev *dev, int irq, + struct ht_irq_msg *msg); +int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update); + #endif /* LINUX_HTIRQ_H */ -- cgit v1.2.3-71-gd317 From 2b4ac44e7c7e16cf9411b81693ff3e604f332bf1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Nov 2006 12:27:48 -0800 Subject: [PATCH] vmalloc: optimization, cleanup, bugfixes - reorder 'struct vm_struct' to speedup lookups on CPUS with small cache lines. The fields 'next,addr,size' should be now in the same cache line, to speedup lookups. - One minor cleanup in __get_vm_area_node() - Bugfixes in vmalloc_user() and vmalloc_32_user() NULL returns from __vmalloc() and __find_vm_area() were not tested. [akpm@osdl.org: remove redundant BUG_ONs] Signed-off-by: Eric Dumazet Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 3 ++- mm/vmalloc.c | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index dc9a29d84abc..924e502905d4 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -23,13 +23,14 @@ struct vm_area_struct; #endif struct vm_struct { + /* keep next,addr,size together to speedup lookups */ + struct vm_struct *next; void *addr; unsigned long size; unsigned long flags; struct page **pages; unsigned int nr_pages; unsigned long phys_addr; - struct vm_struct *next; }; /* diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 46606c133e82..7dc6aa745166 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -186,10 +186,8 @@ static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long fl if (unlikely(!area)) return NULL; - if (unlikely(!size)) { - kfree (area); + if (unlikely(!size)) return NULL; - } /* * We always allocate a guard page. @@ -532,11 +530,12 @@ void *vmalloc_user(unsigned long size) void *ret; ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); - write_lock(&vmlist_lock); - area = __find_vm_area(ret); - area->flags |= VM_USERMAP; - write_unlock(&vmlist_lock); - + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + } return ret; } EXPORT_SYMBOL(vmalloc_user); @@ -605,11 +604,12 @@ void *vmalloc_32_user(unsigned long size) void *ret; ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); - write_lock(&vmlist_lock); - area = __find_vm_area(ret); - area->flags |= VM_USERMAP; - write_unlock(&vmlist_lock); - + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + } return ret; } EXPORT_SYMBOL(vmalloc_32_user); -- cgit v1.2.3-71-gd317 From d8b295f29091310d746509bb6d5828aaf4907a18 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 10 Nov 2006 12:27:53 -0800 Subject: [PATCH] Fix missing parens in set_personality() If you call set_personality() with an expression such as: set_personality(foo ? PERS_FOO1 : PERS_FOO2); then this evaluates to: ((current->personality == foo ? PERS_FOO1 : PERS_FOO2) ? ... which is obviously not the intended result. Add the missing parents to ensure this gets evaluated as expected: ((current->personality == (foo ? PERS_FOO1 : PERS_FOO2)) ? ... Signed-off-by: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/personality.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/personality.h b/include/linux/personality.h index bf4cf2080e5c..012cd558189b 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -114,7 +114,7 @@ struct exec_domain { * Change personality of the currently running process. */ #define set_personality(pers) \ - ((current->personality == pers) ? 0 : __set_personality(pers)) + ((current->personality == (pers)) ? 0 : __set_personality(pers)) #endif /* __KERNEL__ */ -- cgit v1.2.3-71-gd317 From 68589bc353037f233fe510ad9ff432338c95db66 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 14 Nov 2006 02:03:32 -0800 Subject: [PATCH] hugetlb: prepare_hugepage_range check offset too (David:) If hugetlbfs_file_mmap() returns a failure to do_mmap_pgoff() - for example, because the given file offset is not hugepage aligned - then do_mmap_pgoff will go to the unmap_and_free_vma backout path. But at this stage the vma hasn't been marked as hugepage, and the backout path will call unmap_region() on it. That will eventually call down to the non-hugepage version of unmap_page_range(). On ppc64, at least, that will cause serious problems if there are any existing hugepage pagetable entries in the vicinity - for example if there are any other hugepage mappings under the same PUD. unmap_page_range() will trigger a bad_pud() on the hugepage pud entries. I suspect this will also cause bad problems on ia64, though I don't have a machine to test it on. (Hugh:) prepare_hugepage_range() should check file offset alignment when it checks virtual address and length, to stop MAP_FIXED with a bad huge offset from unmapping before it fails further down. PowerPC should apply the same prepare_hugepage_range alignment checks as ia64 and all the others do. Then none of the alignment checks in hugetlbfs_file_mmap are required (nor is the check for too small a mapping); but even so, move up setting of VM_HUGETLB and add a comment to warn of what David Gibson discovered - if hugetlbfs_file_mmap fails before setting it, do_mmap_pgoff's unmap_region when unwinding from error will go the non-huge way, which may cause bad behaviour on architectures (powerpc and ia64) which segregate their huge mappings into a separate region of the address space. Signed-off-by: Hugh Dickins Cc: "Luck, Tony" Cc: "David S. Miller" Acked-by: Adam Litke Acked-by: David Gibson Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/mm/hugetlbpage.c | 4 +++- arch/powerpc/mm/hugetlbpage.c | 8 ++++++-- fs/hugetlbfs/inode.c | 21 ++++++++------------- include/linux/hugetlb.h | 10 +++++++--- mm/mmap.c | 2 +- 5 files changed, 25 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index eee5c1cfbe32..f3a9585e98a8 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -70,8 +70,10 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr) * Don't actually need to do any preparation, but need to make sure * the address is in the right region. */ -int prepare_hugepage_range(unsigned long addr, unsigned long len) +int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff) { + if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) + return -EINVAL; if (len & ~HPAGE_MASK) return -EINVAL; if (addr & ~HPAGE_MASK) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index fd68b74c07c3..506d89768d45 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -491,11 +491,15 @@ static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas) return 0; } -int prepare_hugepage_range(unsigned long addr, unsigned long len) +int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff) { int err = 0; - if ( (addr+len) < addr ) + if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) + return -EINVAL; + if (len & ~HPAGE_MASK) + return -EINVAL; + if (addr & ~HPAGE_MASK) return -EINVAL; if (addr < 0x100000000UL) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 0bea6a619e10..7f4756963d05 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -62,24 +62,19 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) loff_t len, vma_len; int ret; - if (vma->vm_pgoff & (HPAGE_SIZE / PAGE_SIZE - 1)) - return -EINVAL; - - if (vma->vm_start & ~HPAGE_MASK) - return -EINVAL; - - if (vma->vm_end & ~HPAGE_MASK) - return -EINVAL; - - if (vma->vm_end - vma->vm_start < HPAGE_SIZE) - return -EINVAL; + /* + * vma alignment has already been checked by prepare_hugepage_range. + * If you add any error returns here, do so after setting VM_HUGETLB, + * so is_vm_hugetlb_page tests below unmap_region go the right way + * when do_mmap_pgoff unwinds (may be important on powerpc and ia64). + */ + vma->vm_flags |= VM_HUGETLB | VM_RESERVED; + vma->vm_ops = &hugetlb_vm_ops; vma_len = (loff_t)(vma->vm_end - vma->vm_start); mutex_lock(&inode->i_mutex); file_accessed(file); - vma->vm_flags |= VM_HUGETLB | VM_RESERVED; - vma->vm_ops = &hugetlb_vm_ops; ret = -ENOMEM; len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 5081d27bfa27..ace64e57e17f 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -60,8 +60,11 @@ void hugetlb_free_pgd_range(struct mmu_gather **tlb, unsigned long addr, * If the arch doesn't supply something else, assume that hugepage * size aligned regions are ok without further preparation. */ -static inline int prepare_hugepage_range(unsigned long addr, unsigned long len) +static inline int prepare_hugepage_range(unsigned long addr, unsigned long len, + pgoff_t pgoff) { + if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT)) + return -EINVAL; if (len & ~HPAGE_MASK) return -EINVAL; if (addr & ~HPAGE_MASK) @@ -69,7 +72,8 @@ static inline int prepare_hugepage_range(unsigned long addr, unsigned long len) return 0; } #else -int prepare_hugepage_range(unsigned long addr, unsigned long len); +int prepare_hugepage_range(unsigned long addr, unsigned long len, + pgoff_t pgoff); #endif #ifndef ARCH_HAS_SETCLEAR_HUGE_PTE @@ -107,7 +111,7 @@ static inline unsigned long hugetlb_total_pages(void) #define hugetlb_report_meminfo(buf) 0 #define hugetlb_report_node_meminfo(n, buf) 0 #define follow_huge_pmd(mm, addr, pmd, write) NULL -#define prepare_hugepage_range(addr, len) (-EINVAL) +#define prepare_hugepage_range(addr,len,pgoff) (-EINVAL) #define pmd_huge(x) 0 #define is_hugepage_only_range(mm, addr, len) 0 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; }) diff --git a/mm/mmap.c b/mm/mmap.c index 497e502dfd6b..bdace87d7c01 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1379,7 +1379,7 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, * Check if the given range is hugepage aligned, and * can be made suitable for hugepages. */ - ret = prepare_hugepage_range(addr, len); + ret = prepare_hugepage_range(addr, len, pgoff); } else { /* * Ensure that a normal request is not falling in a -- cgit v1.2.3-71-gd317 From b96e7ecbd052a0916b6078e7600604d7e276a336 Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Tue, 14 Nov 2006 19:48:48 -0800 Subject: [NETFILTER]: ip6_tables: fixed conflicted optname for getsockopt 66 and 67 for getsockopt on IPv6 socket is doubly used for IPv6 Advanced API and ip6tables. This moves numbers for ip6tables to 68 and 69. This also kills XT_SO_* because {ip,ip6,arp}_tables doesn't have so much common numbers now. The old userland tools keep to behave as ever, because old kernel always calls functions of IPv6 Advanced API for their numbers. Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/in6.h | 12 +++++++++++- include/linux/netfilter/x_tables.h | 16 ---------------- include/linux/netfilter_arp/arp_tables.h | 25 +++++++++++++------------ include/linux/netfilter_ipv4/ip_tables.h | 27 +++++++++++++++------------ include/linux/netfilter_ipv6/ip6_tables.h | 27 +++++++++++++++------------ 5 files changed, 54 insertions(+), 53 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index 9be6a4756f0b..f28621f638e0 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -225,7 +225,7 @@ struct in6_flowlabel_req #endif /* - * Netfilter + * Netfilter (1) * * Following socket options are used in ip6_tables; * see include/linux/netfilter_ipv6/ip6_tables.h. @@ -240,4 +240,14 @@ struct in6_flowlabel_req #define IPV6_RECVTCLASS 66 #define IPV6_TCLASS 67 +/* + * Netfilter (2) + * + * Following socket options are used in ip6_tables; + * see include/linux/netfilter_ipv6/ip6_tables.h. + * + * IP6T_SO_GET_REVISION_MATCH 68 + * IP6T_SO_GET_REVISION_TARGET 69 + */ + #endif diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 04319a76103a..022edfa97ed9 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -96,22 +96,6 @@ struct _xt_align /* Error verdict. */ #define XT_ERROR_TARGET "ERROR" -/* - * New IP firewall options for [gs]etsockopt at the RAW IP level. - * Unlike BSD Linux inherits IP options so you don't have to use a raw - * socket for this. Instead we check rights in the calls. */ -#define XT_BASE_CTL 64 /* base for firewall socket options */ - -#define XT_SO_SET_REPLACE (XT_BASE_CTL) -#define XT_SO_SET_ADD_COUNTERS (XT_BASE_CTL + 1) -#define XT_SO_SET_MAX XT_SO_SET_ADD_COUNTERS - -#define XT_SO_GET_INFO (XT_BASE_CTL) -#define XT_SO_GET_ENTRIES (XT_BASE_CTL + 1) -#define XT_SO_GET_REVISION_MATCH (XT_BASE_CTL + 2) -#define XT_SO_GET_REVISION_TARGET (XT_BASE_CTL + 3) -#define XT_SO_GET_MAX XT_SO_GET_REVISION_TARGET - #define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0) #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0) diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 44e39b61d9e7..0be235418a2f 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -112,19 +112,20 @@ struct arpt_entry * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use a raw * socket for this. Instead we check rights in the calls. + * + * ATTENTION: check linux/in.h before adding new number here. */ -#define ARPT_CTL_OFFSET 32 -#define ARPT_BASE_CTL (XT_BASE_CTL+ARPT_CTL_OFFSET) - -#define ARPT_SO_SET_REPLACE (XT_SO_SET_REPLACE+ARPT_CTL_OFFSET) -#define ARPT_SO_SET_ADD_COUNTERS (XT_SO_SET_ADD_COUNTERS+ARPT_CTL_OFFSET) -#define ARPT_SO_SET_MAX (XT_SO_SET_MAX+ARPT_CTL_OFFSET) - -#define ARPT_SO_GET_INFO (XT_SO_GET_INFO+ARPT_CTL_OFFSET) -#define ARPT_SO_GET_ENTRIES (XT_SO_GET_ENTRIES+ARPT_CTL_OFFSET) -/* #define ARPT_SO_GET_REVISION_MATCH XT_SO_GET_REVISION_MATCH */ -#define ARPT_SO_GET_REVISION_TARGET (XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET) -#define ARPT_SO_GET_MAX (XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET) +#define ARPT_BASE_CTL 96 + +#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL) +#define ARPT_SO_SET_ADD_COUNTERS (ARPT_BASE_CTL + 1) +#define ARPT_SO_SET_MAX ARPT_SO_SET_ADD_COUNTERS + +#define ARPT_SO_GET_INFO (ARPT_BASE_CTL) +#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1) +/* #define ARPT_SO_GET_REVISION_MATCH (APRT_BASE_CTL + 2) */ +#define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3) +#define ARPT_SO_GET_MAX (ARPT_SO_GET_REVISION_TARGET) /* CONTINUE verdict for targets */ #define ARPT_CONTINUE XT_CONTINUE diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index a536bbdef145..4f06dad0bde9 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -101,18 +101,21 @@ struct ipt_entry /* * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use a raw - * socket for this. Instead we check rights in the calls. */ -#define IPT_BASE_CTL XT_BASE_CTL - -#define IPT_SO_SET_REPLACE XT_SO_SET_REPLACE -#define IPT_SO_SET_ADD_COUNTERS XT_SO_SET_ADD_COUNTERS -#define IPT_SO_SET_MAX XT_SO_SET_MAX - -#define IPT_SO_GET_INFO XT_SO_GET_INFO -#define IPT_SO_GET_ENTRIES XT_SO_GET_ENTRIES -#define IPT_SO_GET_REVISION_MATCH XT_SO_GET_REVISION_MATCH -#define IPT_SO_GET_REVISION_TARGET XT_SO_GET_REVISION_TARGET -#define IPT_SO_GET_MAX XT_SO_GET_REVISION_TARGET + * socket for this. Instead we check rights in the calls. + * + * ATTENTION: check linux/in.h before adding new number here. + */ +#define IPT_BASE_CTL 64 + +#define IPT_SO_SET_REPLACE (IPT_BASE_CTL) +#define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1) +#define IPT_SO_SET_MAX IPT_SO_SET_ADD_COUNTERS + +#define IPT_SO_GET_INFO (IPT_BASE_CTL) +#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1) +#define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2) +#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3) +#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET #define IPT_CONTINUE XT_CONTINUE #define IPT_RETURN XT_RETURN diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index d7a8e9c0dad0..4aed340401db 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -107,18 +107,21 @@ struct ip6t_entry /* * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use - * a raw socket for this. Instead we check rights in the calls. */ -#define IP6T_BASE_CTL XT_BASE_CTL - -#define IP6T_SO_SET_REPLACE XT_SO_SET_REPLACE -#define IP6T_SO_SET_ADD_COUNTERS XT_SO_SET_ADD_COUNTERS -#define IP6T_SO_SET_MAX XT_SO_SET_MAX - -#define IP6T_SO_GET_INFO XT_SO_GET_INFO -#define IP6T_SO_GET_ENTRIES XT_SO_GET_ENTRIES -#define IP6T_SO_GET_REVISION_MATCH XT_SO_GET_REVISION_MATCH -#define IP6T_SO_GET_REVISION_TARGET XT_SO_GET_REVISION_TARGET -#define IP6T_SO_GET_MAX XT_SO_GET_REVISION_TARGET + * a raw socket for this. Instead we check rights in the calls. + * + * ATTENTION: check linux/in6.h before adding new number here. + */ +#define IP6T_BASE_CTL 64 + +#define IP6T_SO_SET_REPLACE (IP6T_BASE_CTL) +#define IP6T_SO_SET_ADD_COUNTERS (IP6T_BASE_CTL + 1) +#define IP6T_SO_SET_MAX IP6T_SO_SET_ADD_COUNTERS + +#define IP6T_SO_GET_INFO (IP6T_BASE_CTL) +#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1) +#define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 4) +#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5) +#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET /* CONTINUE verdict for targets */ #define IP6T_CONTINUE XT_CONTINUE -- cgit v1.2.3-71-gd317 From c7835a77c86422d276b0d1a4c70924d933014c13 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 15 Nov 2006 21:14:42 -0800 Subject: [TG3]: Disable TSO on 5906 if CLKREQ is enabled. Due to hardware errata, TSO must be disabled if the PCI Express clock request is enabled on 5906. The chip may hang when transmitting TSO frames if CLKREQ is enabled. Update version to 3.69. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 20 ++++++++++++++++---- include/linux/pci_regs.h | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6e86866bd3fa..1dbdd6bb587b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.68" -#define DRV_MODULE_RELDATE "November 02, 2006" +#define DRV_MODULE_VERSION "3.69" +#define DRV_MODULE_RELDATE "November 15, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -10366,7 +10366,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) u32 pci_state_reg, grc_misc_cfg; u32 val; u16 pci_cmd; - int err; + int err, pcie_cap; /* Force memory write invalidate off. If we leave it on, * then on 5700_BX chips we have to enable a workaround. @@ -10541,8 +10541,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; - if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) + pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); + if (pcie_cap != 0) { tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + u16 lnkctl; + + pci_read_config_word(tp->pdev, + pcie_cap + PCI_EXP_LNKCTL, + &lnkctl); + if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) + tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; + } + } /* If we have an AMD 762 or VIA K8T800 chipset, write * reordering to the mailbox registers done by the host @@ -11809,6 +11820,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A0 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; } else { diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index c312a12ad2d6..c321316f1bc7 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -371,6 +371,7 @@ #define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ #define PCI_EXP_LNKCAP 12 /* Link Capabilities */ #define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ #define PCI_EXP_LNKSTA 18 /* Link Status */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCTL 24 /* Slot Control */ -- cgit v1.2.3-71-gd317 From da63fc7ce63b43426dc3c69c05e28de2872c159a Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Thu, 16 Nov 2006 01:19:28 -0800 Subject: [PATCH] fat: add fat_getattr() This adds fat_getattr() for setting stat->blksize. (FAT uses the size of cluster for proper I/O) Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/file.c | 10 ++++++++++ fs/msdos/namei.c | 1 + fs/vfat/namei.c | 1 + include/linux/msdos_fs.h | 2 ++ 4 files changed, 14 insertions(+) (limited to 'include/linux') diff --git a/fs/fat/file.c b/fs/fat/file.c index 8337451e7897..0aa813d944a6 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -303,7 +303,17 @@ void fat_truncate(struct inode *inode) fat_flush_inodes(inode->i_sb, inode, NULL); } +int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + generic_fillattr(inode, stat); + stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; + return 0; +} +EXPORT_SYMBOL_GPL(fat_getattr); + struct inode_operations fat_file_inode_operations = { .truncate = fat_truncate, .setattr = fat_notify_change, + .getattr = fat_getattr, }; diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index b0f01b3b0536..452461955cbd 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -654,6 +654,7 @@ static struct inode_operations msdos_dir_inode_operations = { .rmdir = msdos_rmdir, .rename = msdos_rename, .setattr = fat_notify_change, + .getattr = fat_getattr, }; static int msdos_fill_super(struct super_block *sb, void *data, int silent) diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index edb711ff7b05..0afd745a37cd 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1004,6 +1004,7 @@ static struct inode_operations vfat_dir_inode_operations = { .rmdir = vfat_rmdir, .rename = vfat_rename, .setattr = fat_notify_change, + .getattr = fat_getattr, }; static int vfat_fill_super(struct super_block *sb, void *data, int silent) diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index ce6c85815cbd..24a9ef1506b6 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -402,6 +402,8 @@ extern const struct file_operations fat_file_operations; extern struct inode_operations fat_file_inode_operations; extern int fat_notify_change(struct dentry * dentry, struct iattr * attr); extern void fat_truncate(struct inode *inode); +extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat); /* fat/inode.c */ extern void fat_attach(struct inode *inode, loff_t i_pos); -- cgit v1.2.3-71-gd317 From 610a5b742e9df4e59047f22d13d8bd83cafce388 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Fri, 17 Nov 2006 11:51:41 +1100 Subject: [CRYPTO] api: Remove one too many semicolon This patch has removed one too many semicolon in crypto.h. Signed-off-by: Yoichi Yuasa Signed-off-by: Herbert Xu --- include/linux/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 8f2ffa4caabf..6485e9716b36 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -245,7 +245,7 @@ int crypto_alg_available(const char *name, u32 flags) __deprecated_for_modules; int crypto_has_alg(const char *name, u32 type, u32 mask); #else -static int crypto_alg_available(const char *name, u32 flags); +static int crypto_alg_available(const char *name, u32 flags) __deprecated_for_modules; static inline int crypto_alg_available(const char *name, u32 flags) { -- cgit v1.2.3-71-gd317 From b3438f8266cb1f5010085ac47d7ad6a36a212164 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 20 Nov 2006 11:47:18 -0800 Subject: Add "pure_initcall" for static variable initialization This is a quick hack to overcome the fact that SRCU currently does not allow static initializers, and we need to sometimes initialize those things before any other initializers (even "core" ones) can do so. Currently we don't allow this at all for modules, and the only user that needs is right now is cpufreq. As reported by Thomas Gleixner: "Commit b4dfdbb3c707474a2254c5b4d7e62be31a4b7da9 ("[PATCH] cpufreq: make the transition_notifier chain use SRCU breaks cpu frequency notification users, which register the callback > on core_init level." Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Arjan van de Ven Cc: Andrew Morton , Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq.c | 2 +- include/asm-generic/vmlinux.lds.h | 2 ++ include/linux/init.h | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 86e69b7f9122..dd0c2623e27b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -59,7 +59,7 @@ static int __init init_cpufreq_transition_notifier_list(void) srcu_init_notifier_head(&cpufreq_transition_notifier_list); return 0; } -core_initcall(init_cpufreq_transition_notifier_list); +pure_initcall(init_cpufreq_transition_notifier_list); static LIST_HEAD(cpufreq_governor_list); static DEFINE_MUTEX (cpufreq_governor_mutex); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 9d873163a7ab..e60d6f21fa62 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -215,6 +215,8 @@ .notes : { *(.note.*) } :note #define INITCALLS \ + *(.initcall0.init) \ + *(.initcall0s.init) \ *(.initcall1.init) \ *(.initcall1s.init) \ *(.initcall2.init) \ diff --git a/include/linux/init.h b/include/linux/init.h index ff40ea118e3a..5eb5d24b7680 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -93,6 +93,14 @@ extern void setup_arch(char **); static initcall_t __initcall_##fn##id __attribute_used__ \ __attribute__((__section__(".initcall" level ".init"))) = fn +/* + * A "pure" initcall has no dependencies on anything else, and purely + * initializes variables that couldn't be statically initialized. + * + * This only exists for built-in code, not for modules. + */ +#define pure_initcall(fn) __define_initcall("0",fn,1) + #define core_initcall(fn) __define_initcall("1",fn,1) #define core_initcall_sync(fn) __define_initcall("1s",fn,1s) #define postcore_initcall(fn) __define_initcall("2",fn,2) -- cgit v1.2.3-71-gd317 From fb47ddb2db9c18664bd7b06c201a2398885b64fc Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Sun, 19 Nov 2006 10:38:39 -0800 Subject: [IGMP]: Fix IGMPV3_EXP() normalization bit shift value. The IGMPV3_EXP() macro doesn't correctly shift the normalization bit, so time-out values are longer than they should be. Thanks to Dirk Ooms for finding the problem in IGMPv3 - MLDv2 had a similar problem that was already fixed a year ago. :-( Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 03f43e2893a4..21dd56905271 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -191,7 +191,7 @@ struct ip_mc_list #define IGMPV3_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) #define IGMPV3_EXP(thresh, nbmant, nbexp, value) \ ((value) < (thresh) ? (value) : \ - ((IGMPV3_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \ + ((IGMPV3_MASK(value, nbmant) | (1<<(nbmant))) << \ (IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp)))) #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value) -- cgit v1.2.3-71-gd317 From 701e054e0c2db82359f0454c7ed4fd24346d52eb Mon Sep 17 00:00:00 2001 From: Vasily Tarasov Date: Sat, 25 Nov 2006 11:09:22 -0800 Subject: [PATCH] mounstats NULL pointer dereference OpenVZ developers team has encountered the following problem in 2.6.19-rc6 kernel. After some seconds of running script while [[ 1 ]] do find /proc -name mountstats | xargs cat done this Oops appears: BUG: unable to handle kernel NULL pointer dereference at virtual address 00000010 printing eip: c01a6b70 *pde = 00000000 Oops: 0000 [#1] SMP Modules linked in: xt_length ipt_ttl xt_tcpmss ipt_TCPMSS iptable_mangle iptable_filter xt_multiport xt_limit ipt_tos ipt_REJECT ip_tables x_tables parport_pc lp parport sunrpc af_packet thermal processor fan button battery asus_acpi ac ohci_hcd ehci_hcd usbcore i2c_nforce2 i2c_core tg3 floppy pata_amd ide_cd cdrom sata_nv libata CPU: 1 EIP: 0060:[] Not tainted VLI EFLAGS: 00010246 (2.6.19-rc6 #2) EIP is at mountstats_open+0x70/0xf0 eax: 00000000 ebx: e6247030 ecx: e62470f8 edx: 00000000 esi: 00000000 edi: c01a6b00 ebp: c33b83c0 esp: f4105eb4 ds: 007b es: 007b ss: 0068 Process cat (pid: 6044, ti=f4105000 task=f4104a70 task.ti=f4105000) Stack: c33b83c0 c04ee940 f46a4a80 c33b83c0 e4df31b4 c01a6b00 f4105000 c0169231 e4df31b4 c33b83c0 c33b83c0 f4105f20 00000003 f4105000 c0169445 f2503cf0 f7f8c4c0 00008000 c33b83c0 00000000 00008000 c0169350 f4105f20 00008000 Call Trace: [] mountstats_open+0x0/0xf0 [] __dentry_open+0x181/0x250 [] nameidata_to_filp+0x35/0x50 [] do_filp_open+0x50/0x60 [] seq_read+0xc6/0x300 [] get_unused_fd+0x31/0xc0 [] do_sys_open+0x63/0x110 [] sys_open+0x27/0x30 [] sysenter_past_esp+0x56/0x79 ======================= Code: 45 74 8b 54 24 20 89 44 24 08 8b 42 f0 31 d2 e8 47 cb f8 ff 85 c0 89 c3 74 51 8d 80 a0 04 00 00 e8 46 06 2c 00 8b 83 48 04 00 00 <8b> 78 10 85 ff 74 03 f0 ff 07 b0 01 86 83 a0 04 00 00 f0 ff 4b EIP: [] mountstats_open+0x70/0xf0 SS:ESP 0068:f4105eb4 The problem is that task->nsproxy can be equal NULL for some time during task exit. This patch fixes the BUG. Signed-off-by: Vasily Tarasov Cc: Herbert Poetzl Cc: "Serge E. Hallyn" Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 3 ++- include/linux/nsproxy.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/base.c b/fs/proc/base.c index 8df27401d292..795319c54f72 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -442,7 +442,8 @@ static int mountstats_open(struct inode *inode, struct file *file) if (task) { task_lock(task); - namespace = task->nsproxy->namespace; + if (task->nsproxy) + namespace = task->nsproxy->namespace; if (namespace) get_namespace(namespace); task_unlock(task); diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index f6baecdeecd6..971d1c6dfc4b 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -45,8 +45,10 @@ static inline void exit_task_namespaces(struct task_struct *p) { struct nsproxy *ns = p->nsproxy; if (ns) { - put_nsproxy(ns); + task_lock(p); p->nsproxy = NULL; + task_unlock(p); + put_nsproxy(ns); } } #endif -- cgit v1.2.3-71-gd317 From ee3ce191e8eaa4cc15c51a28b34143b36404c4f5 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 25 Nov 2006 11:09:36 -0800 Subject: [PATCH] Enforce "unsigned long flags;" when spinlocking Make it break or warn if you pass to spin_lock_irqsave() and friends something different from "unsigned long flags;". Suprisingly large amount of these was caught by recent commit c53421b18f205c5f97c604ae55c6a921f034b0f6 and others. Idea is largely from FRV typechecking. Suggestions from Andrew Morton. All stupid typos in first version fixed. Passes allmodconfig on i386, x86_64, alpha, arm as well as my usual config. Note #1: checking with sparse is still needed, because a driver can save and pass around flags or something. So far patch is very intrusive. Note #2: techically, we should break only if sizeof(flags) < sizeof(unsigned long), however, the more pain for getting suspicious code into kernel, the better. Signed-off-by: Alexey Dobriyan Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irqflags.h | 37 ++++++++++++++++++++++++++++----- include/linux/spinlock.h | 53 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index 412e025bc5c7..4fe740bf4eae 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -11,6 +11,12 @@ #ifndef _LINUX_TRACE_IRQFLAGS_H #define _LINUX_TRACE_IRQFLAGS_H +#define BUILD_CHECK_IRQ_FLAGS(flags) \ + do { \ + BUILD_BUG_ON(sizeof(flags) != sizeof(unsigned long)); \ + typecheck(unsigned long, flags); \ + } while (0) + #ifdef CONFIG_TRACE_IRQFLAGS extern void trace_hardirqs_on(void); extern void trace_hardirqs_off(void); @@ -50,10 +56,15 @@ #define local_irq_disable() \ do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) #define local_irq_save(flags) \ - do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + raw_local_irq_save(flags); \ + trace_hardirqs_off(); \ + } while (0) #define local_irq_restore(flags) \ do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ if (raw_irqs_disabled_flags(flags)) { \ raw_local_irq_restore(flags); \ trace_hardirqs_off(); \ @@ -69,8 +80,16 @@ */ # define raw_local_irq_disable() local_irq_disable() # define raw_local_irq_enable() local_irq_enable() -# define raw_local_irq_save(flags) local_irq_save(flags) -# define raw_local_irq_restore(flags) local_irq_restore(flags) +# define raw_local_irq_save(flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + local_irq_save(flags); \ + } while (0) +# define raw_local_irq_restore(flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + local_irq_restore(flags); \ + } while (0) #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT @@ -80,7 +99,11 @@ raw_safe_halt(); \ } while (0) -#define local_save_flags(flags) raw_local_save_flags(flags) +#define local_save_flags(flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + raw_local_save_flags(flags); \ + } while (0) #define irqs_disabled() \ ({ \ @@ -90,7 +113,11 @@ raw_irqs_disabled_flags(flags); \ }) -#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) +#define irqs_disabled_flags(flags) \ +({ \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + raw_irqs_disabled_flags(flags); \ +}) #endif /* CONFIG_X86 */ #endif diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index b800d2d68b32..54ad37089c49 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -183,13 +184,37 @@ do { \ #define read_lock(lock) _read_lock(lock) #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) -#define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) -#define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) -#define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) +#define spin_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _spin_lock_irqsave(lock); \ + } while (0) +#define read_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _read_lock_irqsave(lock); \ + } while (0) +#define write_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _write_lock_irqsave(lock); \ + } while (0) #else -#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) -#define read_lock_irqsave(lock, flags) _read_lock_irqsave(lock, flags) -#define write_lock_irqsave(lock, flags) _write_lock_irqsave(lock, flags) +#define spin_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _spin_lock_irqsave(lock, flags); \ + } while (0) +#define read_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _read_lock_irqsave(lock, flags); \ + } while (0) +#define write_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _write_lock_irqsave(lock, flags); \ + } while (0) #endif #define spin_lock_irq(lock) _spin_lock_irq(lock) @@ -225,15 +250,24 @@ do { \ #endif #define spin_unlock_irqrestore(lock, flags) \ - _spin_unlock_irqrestore(lock, flags) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _spin_unlock_irqrestore(lock, flags); \ + } while (0) #define spin_unlock_bh(lock) _spin_unlock_bh(lock) #define read_unlock_irqrestore(lock, flags) \ - _read_unlock_irqrestore(lock, flags) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _read_unlock_irqrestore(lock, flags); \ + } while (0) #define read_unlock_bh(lock) _read_unlock_bh(lock) #define write_unlock_irqrestore(lock, flags) \ - _write_unlock_irqrestore(lock, flags) + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + _write_unlock_irqrestore(lock, flags); \ + } while (0) #define write_unlock_bh(lock) _write_unlock_bh(lock) #define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock)) @@ -247,6 +281,7 @@ do { \ #define spin_trylock_irqsave(lock, flags) \ ({ \ + BUILD_CHECK_IRQ_FLAGS(flags); \ local_irq_save(flags); \ spin_trylock(lock) ? \ 1 : ({ local_irq_restore(flags); 0; }); \ -- cgit v1.2.3-71-gd317 From cfd3ef2346f924d6c0e82236c20fdb3a8840136a Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 25 Nov 2006 11:09:37 -0800 Subject: [PATCH] lockdep: spin_lock_irqsave_nested() Introduce spin_lock_irqsave_nested(); implementation from: http://lkml.org/lkml/2006/6/1/122 Patch from: http://lkml.org/lkml/2006/9/13/258 [akpm@osdl.org: two compile fixes] Signed-off-by: Arjan van de Ven Signed-off-by: Jiri Kosina Signed-off-by: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/spinlock.h | 18 ++++++++++++++++++ include/linux/spinlock_api_smp.h | 2 ++ kernel/spinlock.c | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+) (limited to 'include/linux') diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 54ad37089c49..57f670d78f7c 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -199,6 +199,21 @@ do { \ BUILD_CHECK_IRQ_FLAGS(flags); \ flags = _write_lock_irqsave(lock); \ } while (0) + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _spin_lock_irqsave_nested(lock, subclass); \ + } while (0) +#else +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ + flags = _spin_lock_irqsave(lock); \ + } while (0) +#endif + #else #define spin_lock_irqsave(lock, flags) \ do { \ @@ -215,6 +230,9 @@ do { \ BUILD_CHECK_IRQ_FLAGS(flags); \ _write_lock_irqsave(lock, flags); \ } while (0) +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + spin_lock_irqsave(lock, flags) + #endif #define spin_lock_irq(lock) _spin_lock_irq(lock) diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h index 8828b8155e9c..8a2307ce7296 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -32,6 +32,8 @@ void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(lock); void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) __acquires(lock); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) + __acquires(lock); unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 476c3741511b..2c6c2bf85514 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -293,6 +293,27 @@ void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass) } EXPORT_SYMBOL(_spin_lock_nested); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); + /* + * On lockdep we dont want the hand-coded irq-enable of + * _raw_spin_lock_flags() code, because lockdep assumes + * that interrupts are not re-enabled during lock-acquire: + */ +#ifdef CONFIG_PROVE_SPIN_LOCKING + _raw_spin_lock(lock); +#else + _raw_spin_lock_flags(lock, &flags); +#endif + return flags; +} + +EXPORT_SYMBOL(_spin_lock_irqsave_nested); #endif -- cgit v1.2.3-71-gd317 From b8e6ec865fd1d8838b6ce9516977b65e9f08f876 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 26 Nov 2006 16:27:17 -0800 Subject: Revert "[PATCH] Enforce "unsigned long flags;" when spinlocking" This reverts commit ee3ce191e8eaa4cc15c51a28b34143b36404c4f5, since it broke on at least ARM, MIPS and PA-RISC due to complicated header file dependencies. Conflicts in include/linux/spinlock.h (due to the "nested" variety fixes) fixed up by hand. Cc: Alexey Dobriyan Cc: Ralf Baechle Cc: Kyle McMartin Cc: Russell King Signed-off-by: Linus Torvalds --- include/linux/irqflags.h | 37 ++++---------------------- include/linux/spinlock.h | 69 +++++++++++------------------------------------- 2 files changed, 20 insertions(+), 86 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index 4fe740bf4eae..412e025bc5c7 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -11,12 +11,6 @@ #ifndef _LINUX_TRACE_IRQFLAGS_H #define _LINUX_TRACE_IRQFLAGS_H -#define BUILD_CHECK_IRQ_FLAGS(flags) \ - do { \ - BUILD_BUG_ON(sizeof(flags) != sizeof(unsigned long)); \ - typecheck(unsigned long, flags); \ - } while (0) - #ifdef CONFIG_TRACE_IRQFLAGS extern void trace_hardirqs_on(void); extern void trace_hardirqs_off(void); @@ -56,15 +50,10 @@ #define local_irq_disable() \ do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) #define local_irq_save(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - raw_local_irq_save(flags); \ - trace_hardirqs_off(); \ - } while (0) + do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0) #define local_irq_restore(flags) \ do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ if (raw_irqs_disabled_flags(flags)) { \ raw_local_irq_restore(flags); \ trace_hardirqs_off(); \ @@ -80,16 +69,8 @@ */ # define raw_local_irq_disable() local_irq_disable() # define raw_local_irq_enable() local_irq_enable() -# define raw_local_irq_save(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - local_irq_save(flags); \ - } while (0) -# define raw_local_irq_restore(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - local_irq_restore(flags); \ - } while (0) +# define raw_local_irq_save(flags) local_irq_save(flags) +# define raw_local_irq_restore(flags) local_irq_restore(flags) #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT @@ -99,11 +80,7 @@ raw_safe_halt(); \ } while (0) -#define local_save_flags(flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - raw_local_save_flags(flags); \ - } while (0) +#define local_save_flags(flags) raw_local_save_flags(flags) #define irqs_disabled() \ ({ \ @@ -113,11 +90,7 @@ raw_irqs_disabled_flags(flags); \ }) -#define irqs_disabled_flags(flags) \ -({ \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - raw_irqs_disabled_flags(flags); \ -}) +#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) #endif /* CONFIG_X86 */ #endif diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 57f670d78f7c..8451052ca66f 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -52,7 +52,6 @@ #include #include #include -#include #include @@ -184,52 +183,24 @@ do { \ #define read_lock(lock) _read_lock(lock) #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) -#define spin_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _spin_lock_irqsave(lock); \ - } while (0) -#define read_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _read_lock_irqsave(lock); \ - } while (0) -#define write_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _write_lock_irqsave(lock); \ - } while (0) + +#define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) +#define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) +#define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) #ifdef CONFIG_DEBUG_LOCK_ALLOC -#define spin_lock_irqsave_nested(lock, flags, subclass) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _spin_lock_irqsave_nested(lock, subclass); \ - } while (0) +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + flags = _spin_lock_irqsave_nested(lock, subclass) #else -#define spin_lock_irqsave_nested(lock, flags, subclass) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - flags = _spin_lock_irqsave(lock); \ - } while (0) +#define spin_lock_irqsave_nested(lock, flags, subclass) \ + flags = _spin_lock_irqsave(lock) #endif #else -#define spin_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _spin_lock_irqsave(lock, flags); \ - } while (0) -#define read_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _read_lock_irqsave(lock, flags); \ - } while (0) -#define write_lock_irqsave(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _write_lock_irqsave(lock, flags); \ - } while (0) + +#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) +#define read_lock_irqsave(lock, flags) _read_lock_irqsave(lock, flags) +#define write_lock_irqsave(lock, flags) _write_lock_irqsave(lock, flags) #define spin_lock_irqsave_nested(lock, flags, subclass) \ spin_lock_irqsave(lock, flags) @@ -268,24 +239,15 @@ do { \ #endif #define spin_unlock_irqrestore(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _spin_unlock_irqrestore(lock, flags); \ - } while (0) + _spin_unlock_irqrestore(lock, flags) #define spin_unlock_bh(lock) _spin_unlock_bh(lock) #define read_unlock_irqrestore(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _read_unlock_irqrestore(lock, flags); \ - } while (0) + _read_unlock_irqrestore(lock, flags) #define read_unlock_bh(lock) _read_unlock_bh(lock) #define write_unlock_irqrestore(lock, flags) \ - do { \ - BUILD_CHECK_IRQ_FLAGS(flags); \ - _write_unlock_irqrestore(lock, flags); \ - } while (0) + _write_unlock_irqrestore(lock, flags) #define write_unlock_bh(lock) _write_unlock_bh(lock) #define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock)) @@ -299,7 +261,6 @@ do { \ #define spin_trylock_irqsave(lock, flags) \ ({ \ - BUILD_CHECK_IRQ_FLAGS(flags); \ local_irq_save(flags); \ spin_trylock(lock) ? \ 1 : ({ local_irq_restore(flags); 0; }); \ -- cgit v1.2.3-71-gd317 From 2ea5814472c3c910aed5c5b60f1f3b1000e353f1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 26 Nov 2006 19:05:22 -0800 Subject: Fix 'ALIGN()' macro, take 2 You wouldn't think that doing an ALIGN() macro that aligns something up to a power-of-two boundary would be likely to have bugs, would you? But hey, in the wonderful world of mixing integer types, you have to be careful. This just makes sure that the alignment is interpreted in the same type as the thing to be aligned. Thanks to Roland Dreier, who noticed that the amso1100 driver got broken by the previous fix (that just extended the mask to "unsigned long", but was still broken in "unsigned long long" - it just happened to be the same on 64-bit architectures). See commit 4c8bd7eeee4c8f157fb61fb64b57500990b42e0e for the history of bugs here... Acked-by: Roland Dreier Cc: Andrew Morton Cc: David Miller Cc: Al Viro Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 24b611147adb..b9b5e4ba166a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -30,8 +30,10 @@ extern const char linux_banner[]; #define STACK_MAGIC 0xdeadbeef +#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL)) #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -- cgit v1.2.3-71-gd317 From e81c73596704793e73e6dbb478f41686f15a4b34 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 28 Nov 2006 20:53:39 -0800 Subject: [NET]: Fix MAX_HEADER setting. MAX_HEADER is either set to LL_MAX_HEADER or LL_MAX_HEADER + 48, and this is controlled by a set of CONFIG_* ifdef tests. It is trying to use LL_MAX_HEADER + 48 when any of the tunnels are enabled which set hard_header_len like this: dev->hard_header_len = LL_MAX_HEADER + sizeof(struct xxx); The correct set of tunnel drivers which do this are: ipip ip_gre ip6_tunnel sit so make the ifdef test match. Noticed by Patrick McHardy and with help from Herbert Xu. Signed-off-by: David S. Miller --- include/linux/netdevice.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9264139bd8df..83b8c4f1d69d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -93,8 +93,10 @@ struct netpoll_info; #endif #endif -#if !defined(CONFIG_NET_IPIP) && \ - !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) +#if !defined(CONFIG_NET_IPIP) && !defined(CONFIG_NET_IPIP_MODULE) && \ + !defined(CONFIG_NET_IPGRE) && !defined(CONFIG_NET_IPGRE_MODULE) && \ + !defined(CONFIG_IPV6_SIT) && !defined(CONFIG_IPV6_SIT_MODULE) && \ + !defined(CONFIG_IPV6_TUNNEL) && !defined(CONFIG_IPV6_TUNNEL_MODULE) #define MAX_HEADER LL_MAX_HEADER #else #define MAX_HEADER (LL_MAX_HEADER + 48) -- cgit v1.2.3-71-gd317 From 583bb86fbb9e85287f020fe4eb5352a0ec3c66a3 Mon Sep 17 00:00:00 2001 From: Nicolas Schichan Date: Wed, 18 Oct 2006 15:14:55 +0200 Subject: [MIPS] Add support for kexec A tiny userland application loading the kernel and invoking kexec_load for mips is available here: http://chac.le-poulpe.net/~nico/kexec/kexec-2006-10-18.tar.gz Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 17 ++++++++ arch/mips/kernel/Makefile | 2 + arch/mips/kernel/machine_kexec.c | 85 ++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/relocate_kernel.S | 80 +++++++++++++++++++++++++++++++++++ arch/mips/kernel/scall32-o32.S | 2 +- arch/mips/kernel/scall64-64.S | 2 +- arch/mips/kernel/scall64-n32.S | 2 +- arch/mips/kernel/scall64-o32.S | 2 +- include/asm-mips/kexec.h | 32 ++++++++++++++ include/linux/kexec.h | 2 + 10 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 arch/mips/kernel/machine_kexec.c create mode 100644 arch/mips/kernel/relocate_kernel.S create mode 100644 include/asm-mips/kexec.h (limited to 'include/linux') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1443024b1c7c..c0da0ffe8d57 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -766,6 +766,23 @@ config TOSHIBA_RBTX4938 endchoice +config KEXEC + bool "Kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + source "arch/mips/ddb5xxx/Kconfig" source "arch/mips/gt64120/ev64120/Kconfig" source "arch/mips/jazz/Kconfig" diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 6bfbbed0897e..f35b739d0a12 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -67,6 +67,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o obj-$(CONFIG_I8253) += i8253.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o + CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c new file mode 100644 index 000000000000..e0ad754c7edd --- /dev/null +++ b/arch/mips/kernel/machine_kexec.c @@ -0,0 +1,85 @@ +/* + * machine_kexec.c for kexec + * Created by on Thu Oct 12 15:15:06 2006 + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include + +#include +#include + +const extern unsigned char relocate_new_kernel[]; +const extern unsigned int relocate_new_kernel_size; + +extern unsigned long kexec_start_address; +extern unsigned long kexec_indirection_page; + +int +machine_kexec_prepare(struct kimage *kimage) +{ + return 0; +} + +void +machine_kexec_cleanup(struct kimage *kimage) +{ +} + +void +machine_shutdown(void) +{ +} + +void +machine_crash_shutdown(struct pt_regs *regs) +{ +} + +void +machine_kexec(struct kimage *image) +{ + unsigned long reboot_code_buffer; + unsigned long entry; + unsigned long *ptr; + + reboot_code_buffer = + (unsigned long)page_address(image->control_code_page); + + kexec_start_address = image->start; + kexec_indirection_page = phys_to_virt(image->head & PAGE_MASK); + + memcpy((void*)reboot_code_buffer, relocate_new_kernel, + relocate_new_kernel_size); + + /* + * The generic kexec code builds a page list with physical + * addresses. they are directly accessible through KSEG0 (or + * CKSEG0 or XPHYS if on 64bit system), hence the + * pys_to_virt() call. + */ + for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE); + ptr = (entry & IND_INDIRECTION) ? + phys_to_virt(entry & PAGE_MASK) : ptr + 1) { + if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION || + *ptr & IND_DESTINATION) + *ptr = phys_to_virt(*ptr); + } + + /* + * we do not want to be bothered. + */ + local_irq_disable(); + + flush_icache_range(reboot_code_buffer, + reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); + + printk("Will call new kernel at %08x\n", image->start); + printk("Bye ...\n"); + flush_cache_all(); + ((void (*)(void))reboot_code_buffer)(); +} diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S new file mode 100644 index 000000000000..a3f0d00c1334 --- /dev/null +++ b/arch/mips/kernel/relocate_kernel.S @@ -0,0 +1,80 @@ +/* + * relocate_kernel.S for kexec + * Created by on Thu Oct 12 17:49:57 2006 + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + + .globl relocate_new_kernel +relocate_new_kernel: + + PTR_L s0, kexec_indirection_page + PTR_L s1, kexec_start_address + +process_entry: + PTR_L s2, (s0) + PTR_ADD s0, s0, SZREG + + /* destination page */ + and s3, s2, 0x1 + beq s3, zero, 1f + and s4, s2, ~0x1 /* store destination addr in s4 */ + move a0, s4 + b process_entry + +1: + /* indirection page, update s0 */ + and s3, s2, 0x2 + beq s3, zero, 1f + and s0, s2, ~0x2 + b process_entry + +1: + /* done page */ + and s3, s2, 0x4 + beq s3, zero, 1f + b done +1: + /* source page */ + and s3, s2, 0x8 + beq s3, zero, process_entry + and s2, s2, ~0x8 + li s6, (1 << PAGE_SHIFT) / SZREG + +copy_word: + /* copy page word by word */ + REG_L s5, (s2) + REG_S s5, (s4) + INT_ADD s4, s4, SZREG + INT_ADD s2, s2, SZREG + INT_SUB s6, s6, 1 + beq s6, zero, process_entry + b copy_word + b process_entry + +done: + /* jump to kexec_start_address */ + j s1 + + .globl kexec_start_address +kexec_start_address: + .long 0x0 + + .globl kexec_indirection_page +kexec_indirection_page: + .long 0x0 + +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long relocate_new_kernel_end - relocate_new_kernel diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index a95f37de080e..7c0b3936ba44 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -653,7 +653,7 @@ einval: li v0, -EINVAL sys sys_move_pages 6 sys sys_set_robust_list 2 sys sys_get_robust_list 3 /* 4310 */ - sys sys_ni_syscall 0 + sys sys_kexec_load 4 sys sys_getcpu 3 sys sys_epoll_pwait 6 .endm diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 8fb0f60f657b..e569b846e9a3 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -468,6 +468,6 @@ sys_call_table: PTR sys_move_pages PTR sys_set_robust_list PTR sys_get_robust_list - PTR sys_ni_syscall /* 5270 */ + PTR sys_kexec_load /* 5270 */ PTR sys_getcpu PTR sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 0da5ca2040ff..5b18f265d75b 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -394,6 +394,6 @@ EXPORT(sysn32_call_table) PTR sys_move_pages PTR compat_sys_set_robust_list PTR compat_sys_get_robust_list - PTR sys_ni_syscall + PTR compat_sys_kexec_load PTR sys_getcpu PTR sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index b9d00cae8b5f..e91379c1be1d 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -516,7 +516,7 @@ sys_call_table: PTR compat_sys_move_pages PTR compat_sys_set_robust_list PTR compat_sys_get_robust_list /* 4310 */ - PTR sys_ni_syscall + PTR compat_sys_kexec_load PTR sys_getcpu PTR sys_epoll_pwait .size sys_call_table,.-sys_call_table diff --git a/include/asm-mips/kexec.h b/include/asm-mips/kexec.h new file mode 100644 index 000000000000..b25267ebcb09 --- /dev/null +++ b/include/asm-mips/kexec.h @@ -0,0 +1,32 @@ +/* + * kexec.h for kexec + * Created by on Thu Oct 12 14:59:34 2006 + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#ifndef _MIPS_KEXEC +# define _MIPS_KEXEC + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000) + /* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000) + +#define KEXEC_CONTROL_CODE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_MIPS + +#define MAX_NOTE_BYTES 1024 + +static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) +{ + /* Dummy implementation for now */ +} + +#endif /* !_MIPS_KEXEC */ diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 6427949ddf99..a4ede62b339d 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -122,6 +122,8 @@ extern struct kimage *kexec_crash_image; #define KEXEC_ARCH_IA_64 (50 << 16) #define KEXEC_ARCH_S390 (22 << 16) #define KEXEC_ARCH_SH (42 << 16) +#define KEXEC_ARCH_MIPS_LE (10 << 16) +#define KEXEC_ARCH_MIPS ( 8 << 16) #define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */ -- cgit v1.2.3-71-gd317 From 139a7bdc2b9391a4d0362190d9e5625dcf580105 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 30 Nov 2006 04:40:22 +0100 Subject: mqueue.h: don't include linux/types.h This #include is not required. Signed-off-by: Alexey Dobriyan Signed-off-by: Adrian Bunk --- include/linux/mqueue.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mqueue.h b/include/linux/mqueue.h index 8db9d75541a6..8b5a79615fbf 100644 --- a/include/linux/mqueue.h +++ b/include/linux/mqueue.h @@ -18,8 +18,6 @@ #ifndef _LINUX_MQUEUE_H #define _LINUX_MQUEUE_H -#include - #define MQ_PRIO_MAX 32768 /* per-uid limit of kernel memory used by mqueue, in bytes */ #define MQ_BYTES_MAX 819200 -- cgit v1.2.3-71-gd317 From e20ec9911bfef897459b9f8aeaf6eadb0920299a Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Thu, 30 Nov 2006 04:46:13 +0100 Subject: fix spelling error in include/linux/kernel.h Signed-off-by: Adrian Bunk --- include/linux/kernel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b9b5e4ba166a..6738283ac385 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -65,7 +65,7 @@ struct user; * context (spinlock, irq-handler, ...). * * This is a useful debugging help to be able to catch problems early and not - * be biten later when the calling function happens to sleep when it is not + * be bitten later when the calling function happens to sleep when it is not * supposed to. */ #ifdef CONFIG_PREEMPT_VOLUNTARY -- cgit v1.2.3-71-gd317 From 98c4f0c336afe4318c12397bc74910d86ee036a2 Mon Sep 17 00:00:00 2001 From: Chase Venters Date: Thu, 30 Nov 2006 04:53:49 +0100 Subject: Fix jiffies.h comment jiffies.h includes a comment informing that jiffies_64 must be read with the assistance of the xtime_lock seqlock. The comment text, however, calls jiffies_64 "not volatile", which should probably read "not atomic". Signed-off-by: Chase Venters Signed-off-by: Adrian Bunk --- include/linux/jiffies.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index c8d5f207c3d4..0ec6e28bccd2 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -74,7 +74,7 @@ #define __jiffy_data __attribute__((section(".data"))) /* - * The 64-bit value is not volatile - you MUST NOT read it + * The 64-bit value is not atomic - you MUST NOT read it * without sampling the sequence number in xtime_lock. * get_jiffies_64() will do this for you as appropriate. */ -- cgit v1.2.3-71-gd317 From 0779bf2d2ecc4d9b1e9437ae659f50e6776a7666 Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Thu, 30 Nov 2006 05:24:39 +0100 Subject: Fix misc .c/.h comment typos Fix various .c/.h typos in comments (no code changes). Signed-off-by: Matt LaPlante Signed-off-by: Adrian Bunk --- arch/cris/arch-v10/drivers/eeprom.c | 6 +++--- arch/cris/arch-v10/drivers/i2c.c | 2 +- arch/cris/arch-v10/kernel/kgdb.c | 2 +- arch/ia64/hp/common/sba_iommu.c | 8 ++++---- arch/sh64/lib/dbg.c | 2 +- drivers/atm/iphase.c | 2 +- drivers/char/rio/riocmd.c | 2 +- drivers/char/rio/rioinit.c | 2 +- drivers/char/rio/rioparam.c | 6 +++--- drivers/ide/ide-floppy.c | 2 +- drivers/isdn/hardware/eicon/os_4bri.c | 2 +- drivers/isdn/hisax/hfc4s8s_l1.h | 2 +- drivers/media/dvb/ttpci/budget-patch.c | 8 ++++---- drivers/net/e100.c | 2 +- drivers/net/e1000/e1000_hw.c | 2 +- drivers/net/sk98lin/h/skdrv2nd.h | 2 +- drivers/net/sk98lin/skdim.c | 4 ++-- drivers/net/wireless/ipw2200.c | 4 ++-- drivers/parisc/ccio-dma.c | 2 +- drivers/parisc/iosapic.c | 6 +++--- drivers/pci/hotplug/ibmphp_hpc.c | 2 +- drivers/s390/net/claw.h | 2 +- drivers/scsi/aic94xx/aic94xx_reg_def.h | 2 +- drivers/scsi/aic94xx/aic94xx_sds.c | 4 ++-- drivers/scsi/ncr53c8xx.c | 14 +++++++------- drivers/scsi/ncr53c8xx.h | 6 +++--- drivers/usb/host/u132-hcd.c | 6 +++--- drivers/usb/misc/usb_u132.h | 2 +- drivers/usb/serial/digi_acceleport.c | 2 +- fs/reiserfs/journal.c | 6 +++--- include/asm-m68knommu/mcfmbus.h | 2 +- include/asm-parisc/dma.h | 6 +++--- include/asm-parisc/pci.h | 2 +- include/asm-parisc/ropes.h | 2 +- include/linux/ixjuser.h | 2 +- include/linux/reiserfs_fs_sb.h | 2 +- net/wanrouter/af_wanpipe.c | 4 ++-- net/wanrouter/wanmain.c | 2 +- sound/oss/cs46xx.c | 6 +++--- 39 files changed, 71 insertions(+), 71 deletions(-) (limited to 'include/linux') diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c index 6e1f191a71e3..284ebfda03f0 100644 --- a/arch/cris/arch-v10/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -1,7 +1,7 @@ /*!***************************************************************************** *! -*! Implements an interface for i2c compatible eeproms to run under linux. -*! Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustents by +*! Implements an interface for i2c compatible eeproms to run under Linux. +*! Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustments by *! Johan.Adolfsson@axis.com *! *! Probing results: @@ -51,7 +51,7 @@ *! Revision 1.8 2001/06/15 13:24:29 jonashg *! * Added verification of pointers from userspace in read and write. *! * Made busy counter volatile. -*! * Added define for inital write delay. +*! * Added define for initial write delay. *! * Removed warnings by using loff_t instead of unsigned long. *! *! Revision 1.7 2001/06/14 15:26:54 jonashg diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c index 6114596c3b33..092c724a645f 100644 --- a/arch/cris/arch-v10/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c @@ -47,7 +47,7 @@ *! Update Port B register and shadow even when running with hardware support *! to avoid glitches when reading bits *! Never set direction to out in i2c_inbyte -*! Removed incorrect clock togling at end of i2c_inbyte +*! Removed incorrect clock toggling at end of i2c_inbyte *! *! Revision 1.8 2002/08/13 06:31:53 starvik *! Made SDA and SCL line configurable diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c index 34528da98817..07628a13c6c4 100644 --- a/arch/cris/arch-v10/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -33,7 +33,7 @@ *! *! Revision 1.2 2002/11/19 14:35:24 starvik *! Changes from linux 2.4 -*! Changed struct initializer syntax to the currently prefered notation +*! Changed struct initializer syntax to the currently preferred notation *! *! Revision 1.1 2001/12/17 13:59:27 bjornw *! Initial revision diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index db8e1fcfa047..14691cda05c3 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -75,7 +75,7 @@ ** If a device prefetches beyond the end of a valid pdir entry, it will cause ** a hard failure, ie. MCA. Version 3.0 and later of the zx1 LBA should ** disconnect on 4k boundaries and prevent such issues. If the device is -** particularly agressive, this option will keep the entire pdir valid such +** particularly aggressive, this option will keep the entire pdir valid such ** that prefetching will hit a valid address. This could severely impact ** error containment, and is therefore off by default. The page that is ** used for spill-over is poisoned, so that should help debugging somewhat. @@ -258,10 +258,10 @@ static u64 prefetch_spill_page; /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up -** (or rather not merge) DMA's into managable chunks. +** (or rather not merge) DMAs into manageable chunks. ** On parisc, this is more of the software/tuning constraint -** rather than the HW. I/O MMU allocation alogorithms can be -** faster with smaller size is (to some degree). +** rather than the HW. I/O MMU allocation algorithms can be +** faster with smaller sizes (to some degree). */ #define DMA_CHUNK_SIZE (BITS_PER_LONG*iovp_size) diff --git a/arch/sh64/lib/dbg.c b/arch/sh64/lib/dbg.c index 1326f45f31eb..4310fc87444e 100644 --- a/arch/sh64/lib/dbg.c +++ b/arch/sh64/lib/dbg.c @@ -383,7 +383,7 @@ void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs) /* ======================================================================= */ /* -** Depending on scan the MMU, Data or Instrction side +** Depending on scan the MMU, Data or Instruction side ** looking for a valid mapping matching Eaddr & asid. ** Return -1 if not found or the TLB id entry otherwise. ** Note: it works only for 4k pages! diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 9ed1c60048f0..bb7ef570514c 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -305,7 +305,7 @@ static void clear_lockup (struct atm_vcc *vcc, IADEV *dev) { ** | R | NZ | 5-bit exponent | 9-bit mantissa | ** +----+----+------------------+-------------------------------+ ** -** R = reserverd (written as 0) +** R = reserved (written as 0) ** NZ = 0 if 0 cells/sec; 1 otherwise ** ** if NZ = 1, rate = 1.mmmmmmmmm x 2^(eeeee) cells/sec diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 4df6ab2206a1..167ebc84e8d7 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -922,7 +922,7 @@ int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP) ** ** Packet is an actual packet structure to be filled in with the packet ** information associated with the command. You need to fill in everything, -** as the command processore doesn't process the command packet in any way. +** as the command processor doesn't process the command packet in any way. ** ** The PreFuncP is called before the packet is enqueued on the host rup. ** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index 99f3df02b61c..0794844369d6 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c @@ -222,7 +222,7 @@ int RIOBoardTest(unsigned long paddr, void __iomem *caddr, unsigned char type, i ** which value will be written into memory. ** Call with op set to zero means that the RAM will not be read and checked ** before it is written. -** Call with op not zero, and the RAM will be read and compated with val[op-1] +** Call with op not zero and the RAM will be read and compared with val[op-1] ** to check that the data from the previous phase was retained. */ diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c index 1066d9760704..bb498d24adcc 100644 --- a/drivers/char/rio/rioparam.c +++ b/drivers/char/rio/rioparam.c @@ -87,8 +87,8 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; ** command bit set onto the port. The command bit is in the len field, ** and gets ORed in with the actual byte count. ** -** When you send a packet with the command bit set, then the first -** data byte ( data[0] ) is interpretted as the command to execute. +** When you send a packet with the command bit set the first +** data byte (data[0]) is interpreted as the command to execute. ** It also governs what data structure overlay should accompany the packet. ** Commands are defined in cirrus/cirrus.h ** @@ -103,7 +103,7 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; ** ** Most commands do not use the remaining bytes in the data array. The ** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and -** OPEN are currently analagous). With these three commands the following +** OPEN are currently analogous). With these three commands the following ** 11 data bytes are all used to pass config information such as baud rate etc. ** The fields are also defined in cirrus.h. Some contain straightforward ** information such as the transmit XON character. Two contain the transmit and diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 8ccee9c769f8..e3a267622bb6 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -1635,7 +1635,7 @@ static int idefloppy_begin_format(ide_drive_t *drive, int __user *arg) /* ** Get ATAPI_FORMAT_UNIT progress indication. ** -** Userland gives a pointer to an int. The int is set to a progresss +** Userland gives a pointer to an int. The int is set to a progress ** indicator 0-65536, with 65536=100%. ** ** If the drive does not support format progress indication, we just check diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index 11e6f937c1e4..7b4ec3f60dbf 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c @@ -464,7 +464,7 @@ int diva_4bri_init_card(diva_os_xdi_adapter_t * a) /* ** Cleanup function will be called for master adapter only -** this is garanteed by design: cleanup callback is set +** this is guaranteed by design: cleanup callback is set ** by master adapter only */ static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t * a) diff --git a/drivers/isdn/hisax/hfc4s8s_l1.h b/drivers/isdn/hisax/hfc4s8s_l1.h index e8f9c077fa85..9d5d2a56b4e9 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.h +++ b/drivers/isdn/hisax/hfc4s8s_l1.h @@ -16,7 +16,7 @@ /* * include Genero generated HFC-4S/8S header file hfc48scu.h -* for comlete register description. This will define _HFC48SCU_H_ +* for complete register description. This will define _HFC48SCU_H_ * to prevent redefinitions */ diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index fc1267b8c892..9a155396d6ac 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -500,14 +500,14 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte /* New design (By Emard) ** this rps1 code will copy internal HS event to GPIO3 pin. -** GPIO3 is in budget-patch hardware connectd to port B VSYNC +** GPIO3 is in budget-patch hardware connected to port B VSYNC ** HS is an internal event of 7146, accessible with RPS ** and temporarily raised high every n lines ** (n in defined in the RPS_THRESH1 counter threshold) ** I think HS is raised high on the beginning of the n-th line ** and remains high until this n-th line that triggered -** it is completely received. When the receiption of n-th line +** it is completely received. When the reception of n-th line ** ends, HS is lowered. ** To transmit data over DMA, 7146 needs changing state at @@ -541,7 +541,7 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte ** hardware debug note: a working budget card (including budget patch) ** with vpeirq() interrupt setup in mode "0x90" (every 64K) will ** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes -** and that means 3*25=75 Hz of interrupt freqency, as seen by +** and that means 3*25=75 Hz of interrupt frequency, as seen by ** watch cat /proc/interrupts ** ** If this frequency is 3x lower (and data received in the DMA @@ -550,7 +550,7 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte ** this means VSYNC line is not connected in the hardware. ** (check soldering pcb and pins) ** The same behaviour of missing VSYNC can be duplicated on budget -** cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. +** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. */ // Setup RPS1 "program" (p35) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 19ab3441269c..3a8df479cbda 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1215,7 +1215,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb * the literal in the instruction before the code is loaded, the * driver can change the algorithm. * -* INTDELAY - This loads the dead-man timer with its inital value. +* INTDELAY - This loads the dead-man timer with its initial value. * When this timer expires the interrupt is asserted, and the * timer is reset each time a new packet is received. (see * BUNDLEMAX below to set the limit on number of chained packets) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 65077f39da69..796c4f7d4260 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -3868,7 +3868,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code * -* Sets bit 15 of the MII Control regiser +* Sets bit 15 of the MII Control register ******************************************************************************/ int32_t e1000_phy_reset(struct e1000_hw *hw) diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h index 778d9e618ebd..3fa67171e832 100644 --- a/drivers/net/sk98lin/h/skdrv2nd.h +++ b/drivers/net/sk98lin/h/skdrv2nd.h @@ -160,7 +160,7 @@ struct s_IOCTL { /* ** Interim definition of SK_DRV_TIMER placed in this file until -** common modules have boon finallized +** common modules have been finalized */ #define SK_DRV_TIMER 11 #define SK_DRV_MODERATION_TIMER 1 diff --git a/drivers/net/sk98lin/skdim.c b/drivers/net/sk98lin/skdim.c index 07c1b4c8699d..37ce03fb8de3 100644 --- a/drivers/net/sk98lin/skdim.c +++ b/drivers/net/sk98lin/skdim.c @@ -252,7 +252,7 @@ SkDimEnableModerationIfNeeded(SK_AC *pAC) { /******************************************************************************* ** Function : SkDimDisplayModerationSettings -** Description : Displays the current settings regaring interrupt moderation +** Description : Displays the current settings regarding interrupt moderation ** Programmer : Ralph Roesler ** Last Modified: 22-mar-03 ** Returns : void (!) @@ -510,7 +510,7 @@ EnableIntMod(SK_AC *pAC) { /******************************************************************************* ** Function : DisableIntMod() -** Description : Disbles the interrupt moderation independent of what inter- +** Description : Disables the interrupt moderation independent of what inter- ** rupts are running or not ** Programmer : Ralph Roesler ** Last Modified: 23-mar-03 diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 1f742814a01c..72120d5c2f7b 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6920,8 +6920,8 @@ static int ipw_qos_association(struct ipw_priv *priv, } /* -* handling the beaconing responces. if we get different QoS setting -* of the network from the the associated setting adjust the QoS +* handling the beaconing responses. if we get different QoS setting +* off the network from the associated setting, adjust the QoS * setting */ static int ipw_qos_association_resp(struct ipw_priv *priv, diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 68cb3a080050..fe3f5f5365c5 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -486,7 +486,7 @@ typedef unsigned long space_t; ** This bit tells U2 to do R/M/W for partial cachelines. "Streaming" ** data can avoid this if the mapping covers full cache lines. ** o STOP_MOST is needed for atomicity across cachelines. -** Apperently only "some EISA devices" need this. +** Apparently only "some EISA devices" need this. ** Using CONFIG_ISA is hack. Only the IOA with EISA under it needs ** to use this hint iff the EISA devices needs this feature. ** According to the U2 ERS, STOP_MOST enabled pages hurt performance. diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index c2949b4367e5..12bab64a62a1 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -50,12 +50,12 @@ ** ** PA Firmware ** ----------- -** PA-RISC platforms have two fundementally different types of firmware. +** PA-RISC platforms have two fundamentally different types of firmware. ** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register ** and BARs similar to a traditional PC BIOS. ** The newer "PAT" firmware supports PDC calls which return tables. -** PAT firmware only initializes PCI Console and Boot interface. -** With these tables, the OS can progam all other PCI devices. +** PAT firmware only initializes the PCI Console and Boot interface. +** With these tables, the OS can program all other PCI devices. ** ** One such PAT PDC call returns the "Interrupt Routing Table" (IRT). ** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index c3ac98a0a6a6..f55ac3885cb3 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -531,7 +531,7 @@ static u8 hpc_readcmdtoindex (u8 cmd, u8 index) * * Action: issue a READ command to HPC * -* Input: pslot - can not be NULL for READ_ALLSTAT +* Input: pslot - cannot be NULL for READ_ALLSTAT * pstatus - can be NULL for READ_ALLSTAT * * Return 0 or error codes diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h index 969be465309c..1ee9a6f06541 100644 --- a/drivers/s390/net/claw.h +++ b/drivers/s390/net/claw.h @@ -29,7 +29,7 @@ #define CLAW_COMPLETE 0xff /* flag to indicate i/o completed */ /*-----------------------------------------------------* -* CLAW control comand code * +* CLAW control command code * *------------------------------------------------------*/ #define SYSTEM_VALIDATE_REQUEST 0x01 /* System Validate request */ diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index b79f45f3ad47..a11f4e6d8bd9 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h @@ -2000,7 +2000,7 @@ * The host accesses this scratch in a different manner from the * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE * and CMnSCRPAGE to access the scratch memory. A flat mapping of the - * scratch memory is avaliable for software convenience and to prevent + * scratch memory is available for software convenience and to prevent * corruption while the sequencer is running. This memory is mapped * onto addresses 800h - BFFh, total of 400h bytes. * diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index de7c04d4254d..e5a0ec37e954 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -64,7 +64,7 @@ struct asd_ocm_dir { #define OCM_INIT_DIR_ENTRIES 5 /*************************************************************************** -* OCM dircetory default +* OCM directory default ***************************************************************************/ static struct asd_ocm_dir OCMDirInit = { @@ -73,7 +73,7 @@ static struct asd_ocm_dir OCMDirInit = }; /*************************************************************************** -* OCM dircetory Entries default +* OCM directory Entries default ***************************************************************************/ static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] = { diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 6cc2bc2f62be..adb8eb4f5fd1 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -185,7 +185,7 @@ static inline struct list_head *ncr_list_pop(struct list_head *head) ** power of 2 cache line size. ** Enhanced in linux-2.3.44 to provide a memory pool ** per pcidev to support dynamic dma mapping. (I would -** have preferred a real bus astraction, btw). +** have preferred a real bus abstraction, btw). ** **========================================================== */ @@ -1438,7 +1438,7 @@ struct head { ** The first four bytes (scr_st[4]) are used inside the script by ** "COPY" commands. ** Because source and destination must have the same alignment -** in a DWORD, the fields HAVE to be at the choosen offsets. +** in a DWORD, the fields HAVE to be at the chosen offsets. ** xerr_st 0 (0x34) scratcha ** sync_st 1 (0x05) sxfer ** wide_st 3 (0x03) scntl3 @@ -1498,7 +1498,7 @@ struct head { ** the DSA (data structure address) register points ** to this substructure of the ccb. ** This substructure contains the header with -** the script-processor-changable data and +** the script-processor-changeable data and ** data blocks for the indirect move commands. ** **---------------------------------------------------------- @@ -5107,7 +5107,7 @@ void ncr_complete (struct ncb *np, struct ccb *cp) /* ** This CCB has been skipped by the NCR. -** Queue it in the correponding unit queue. +** Queue it in the corresponding unit queue. */ static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp) { @@ -5896,8 +5896,8 @@ static void ncr_log_hard_error(struct ncb *np, u16 sist, u_char dstat) ** ** In normal cases, interrupt conditions occur one at a ** time. The ncr is able to stack in some extra registers -** other interrupts that will occurs after the first one. -** But severall interrupts may occur at the same time. +** other interrupts that will occur after the first one. +** But, several interrupts may occur at the same time. ** ** We probably should only try to deal with the normal ** case, but it seems that multiple interrupts occur in @@ -6796,7 +6796,7 @@ void ncr_int_sir (struct ncb *np) ** The host status field is set to HS_NEGOTIATE to mark this ** situation. ** -** If the target doesn't answer this message immidiately +** If the target doesn't answer this message immediately ** (as required by the standard), the SIR_NEGO_FAIL interrupt ** will be raised eventually. ** The handler removes the HS_NEGOTIATE status, and sets the diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index cb8b7701431e..b39357d9af8d 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -218,7 +218,7 @@ ** Same as option 1, but also deal with ** misconfigured interrupts. ** -** - Edge triggerred instead of level sensitive. +** - Edge triggered instead of level sensitive. ** - No interrupt line connected. ** - IRQ number misconfigured. ** @@ -549,7 +549,7 @@ struct ncr_driver_setup { /* ** Initial setup. -** Can be overriden at startup by a command line. +** Can be overridden at startup by a command line. */ #define SCSI_NCR_DRIVER_SETUP \ { \ @@ -1093,7 +1093,7 @@ struct scr_tblsel { **----------------------------------------------------------- ** On 810A, 860, 825A, 875, 895 and 896 chips the content ** of SFBR register can be used as data (SCR_SFBR_DATA). -** The 896 has additionnal IO registers starting at +** The 896 has additional IO registers starting at ** offset 0x80. Bit 7 of register offset is stored in ** bit 7 of the SCRIPTS instruction first DWORD. **----------------------------------------------------------- diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 32c635ecbf31..a00d1595656c 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -211,7 +211,7 @@ int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, u8 addressofs, int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, u8 addressofs, u8 width, u32 data); /* -* these can not be inlines because we need the structure offset!! +* these cannot be inlines because we need the structure offset!! * Does anyone have a better way????? */ #define u132_read_pcimem(u132, member, data) \ @@ -3045,7 +3045,7 @@ static struct hc_driver u132_hc_driver = { * This function may be called by the USB core whilst the "usb_all_devices_rwsem" * is held for writing, thus this module must not call usb_remove_hcd() * synchronously - but instead should immediately stop activity to the -* device and ansynchronously call usb_remove_hcd() +* device and asynchronously call usb_remove_hcd() */ static int __devexit u132_remove(struct platform_device *pdev) { @@ -3241,7 +3241,7 @@ static int u132_resume(struct platform_device *pdev) #define u132_resume NULL #endif /* -* this driver is loaded explicitely by ftdi_u132 +* this driver is loaded explicitly by ftdi_u132 * * the platform_driver struct is static because it is per type of module */ diff --git a/drivers/usb/misc/usb_u132.h b/drivers/usb/misc/usb_u132.h index 551ba8906d62..5b5a3e621daa 100644 --- a/drivers/usb/misc/usb_u132.h +++ b/drivers/usb/misc/usb_u132.h @@ -52,7 +52,7 @@ * the kernel to load the "u132-hcd" module. * * The "ftdi-u132" module provides the interface to the inserted -* PC card and the "u132-hcd" module uses the API to send and recieve +* PC card and the "u132-hcd" module uses the API to send and receive * data. The API features call-backs, so that part of the "u132-hcd" * module code will run in the context of one of the kernel threads * of the "ftdi-u132" module. diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index bdb58100fc1d..5e3ac281a2f8 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -157,7 +157,7 @@ * to TASK_RUNNING will be lost and write_chan's subsequent call to * schedule() will never return (unless it catches a signal). * This race condition occurs because write_bulk_callback() (and thus -* the wakeup) are called asynchonously from an interrupt, rather than +* the wakeup) are called asynchronously from an interrupt, rather than * from the scheduler. We can avoid the race by calling the wakeup * from the scheduler queue and that's our fix: Now, at the end of * write_bulk_callback() we queue up a wakeup call on the scheduler diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 85ce23268302..ac93174c9639 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -1464,7 +1464,7 @@ static int flush_journal_list(struct super_block *s, } /* if someone has this block in a newer transaction, just make - ** sure they are commited, and don't try writing it to disk + ** sure they are committed, and don't try writing it to disk */ if (pjl) { if (atomic_read(&pjl->j_commit_left)) @@ -3384,7 +3384,7 @@ static int remove_from_transaction(struct super_block *p_s_sb, /* ** for any cnode in a journal list, it can only be dirtied of all the -** transactions that include it are commited to disk. +** transactions that include it are committed to disk. ** this checks through each transaction, and returns 1 if you are allowed to dirty, ** and 0 if you aren't ** @@ -3426,7 +3426,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) } /* syncs the commit blocks, but does not force the real buffers to disk -** will wait until the current transaction is done/commited before returning +** will wait until the current transaction is done/committed before returning */ int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) diff --git a/include/asm-m68knommu/mcfmbus.h b/include/asm-m68knommu/mcfmbus.h index 13df9d41bd1a..319899c47a2c 100644 --- a/include/asm-m68knommu/mcfmbus.h +++ b/include/asm-m68knommu/mcfmbus.h @@ -37,7 +37,7 @@ #define MCFMBUS_MFDR_MBC(a) ((a)&0x3F) /*M-Bus Clock*/ /* -* Define bit flags in Controll Register +* Define bit flags in Control Register */ #define MCFMBUS_MBCR_MEN (0x80) /* M-Bus Enable */ diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h index da2cf373e31c..31ad0f05af3d 100644 --- a/include/asm-parisc/dma.h +++ b/include/asm-parisc/dma.h @@ -17,10 +17,10 @@ /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up -** (or rather not merge) DMA's into managable chunks. +** (or rather not merge) DMAs into manageable chunks. ** On parisc, this is more of the software/tuning constraint -** rather than the HW. I/O MMU allocation alogorithms can be -** faster with smaller size is (to some degree). +** rather than the HW. I/O MMU allocation algorithms can be +** faster with smaller sizes (to some degree). */ #define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE) diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h index 7b8ad118d2fe..7b3be9ac0dda 100644 --- a/include/asm-parisc/pci.h +++ b/include/asm-parisc/pci.h @@ -149,7 +149,7 @@ extern int parisc_bus_is_phys; /* in arch/parisc/kernel/setup.c */ /* ** Most PCI devices (eg Tulip, NCR720) also export the same registers ** to both MMIO and I/O port space. Due to poor performance of I/O Port -** access under HP PCI bus adapters, strongly reccomend use of MMIO +** access under HP PCI bus adapters, strongly recommend the use of MMIO ** address space. ** ** While I'm at it more PA programming notes: diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h index 5542dd00472b..007a880615eb 100644 --- a/include/asm-parisc/ropes.h +++ b/include/asm-parisc/ropes.h @@ -14,7 +14,7 @@ #endif /* -** The number of pdir entries to "free" before issueing +** The number of pdir entries to "free" before issuing ** a read to PCOM register to flush out PCOM writes. ** Interacts with allocation granularity (ie 4 or 8 entries ** allocated and free'd/purged at a time might make this diff --git a/include/linux/ixjuser.h b/include/linux/ixjuser.h index fd1756d3a47e..88b45895746d 100644 --- a/include/linux/ixjuser.h +++ b/include/linux/ixjuser.h @@ -315,7 +315,7 @@ typedef struct { * structures. If the freq0 variable is non-zero, the tone table contents * for the tone_index are updated to the frequencies and gains defined. It * should be noted that DTMF tones cannot be reassigned, so if DTMF tone -* table indexs are used in a cadence the frequency and gain variables will +* table indexes are used in a cadence the frequency and gain variables will * be ignored. * * If the array elements contain frequency parameters the driver will diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h index 73e0becec086..62a7169aed8b 100644 --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h @@ -429,7 +429,7 @@ enum reiserfs_mount_options { /* -o hash={tea, rupasov, r5, detect} is meant for properly mounting ** reiserfs disks from 3.5.19 or earlier. 99% of the time, this option ** is not required. If the normal autodection code can't determine which -** hash to use (because both hases had the same value for a file) +** hash to use (because both hashes had the same value for a file) ** use this option to force a specific hash. It won't allow you to override ** the existing hash on the FS, so if you have a tea hash disk, and mount ** with -o hash=rupasov, the mount will fail. diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 6f39faa15832..c2059733e15a 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -13,7 +13,7 @@ * Due Credit: * Wanpipe socket layer is based on Packet and * the X25 socket layers. The above sockets were -* used for the specific use of Sangoma Technoloiges +* used for the specific use of Sangoma Technologies * API programs. * Packet socket Authors: Ross Biro, Fred N. van Kempen and * Alan Cox. @@ -23,7 +23,7 @@ * Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets. * Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call. * Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. -* Server and client applicaton can run +* Server and client application can run * simultaneously without conflicts. * Feb 29, 2000 Nenad Corbic o Added support for PVC protocols, such as * CHDLC, Frame Relay and HDLC API. diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 9479659277ae..316211d9f17d 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -3,7 +3,7 @@ * * This module is completely hardware-independent and provides * the following common services for the WAN Link Drivers: -* o WAN device managenment (registering, unregistering) +* o WAN device management (registering, unregistering) * o Network interface management * o Physical connection management (dial-up, incoming calls) * o Logical connection management (switched virtual circuits) diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c index 6e3c41f530e6..b1c5d8286e40 100644 --- a/sound/oss/cs46xx.c +++ b/sound/oss/cs46xx.c @@ -779,7 +779,7 @@ static unsigned int cs_set_adc_rate(struct cs_state *state, unsigned int rate) rate = 48000 / 9; /* - * We can not capture at at rate greater than the Input Rate (48000). + * We cannot capture at at rate greater than the Input Rate (48000). * Return an error if an attempt is made to stray outside that limit. */ if (rate > 48000) @@ -4754,8 +4754,8 @@ static int cs_hardware_init(struct cs_card *card) mdelay(5 * cs_laptop_wait); /* Shouldnt be needed ?? */ /* -* If we are resuming under 2.2.x then we can not schedule a timeout. -* so, just spin the CPU. +* If we are resuming under 2.2.x then we cannot schedule a timeout, +* so just spin the CPU. */ if (card->pm.flags & CS46XX_PM_IDLE) { /* -- cgit v1.2.3-71-gd317 From 03a67a46af8647b2c7825107045ecae641e103d3 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 30 Nov 2006 05:32:19 +0100 Subject: Fix typos in doc and comments Changes persistant -> persistent. www.dictionary.com does not know persistant (with an A), but should it be one of those things you can spell in more than one correct way, let me know. Signed-off-by: Jan Engelhardt Signed-off-by: Adrian Bunk --- Documentation/Changes | 2 +- Documentation/power/states.txt | 2 +- arch/um/drivers/chan_user.c | 2 +- drivers/message/fusion/mptbase.c | 2 +- drivers/mtd/maps/cfi_flagadm.c | 2 +- drivers/pci/Kconfig | 2 +- fs/Kconfig | 2 +- fs/jfs/jfs_filsys.h | 2 +- include/linux/textsearch.h | 4 ++-- lib/textsearch.c | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/Documentation/Changes b/Documentation/Changes index abee7f58c1ed..73a8617f1861 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -201,7 +201,7 @@ udev ---- udev is a userspace application for populating /dev dynamically with only entries for devices actually present. udev replaces the basic -functionality of devfs, while allowing persistant device naming for +functionality of devfs, while allowing persistent device naming for devices. FUSE diff --git a/Documentation/power/states.txt b/Documentation/power/states.txt index 3e5e5d3ff419..0931a330d362 100644 --- a/Documentation/power/states.txt +++ b/Documentation/power/states.txt @@ -62,7 +62,7 @@ setup via another operating system for it to use. Despite the inconvenience, this method requires minimal work by the kernel, since the firmware will also handle restoring memory contents on resume. -If the kernel is responsible for persistantly saving state, a mechanism +If the kernel is responsible for persistently saving state, a mechanism called 'swsusp' (Swap Suspend) is used to write memory contents to free swap space. swsusp has some restrictive requirements, but should work in most cases. Some, albeit outdated, documentation can be found diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 2f880cb167a5..0cad3546cb89 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -120,7 +120,7 @@ static int winch_thread(void *arg) /* These are synchronization calls between various UML threads on the * host - since they are not different kernel threads, we cannot use * kernel semaphores. We don't use SysV semaphores because they are - * persistant. */ + * persistent. */ count = os_read_file(pipe_fd, &c, sizeof(c)); if(count != sizeof(c)) printk("winch_thread : failed to read synchronization byte, " diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index e5c72719debc..051b7c5b8f03 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6185,7 +6185,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) "Abort", /* 12h */ "IO Not Yet Executed", /* 13h */ "IO Executed", /* 14h */ - "Persistant Reservation Out Not Affiliation Owner", /* 15h */ + "Persistent Reservation Out Not Affiliation Owner", /* 15h */ "Open Transmit DMA Abort", /* 16h */ "IO Device Missing Delay Retry", /* 17h */ NULL, /* 18h */ diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 92b5d883d7b0..65e5ee552010 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -80,7 +80,7 @@ struct mtd_partition flagadm_parts[] = { .size = FLASH_PARTITION2_SIZE }, { - .name = "Persistant storage", + .name = "Persistent storage", .offset = FLASH_PARTITION3_ADDR, .size = FLASH_PARTITION3_SIZE } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index d0ba112355cc..3cfb0a3575e6 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -34,7 +34,7 @@ config PCI_MULTITHREAD_PROBE It is very unwise to use this option if you are not using a boot process that can handle devices being created in any - order. A program that can create persistant block and network + order. A program that can create persistent block and network device names (like udev) is a good idea if you wish to use this option. diff --git a/fs/Kconfig b/fs/Kconfig index 8bec76bbc0c3..b3b5aa0edff9 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -972,7 +972,7 @@ config SYSFS Some system agents rely on the information in sysfs to operate. /sbin/hotplug uses device and object attributes in sysfs to assist in - delegating policy decisions, like persistantly naming devices. + delegating policy decisions, like persistently naming devices. sysfs is currently used by the block subsystem to mount the root partition. If sysfs is disabled you must specify the boot device on diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h index 9901928668cf..eb550b339bb8 100644 --- a/fs/jfs/jfs_filsys.h +++ b/fs/jfs/jfs_filsys.h @@ -81,7 +81,7 @@ #define JFS_SWAP_BYTES 0x00100000 /* running on big endian computer */ /* Directory index */ -#define JFS_DIR_INDEX 0x00200000 /* Persistant index for */ +#define JFS_DIR_INDEX 0x00200000 /* Persistent index for */ /* directory entries */ diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h index 7dac8f04d28e..004808a6df1d 100644 --- a/include/linux/textsearch.h +++ b/include/linux/textsearch.h @@ -20,7 +20,7 @@ struct ts_config; /** * struct ts_state - search state * @offset: offset for next match - * @cb: control buffer, for persistant variables of get_next_block() + * @cb: control buffer, for persistent variables of get_next_block() */ struct ts_state { @@ -71,7 +71,7 @@ struct ts_config * Called repeatedly until 0 is returned. Must assign the * head of the next block of data to &*dst and return the length * of the block or 0 if at the end. consumed == 0 indicates - * a new search. May store/read persistant values in state->cb. + * a new search. May store/read persistent values in state->cb. */ unsigned int (*get_next_block)(unsigned int consumed, const u8 **dst, diff --git a/lib/textsearch.c b/lib/textsearch.c index 2cb4a437942e..98bcadc01185 100644 --- a/lib/textsearch.c +++ b/lib/textsearch.c @@ -40,7 +40,7 @@ * configuration according to the specified parameters. * (3) User starts the search(es) by calling _find() or _next() to * fetch subsequent occurrences. A state variable is provided - * to the algorihtm to store persistant variables. + * to the algorihtm to store persistent variables. * (4) Core eventually resets the search offset and forwards the find() * request to the algorithm. * (5) Algorithm calls get_next_block() provided by the user continously -- cgit v1.2.3-71-gd317 From be1c63411addba3ad750eb4fdfc50b97bc82825e Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Fri, 1 Dec 2006 10:39:12 +0100 Subject: [PATCH] blktrace: add timestamp message This adds a new timestamp message to blktrace, giving the timeofday when we starting tracing. This helps user space correlate block trace events with eg an application strace. This requires a (compatible) update to blkparse. The changed blkparse is still able to process traces generated by older kernels, and older versions of blkparse should silently ignore the new records (because they have a pid of 0). Signed-off-by: Olaf Kirch Signed-off-by: Jens Axboe --- block/blktrace.c | 57 ++++++++++++++++++++++++++++++++++---------- include/linux/blktrace_api.h | 12 ++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/block/blktrace.c b/block/blktrace.c index 135593c8e45b..562ca7cbf858 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -22,30 +22,61 @@ #include #include #include +#include #include static DEFINE_PER_CPU(unsigned long long, blk_trace_cpu_offset) = { 0, }; static unsigned int blktrace_seq __read_mostly = 1; +/* + * Send out a notify message. + */ +static inline unsigned int trace_note(struct blk_trace *bt, + pid_t pid, int action, + const void *data, size_t len) +{ + struct blk_io_trace *t; + int cpu = smp_processor_id(); + + t = relay_reserve(bt->rchan, sizeof(*t) + len); + if (t == NULL) + return 0; + + t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; + t->time = sched_clock() - per_cpu(blk_trace_cpu_offset, cpu); + t->device = bt->dev; + t->action = action; + t->pid = pid; + t->cpu = cpu; + t->pdu_len = len; + memcpy((void *) t + sizeof(*t), data, len); + return blktrace_seq; +} + /* * Send out a notify for this process, if we haven't done so since a trace * started */ static void trace_note_tsk(struct blk_trace *bt, struct task_struct *tsk) { - struct blk_io_trace *t; + tsk->btrace_seq = trace_note(bt, tsk->pid, + BLK_TN_PROCESS, + tsk->comm, sizeof(tsk->comm)); +} - t = relay_reserve(bt->rchan, sizeof(*t) + sizeof(tsk->comm)); - if (t) { - t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; - t->device = bt->dev; - t->action = BLK_TC_ACT(BLK_TC_NOTIFY); - t->pid = tsk->pid; - t->cpu = smp_processor_id(); - t->pdu_len = sizeof(tsk->comm); - memcpy((void *) t + sizeof(*t), tsk->comm, t->pdu_len); - tsk->btrace_seq = blktrace_seq; - } +static void trace_note_time(struct blk_trace *bt) +{ + struct timespec now; + unsigned long flags; + u32 words[2]; + + getnstimeofday(&now); + words[0] = now.tv_sec; + words[1] = now.tv_nsec; + + local_irq_save(flags); + trace_note(bt, 0, BLK_TN_TIMESTAMP, words, sizeof(words)); + local_irq_restore(flags); } static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector, @@ -394,6 +425,8 @@ static int blk_trace_startstop(request_queue_t *q, int start) blktrace_seq++; smp_mb(); bt->trace_state = Blktrace_running; + + trace_note_time(bt); ret = 0; } } else { diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index b99a714fcac6..3680ff9a30ed 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -49,6 +49,15 @@ enum blktrace_act { __BLK_TA_REMAP, /* bio was remapped */ }; +/* + * Notify events. + */ +enum blktrace_notify { + __BLK_TN_PROCESS = 0, /* establish pid/name mapping */ + __BLK_TN_TIMESTAMP, /* include system clock */ +}; + + /* * Trace actions in full. Additionally, read or write is masked */ @@ -68,6 +77,9 @@ enum blktrace_act { #define BLK_TA_BOUNCE (__BLK_TA_BOUNCE) #define BLK_TA_REMAP (__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE)) +#define BLK_TN_PROCESS (__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY)) +#define BLK_TN_TIMESTAMP (__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY)) + #define BLK_IO_TRACE_MAGIC 0x65617400 #define BLK_IO_TRACE_VERSION 0x07 -- cgit v1.2.3-71-gd317 From 0e75f9063f5c55fb0b0b546a7c356f8ec186825e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 1 Dec 2006 10:40:55 +0100 Subject: [PATCH] block: support larger block pc requests This patch modifies blk_rq_map/unmap_user() and the cdrom and scsi_ioctl.c users so that it supports requests larger than bio by chaining them together. Signed-off-by: Mike Christie Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 166 +++++++++++++++++++++++++++++++++++++------------ block/scsi_ioctl.c | 53 ++++++++-------- drivers/cdrom/cdrom.c | 6 +- fs/bio.c | 18 +----- include/linux/blkdev.h | 7 ++- 5 files changed, 160 insertions(+), 90 deletions(-) (limited to 'include/linux') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9eaee6640535..0f82e12f7b67 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2322,6 +2322,84 @@ void blk_insert_request(request_queue_t *q, struct request *rq, EXPORT_SYMBOL(blk_insert_request); +static int __blk_rq_unmap_user(struct bio *bio) +{ + int ret = 0; + + if (bio) { + if (bio_flagged(bio, BIO_USER_MAPPED)) + bio_unmap_user(bio); + else + ret = bio_uncopy_user(bio); + } + + return ret; +} + +static int __blk_rq_map_user(request_queue_t *q, struct request *rq, + void __user *ubuf, unsigned int len) +{ + unsigned long uaddr; + struct bio *bio, *orig_bio; + int reading, ret; + + reading = rq_data_dir(rq) == READ; + + /* + * if alignment requirement is satisfied, map in user pages for + * direct dma. else, set up kernel bounce buffers + */ + uaddr = (unsigned long) ubuf; + if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) + bio = bio_map_user(q, NULL, uaddr, len, reading); + else + bio = bio_copy_user(q, uaddr, len, reading); + + if (IS_ERR(bio)) { + return PTR_ERR(bio); + } + + orig_bio = bio; + blk_queue_bounce(q, &bio); + /* + * We link the bounce buffer in and could have to traverse it + * later so we have to get a ref to prevent it from being freed + */ + bio_get(bio); + + /* + * for most (all? don't know of any) queues we could + * skip grabbing the queue lock here. only drivers with + * funky private ->back_merge_fn() function could be + * problematic. + */ + spin_lock_irq(q->queue_lock); + if (!rq->bio) + blk_rq_bio_prep(q, rq, bio); + else if (!q->back_merge_fn(q, rq, bio)) { + ret = -EINVAL; + spin_unlock_irq(q->queue_lock); + goto unmap_bio; + } else { + rq->biotail->bi_next = bio; + rq->biotail = bio; + + rq->nr_sectors += bio_sectors(bio); + rq->hard_nr_sectors = rq->nr_sectors; + rq->data_len += bio->bi_size; + } + spin_unlock_irq(q->queue_lock); + + return bio->bi_size; + +unmap_bio: + /* if it was boucned we must call the end io function */ + bio_endio(bio, bio->bi_size, 0); + __blk_rq_unmap_user(orig_bio); + bio_put(bio); + return ret; +} + /** * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage * @q: request queue where request should be inserted @@ -2343,42 +2421,44 @@ EXPORT_SYMBOL(blk_insert_request); * unmapping. */ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, - unsigned int len) + unsigned long len) { - unsigned long uaddr; - struct bio *bio; - int reading; + unsigned long bytes_read = 0; + int ret; if (len > (q->max_hw_sectors << 9)) return -EINVAL; if (!len || !ubuf) return -EINVAL; - reading = rq_data_dir(rq) == READ; + while (bytes_read != len) { + unsigned long map_len, end, start; - /* - * if alignment requirement is satisfied, map in user pages for - * direct dma. else, set up kernel bounce buffers - */ - uaddr = (unsigned long) ubuf; - if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) - bio = bio_map_user(q, NULL, uaddr, len, reading); - else - bio = bio_copy_user(q, uaddr, len, reading); + map_len = min_t(unsigned long, len - bytes_read, BIO_MAX_SIZE); + end = ((unsigned long)ubuf + map_len + PAGE_SIZE - 1) + >> PAGE_SHIFT; + start = (unsigned long)ubuf >> PAGE_SHIFT; - if (!IS_ERR(bio)) { - rq->bio = rq->biotail = bio; - blk_rq_bio_prep(q, rq, bio); + /* + * A bad offset could cause us to require BIO_MAX_PAGES + 1 + * pages. If this happens we just lower the requested + * mapping len by a page so that we can fit + */ + if (end - start > BIO_MAX_PAGES) + map_len -= PAGE_SIZE; - rq->buffer = rq->data = NULL; - rq->data_len = len; - return 0; + ret = __blk_rq_map_user(q, rq, ubuf, map_len); + if (ret < 0) + goto unmap_rq; + bytes_read += ret; + ubuf += ret; } - /* - * bio is the err-ptr - */ - return PTR_ERR(bio); + rq->buffer = rq->data = NULL; + return 0; +unmap_rq: + blk_rq_unmap_user(rq); + return ret; } EXPORT_SYMBOL(blk_rq_map_user); @@ -2404,7 +2484,7 @@ EXPORT_SYMBOL(blk_rq_map_user); * unmapping. */ int blk_rq_map_user_iov(request_queue_t *q, struct request *rq, - struct sg_iovec *iov, int iov_count) + struct sg_iovec *iov, int iov_count, unsigned int len) { struct bio *bio; @@ -2418,10 +2498,15 @@ int blk_rq_map_user_iov(request_queue_t *q, struct request *rq, if (IS_ERR(bio)) return PTR_ERR(bio); - rq->bio = rq->biotail = bio; + if (bio->bi_size != len) { + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio); + return -EINVAL; + } + + bio_get(bio); blk_rq_bio_prep(q, rq, bio); rq->buffer = rq->data = NULL; - rq->data_len = bio->bi_size; return 0; } @@ -2429,23 +2514,26 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); /** * blk_rq_unmap_user - unmap a request with user data - * @bio: bio to be unmapped - * @ulen: length of user buffer + * @rq: rq to be unmapped * * Description: - * Unmap a bio previously mapped by blk_rq_map_user(). + * Unmap a rq previously mapped by blk_rq_map_user(). + * rq->bio must be set to the original head of the request. */ -int blk_rq_unmap_user(struct bio *bio, unsigned int ulen) +int blk_rq_unmap_user(struct request *rq) { - int ret = 0; + struct bio *bio, *mapped_bio; - if (bio) { - if (bio_flagged(bio, BIO_USER_MAPPED)) - bio_unmap_user(bio); + while ((bio = rq->bio)) { + if (bio_flagged(bio, BIO_BOUNCED)) + mapped_bio = bio->bi_private; else - ret = bio_uncopy_user(bio); - } + mapped_bio = bio; + __blk_rq_unmap_user(mapped_bio); + rq->bio = bio->bi_next; + bio_put(bio); + } return 0; } @@ -2476,11 +2564,8 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, if (rq_data_dir(rq) == WRITE) bio->bi_rw |= (1 << BIO_RW); - rq->bio = rq->biotail = bio; blk_rq_bio_prep(q, rq, bio); - rq->buffer = rq->data = NULL; - rq->data_len = len; return 0; } @@ -3495,6 +3580,7 @@ void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio) rq->hard_cur_sectors = rq->current_nr_sectors; rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio); rq->buffer = bio_data(bio); + rq->data_len = bio->bi_size; rq->bio = rq->biotail = bio; } diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index e55a75621437..5493c2fbbab1 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -226,7 +226,6 @@ static int sg_io(struct file *file, request_queue_t *q, unsigned long start_time; int writing = 0, ret = 0; struct request *rq; - struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char cmd[BLK_MAX_CDB]; @@ -258,30 +257,6 @@ static int sg_io(struct file *file, request_queue_t *q, if (!rq) return -ENOMEM; - if (hdr->iovec_count) { - const int size = sizeof(struct sg_iovec) * hdr->iovec_count; - struct sg_iovec *iov; - - iov = kmalloc(size, GFP_KERNEL); - if (!iov) { - ret = -ENOMEM; - goto out; - } - - if (copy_from_user(iov, hdr->dxferp, size)) { - kfree(iov); - ret = -EFAULT; - goto out; - } - - ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count); - kfree(iov); - } else if (hdr->dxfer_len) - ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); - - if (ret) - goto out; - /* * fill in request structure */ @@ -294,7 +269,6 @@ static int sg_io(struct file *file, request_queue_t *q, rq->sense_len = 0; rq->cmd_type = REQ_TYPE_BLOCK_PC; - bio = rq->bio; /* * bounce this after holding a reference to the original bio, it's @@ -309,6 +283,31 @@ static int sg_io(struct file *file, request_queue_t *q, if (!rq->timeout) rq->timeout = BLK_DEFAULT_TIMEOUT; + if (hdr->iovec_count) { + const int size = sizeof(struct sg_iovec) * hdr->iovec_count; + struct sg_iovec *iov; + + iov = kmalloc(size, GFP_KERNEL); + if (!iov) { + ret = -ENOMEM; + goto out; + } + + if (copy_from_user(iov, hdr->dxferp, size)) { + kfree(iov); + ret = -EFAULT; + goto out; + } + + ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count, + hdr->dxfer_len); + kfree(iov); + } else if (hdr->dxfer_len) + ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); + + if (ret) + goto out; + rq->retries = 0; start_time = jiffies; @@ -339,7 +338,7 @@ static int sg_io(struct file *file, request_queue_t *q, hdr->sb_len_wr = len; } - if (blk_rq_unmap_user(bio, hdr->dxfer_len)) + if (blk_rq_unmap_user(rq)) ret = -EFAULT; /* may not have succeeded, but output values written to control diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 7ea0f48f8fa6..2df5cf4ec743 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2133,16 +2133,14 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, rq->timeout = 60 * HZ; bio = rq->bio; - if (rq->bio) - blk_queue_bounce(q, &rq->bio); - if (blk_execute_rq(q, cdi->disk, rq, 0)) { struct request_sense *s = rq->sense; ret = -EIO; cdi->last_sense = s->sense_key; } - if (blk_rq_unmap_user(bio, len)) + rq->bio = bio; + if (blk_rq_unmap_user(rq)) ret = -EFAULT; if (ret) diff --git a/fs/bio.c b/fs/bio.c index d91cfbf7ebc4..aa4d09bd4e71 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -560,10 +560,8 @@ struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr, break; } - if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) { - ret = -EINVAL; + if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) break; - } len -= bytes; } @@ -750,7 +748,6 @@ struct bio *bio_map_user_iov(request_queue_t *q, struct block_device *bdev, int write_to_vm) { struct bio *bio; - int len = 0, i; bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm); @@ -765,18 +762,7 @@ struct bio *bio_map_user_iov(request_queue_t *q, struct block_device *bdev, */ bio_get(bio); - for (i = 0; i < iov_count; i++) - len += iov[i].iov_len; - - if (bio->bi_size == len) - return bio; - - /* - * don't support partial mappings - */ - bio_endio(bio, bio->bi_size, 0); - bio_unmap_user(bio); - return ERR_PTR(-EINVAL); + return bio; } static void __bio_unmap_user(struct bio *bio) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 7bfcde2d5578..e1c7286165ff 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -678,10 +678,11 @@ extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); extern void blk_start_queueing(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); -extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int); -extern int blk_rq_unmap_user(struct bio *, unsigned int); +extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long); +extern int blk_rq_unmap_user(struct request *); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); -extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int); +extern int blk_rq_map_user_iov(request_queue_t *, struct request *, + struct sg_iovec *, int, unsigned int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *, int); extern void blk_execute_rq_nowait(request_queue_t *, struct gendisk *, -- cgit v1.2.3-71-gd317 From bb37b94c68e7b37eecea8576039ae9396ca07839 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 1 Dec 2006 10:42:33 +0100 Subject: [BLOCK] Cleanup unused variable passing - ->init_queue() does not need the elevator passed in - ->put_request() is a hot path and need not have the queue passed in - cfq_update_io_seektime() does not need cfqd passed in Signed-off-by: Jens Axboe --- block/as-iosched.c | 2 +- block/cfq-iosched.c | 9 ++++----- block/deadline-iosched.c | 2 +- block/elevator.c | 4 ++-- block/noop-iosched.c | 2 +- include/linux/elevator.h | 4 ++-- 6 files changed, 11 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/block/as-iosched.c b/block/as-iosched.c index 50b95e4c1425..00242111a457 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1317,7 +1317,7 @@ static void as_exit_queue(elevator_t *e) /* * initialize elevator private data (as_data). */ -static void *as_init_queue(request_queue_t *q, elevator_t *e) +static void *as_init_queue(request_queue_t *q) { struct as_data *ad; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 1d9c3c70a9a0..e9019ed39b73 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1464,8 +1464,7 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic) } static void -cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, - struct request *rq) +cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq) { sector_t sdist; u64 total; @@ -1617,7 +1616,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, } cfq_update_io_thinktime(cfqd, cic); - cfq_update_io_seektime(cfqd, cic, rq); + cfq_update_io_seektime(cic, rq); cfq_update_idle_window(cfqd, cfqq, cic); cic->last_queue = jiffies; @@ -1770,7 +1769,7 @@ static int cfq_may_queue(request_queue_t *q, int rw) /* * queue lock held here */ -static void cfq_put_request(request_queue_t *q, struct request *rq) +static void cfq_put_request(struct request *rq) { struct cfq_queue *cfqq = RQ_CFQQ(rq); @@ -1951,7 +1950,7 @@ static void cfq_exit_queue(elevator_t *e) kfree(cfqd); } -static void *cfq_init_queue(request_queue_t *q, elevator_t *e) +static void *cfq_init_queue(request_queue_t *q) { struct cfq_data *cfqd; int i; diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index b7c5b34cb7b4..6d673e938d3e 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -356,7 +356,7 @@ static void deadline_exit_queue(elevator_t *e) /* * initialize elevator private data (deadline_data). */ -static void *deadline_init_queue(request_queue_t *q, elevator_t *e) +static void *deadline_init_queue(request_queue_t *q) { struct deadline_data *dd; diff --git a/block/elevator.c b/block/elevator.c index 8ccd163254b8..c0063f345c5d 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -129,7 +129,7 @@ static struct elevator_type *elevator_get(const char *name) static void *elevator_init_queue(request_queue_t *q, struct elevator_queue *eq) { - return eq->ops->elevator_init_fn(q, eq); + return eq->ops->elevator_init_fn(q); } static void elevator_attach(request_queue_t *q, struct elevator_queue *eq, @@ -810,7 +810,7 @@ void elv_put_request(request_queue_t *q, struct request *rq) elevator_t *e = q->elevator; if (e->ops->elevator_put_req_fn) - e->ops->elevator_put_req_fn(q, rq); + e->ops->elevator_put_req_fn(rq); } int elv_may_queue(request_queue_t *q, int rw) diff --git a/block/noop-iosched.c b/block/noop-iosched.c index 79af43179421..1c3de2b9a6b5 100644 --- a/block/noop-iosched.c +++ b/block/noop-iosched.c @@ -65,7 +65,7 @@ noop_latter_request(request_queue_t *q, struct request *rq) return list_entry(rq->queuelist.next, struct request, queuelist); } -static void *noop_init_queue(request_queue_t *q, elevator_t *e) +static void *noop_init_queue(request_queue_t *q) { struct noop_data *nd; diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 2fa9f1144228..a24931d24404 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -21,11 +21,11 @@ typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *); typedef int (elevator_may_queue_fn) (request_queue_t *, int); typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, gfp_t); -typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); +typedef void (elevator_put_req_fn) (struct request *); typedef void (elevator_activate_req_fn) (request_queue_t *, struct request *); typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *); -typedef void *(elevator_init_fn) (request_queue_t *, elevator_t *); +typedef void *(elevator_init_fn) (request_queue_t *); typedef void (elevator_exit_fn) (elevator_t *); struct elevator_ops -- cgit v1.2.3-71-gd317 From bce40a36de574376f41f1ff3c4d212a7da2a3c90 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 21 Oct 2006 12:35:02 +0200 Subject: [PATCH] mmc: Add support for mmc v4 high speed mode This adds support for the high-speed modes defined by mmc v4 (assuming the host controller is up to it). On a TI sdhci controller, it improves read speed from 1.3MBps to 2.3MBps. The TI controller can only go up to 24MHz, but everything helps. Another person has taken this basic patch and used it on a Nokia 770 to get a bigger boost because that controller can run at 48MHZ. Signed-off-by: Philip Langdale Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 121 ++++++++++++++++++++++++++++++++++++++++++- include/linux/mmc/card.h | 8 +++ include/linux/mmc/protocol.h | 47 +++++++++++++++-- 3 files changed, 171 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 766bc54406e5..2d5b93000dee 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -4,6 +4,7 @@ * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. + * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -953,6 +954,114 @@ static void mmc_read_csds(struct mmc_host *host) } } +static void mmc_process_ext_csds(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + + struct scatterlist sg; + + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + u8 *ext_csd; + ext_csd = kmalloc(512, GFP_KERNEL); + if (!ext_csd) { + printk("%s: could not allocate a buffer to receive the ext_csd." + "mmc v4 cards will be treated as v3.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (mmc_card_sd(card)) + continue; + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_EXT_CSD; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 512; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, ext_csd, 512); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + switch (ext_csd[EXT_CSD_CARD_TYPE]) { + case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 52000000; + break; + case EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 26000000; + break; + default: + /* MMC v4 spec says this cannot happen */ + printk("%s: card is mmc v4 but doesn't support " + "any high-speed modes.\n", + mmc_hostname(card->host)); + mmc_card_set_bad(card); + continue; + } + + /* Activate highspeed support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to mmc v4 " + "high-speed mode.\n", + mmc_hostname(card->host)); + continue; + } + + mmc_card_set_highspeed(card); + } + + kfree(ext_csd); + + mmc_deselect_cards(host); +} + static void mmc_read_scrs(struct mmc_host *host) { int err; @@ -1031,8 +1140,14 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) unsigned int max_dtr = host->f_max; list_for_each_entry(card, &host->cards, node) - if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) - max_dtr = card->csd.max_dtr; + if (!mmc_card_dead(card)) { + if (mmc_card_highspeed(card)) { + if (max_dtr > card->ext_csd.hs_max_dtr) + max_dtr = card->ext_csd.hs_max_dtr; + } else if (max_dtr > card->csd.max_dtr) { + max_dtr = card->csd.max_dtr; + } + } pr_debug("%s: selected %d.%03dMHz transfer rate\n", mmc_hostname(host), @@ -1152,6 +1267,8 @@ static void mmc_setup(struct mmc_host *host) if (host->mode == MMC_MODE_SD) mmc_read_scrs(host); + else + mmc_process_ext_csds(host); } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 991a37382a22..ce25256f80d5 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -39,6 +39,10 @@ struct mmc_csd { write_misalign:1; }; +struct mmc_ext_csd { + unsigned int hs_max_dtr; +}; + struct sd_scr { unsigned char sda_vsn; unsigned char bus_widths; @@ -62,11 +66,13 @@ struct mmc_card { #define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */ +#define MMC_STATE_HIGHSPEED (1<<5) /* card is in mmc4 highspeed mode */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ struct mmc_cid cid; /* card identification */ struct mmc_csd csd; /* card specific */ + struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ }; @@ -75,12 +81,14 @@ struct mmc_card { #define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD) #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) +#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD) #define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) +#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED) #define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) ((c)->dev.bus_id) diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 08dec8d9e703..311b6547f561 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -25,14 +25,16 @@ #ifndef MMC_MMC_PROTOCOL_H #define MMC_MMC_PROTOCOL_H -/* Standard MMC commands (3.1) type argument response */ +/* Standard MMC commands (4.1) type argument response */ /* class 1 */ #define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ @@ -87,6 +89,17 @@ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ #define SD_APP_SEND_SCR 51 /* adtc R1 */ +/* + * MMC_SWITCH argument format: + * + * [31:26] Always 0 + * [25:24] Access Mode + * [23:16] Location of target Byte in EXT_CSD + * [15:08] Value Byte + * [07:03] Always 0 + * [02:00] Command Set + */ + /* MMC status in R1 Type @@ -230,13 +243,41 @@ struct _mmc_csd { #define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ #define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ -#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ +#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ #define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ #define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ #define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ -#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */ +#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ + +/* + * EXT_CSD fields + */ + +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ + +/* + * MMC_SWITCH access modes + */ +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ /* * SD bus widths -- cgit v1.2.3-71-gd317 From e45a1bd20fa5b920901879e85cdf5eda21f78d7c Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sun, 29 Oct 2006 10:14:19 +0100 Subject: mmc: Add support for mmc v4 wide-bus modes This change adds support for the mmc4 4-bit wide-bus mode. The mmc4 spec defines 8-bit and 4-bit transfer modes. As we do not support any 8-bit hardware, this patch only adds support for the 4-bit mode, but it can easily be built upon when the time comes. The 4-bit mode is electrically compatible with SD's 4-bit mode but the procedure for turning it on is different. This patch implements only the essential parts of the procedure as defined by the spec. Two additional steps are recommended but not compulsory. I am documenting them here so that there's a record. 1) A bus-test mechanism is implemented using dedicated mmc commands which allow for testing the functionality of the data bus at the electrical level. This is pretty paranoid and they way the commands work is not compatible with the mmc subsystem (they don't set valid CRC values). 2) MMC v4 cards can indicate they would like to draw more than the default amount of current in wide-bus modes. We currently will never switch the card into a higher draw mode. Supposedly, allowing the card to draw more current will let it perform better, but the specs seem to indicate that the card will function correctly without the mode change. Empirical testing supports this interpretation. Signed-off-by: Philip Langdale Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 51 ++++++++++++++++++++++++++++++++------------ include/linux/mmc/protocol.h | 5 +++++ 2 files changed, 42 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2d5b93000dee..1593a6a632cf 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -397,23 +397,23 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) return err; /* - * Default bus width is 1 bit. - */ - host->ios.bus_width = MMC_BUS_WIDTH_1; - - /* - * We can only change the bus width of the selected - * card so therefore we have to put the handling + * We can only change the bus width of SD cards when + * they are selected so we have to put the handling * here. + * + * The card is in 1 bit mode by default so + * we only need to change if it supports the + * wider version. */ - if (host->caps & MMC_CAP_4_BIT_DATA) { + if (mmc_card_sd(card) && + (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + /* - * The card is in 1 bit mode by default so - * we only need to change if it supports the - * wider version. - */ - if (mmc_card_sd(card) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + * Default bus width is 1 bit. + */ + host->ios.bus_width = MMC_BUS_WIDTH_1; + + if (host->caps & MMC_CAP_4_BIT_DATA) { struct mmc_command cmd; cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.arg = SD_BUS_WIDTH_4; @@ -1055,6 +1055,29 @@ static void mmc_process_ext_csds(struct mmc_host *host) } mmc_card_set_highspeed(card); + + /* Check for host support for wide-bus modes. */ + if (!(host->caps & MMC_CAP_4_BIT_DATA)) { + continue; + } + + /* Activate 4-bit support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_4 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to " + "mmc v4 4-bit bus mode.\n", + mmc_hostname(card->host)); + continue; + } + + host->ios.bus_width = MMC_BUS_WIDTH_4; } kfree(ext_csd); diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 311b6547f561..45c51fd85786 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -256,6 +256,7 @@ struct _mmc_csd { * EXT_CSD fields */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_CARD_TYPE 196 /* RO */ @@ -270,6 +271,10 @@ struct _mmc_csd { #define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ + /* * MMC_SWITCH access modes */ -- cgit v1.2.3-71-gd317 From 7ccd266e676a3f0c6f8f897f58b684cac3dd1650 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 8 Nov 2006 23:03:10 +0100 Subject: mmc: Support for high speed SD cards Modern SD cards support a clock speed of 50 MHz. Make sure we test for this capability and do the song and dance required to activate it. Activating high speed support actually modifies the TRAN_SPEED field of the CSD. But as the spec says that the cards must report 50 MHz, we might as well skip re-reading the CSD. Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 122 +++++++++++++++++++++++++++++++++++++++++-- include/linux/mmc/card.h | 7 ++- include/linux/mmc/protocol.h | 22 ++++++++ 3 files changed, 146 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 82b7643c1654..9d190022a490 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1157,6 +1157,116 @@ static void mmc_read_scrs(struct mmc_host *host) mmc_deselect_cards(host); } +static void mmc_read_switch_caps(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + unsigned char *status; + struct scatterlist sg; + + status = kmalloc(64, GFP_KERNEL); + if (!status) { + printk(KERN_WARNING "%s: Unable to allocate buffer for " + "reading switch capabilities.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (!mmc_card_sd(card)) + continue; + if (card->scr.sda_vsn < SCR_SPEC_VER_1) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x00FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + if (status[13] & 0x02) + card->sw_caps.hs_max_dtr = 50000000; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x80FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + if ((status[16] & 0xF) != 1) { + printk(KERN_WARNING "%s: Problem switching card " + "into high-speed mode!\n", + mmc_hostname(host)); + continue; + } + + mmc_card_set_highspeed(card); + } + + kfree(status); + + mmc_deselect_cards(host); +} + static unsigned int mmc_calculate_clock(struct mmc_host *host) { struct mmc_card *card; @@ -1164,9 +1274,12 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) list_for_each_entry(card, &host->cards, node) if (!mmc_card_dead(card)) { - if (mmc_card_highspeed(card)) { + if (mmc_card_highspeed(card) && mmc_card_sd(card)) { + if (max_dtr > card->sw_caps.hs_max_dtr) + max_dtr = card->sw_caps.hs_max_dtr; + } else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) { if (max_dtr > card->ext_csd.hs_max_dtr) - max_dtr = card->ext_csd.hs_max_dtr; + max_dtr = card->ext_csd.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { max_dtr = card->csd.max_dtr; } @@ -1288,9 +1401,10 @@ static void mmc_setup(struct mmc_host *host) mmc_read_csds(host); - if (host->mode == MMC_MODE_SD) + if (host->mode == MMC_MODE_SD) { mmc_read_scrs(host); - else + mmc_read_switch_caps(host); + } else mmc_process_ext_csds(host); } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index ce25256f80d5..d0e6a5497614 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -50,6 +50,10 @@ struct sd_scr { #define SD_SCR_BUS_WIDTH_4 (1<<2) }; +struct sd_switch_caps { + unsigned int hs_max_dtr; +}; + struct mmc_host; /* @@ -66,7 +70,7 @@ struct mmc_card { #define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */ -#define MMC_STATE_HIGHSPEED (1<<5) /* card is in mmc4 highspeed mode */ +#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ @@ -74,6 +78,7 @@ struct mmc_card { struct mmc_csd csd; /* card specific */ struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ + struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ }; #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 45c51fd85786..2dce60c43f4b 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -82,6 +82,7 @@ /* class 8 */ /* This is basically the same command as for MMC with some quirks. */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ /* Application commands */ #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ @@ -100,6 +101,19 @@ * [02:00] Command Set */ +/* + * SD_SWITCH argument format: + * + * [31] Check (0) or switch (1) + * [30:24] Reserved (0) + * [23:20] Function group 6 + * [19:16] Function group 5 + * [15:12] Function group 4 + * [11:8] Function group 3 + * [7:4] Function group 2 + * [3:0] Function group 1 + */ + /* MMC status in R1 Type @@ -284,6 +298,14 @@ struct _mmc_csd { #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ +/* + * SCR field definitions + */ + +#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */ + /* * SD bus widths */ -- cgit v1.2.3-71-gd317 From 437052516779fea608261a50682b124315f48f01 Mon Sep 17 00:00:00 2001 From: "inaky@linux.intel.com" Date: Wed, 11 Oct 2006 20:05:58 -0700 Subject: usb/hub: allow hubs up to 31 children Current Wireless USB host hardware (Intel i1480 for example) allows up to 22 devices to connect, thus bringing up the max number of children in the WUSB Host Controller to 22 'fake' ports. Upcoming hardware might raise that limit. Makes almost no difference to go to 31, as the bit arrays are byte-aligned (plus an extra bit in general), so 22 bits fit in 4 bytes as 31 do. As well, the only other array that depends on USB_MAXCHILDREN is 'struct usb_hub->indicator'. By declaring it 'u8' instead of 'enum hub_led_mode', we reduce the size of each entry from 4 bytes (in i386) to 1, which will add as we when are doubling USB_MAXCHILDREN (with 16 the size of that array is 64 bytes, with 31 would be 128; by using u8 that goes down to 31 bytes). Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.h | 2 +- include/linux/usb.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 0f8e82a4d480..1b05994de4dc 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -229,7 +229,7 @@ struct usb_hub { unsigned resume_root_hub:1; unsigned has_indicators:1; - enum hub_led_mode indicator[USB_MAXCHILDREN]; + u8 indicator[USB_MAXCHILDREN]; struct work_struct leds; }; diff --git a/include/linux/usb.h b/include/linux/usb.h index 5482bfb3303d..e5cb1690975a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -313,8 +313,13 @@ struct usb_bus { /* This is arbitrary. * From USB 2.0 spec Table 11-13, offset 7, a hub can * have up to 255 ports. The most yet reported is 10. + * + * Current Wireless USB host hardware (Intel i1480 for example) allows + * up to 22 devices to connect. Upcoming hardware might raise that + * limit. Because the arrays need to add a bit for hub status data, we + * do 31, so plus one evens out to four bytes. */ -#define USB_MAXCHILDREN (16) +#define USB_MAXCHILDREN (31) struct usb_tt; -- cgit v1.2.3-71-gd317 From 0c1ac4f25f894f9df0ffe9b912c165fb6a185a3c Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Mon, 30 Oct 2006 14:53:03 -0300 Subject: USB: makes usb_endpoint_* functions inline. We have no benefits of having the usb_endpoint_* functions as functions, but making them inline saves text and data segment sizes: text data bss dec hex filename 14893634 3108770 1108840 19111244 1239d4c vmlinux.func 14893185 3108566 1108840 19110591 1239abf vmlinux.inline This is the result of a 2.6.19-rc3 kernel compiled with GCC 4.1.1 without CONFIG_MODULES, CONFIG_CC_OPTIMIZE_FOR_SIZE, CONFIG_REGPARM options set. USB support is fully enabled (while most of the other drivers are not), and that kernel has most of the USB code ported to use the endpoint functions. That happens because a call to those functions are expensive (in terms of bytes), while the function's size is smaller or have the same 'size' of the call. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 144 ------------------------------------------------- include/linux/usb.h | 142 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 131 insertions(+), 155 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 467cb02832f3..a83c2d5065c1 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -537,138 +537,6 @@ int usb_get_current_frame_number(struct usb_device *dev) return usb_hcd_get_frame_number (dev); } -/** - * usb_endpoint_dir_in - check if the endpoint has IN direction - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type IN, otherwise it returns false. - */ -int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); -} - -/** - * usb_endpoint_dir_out - check if the endpoint has OUT direction - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type OUT, otherwise it returns false. - */ -int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); -} - -/** - * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type bulk, otherwise it returns false. - */ -int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK); -} - -/** - * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type interrupt, otherwise it returns - * false. - */ -int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT); -} - -/** - * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type isochronous, otherwise it returns - * false. - */ -int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC); -} - -/** - * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has bulk transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has bulk transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); -} - -/** - * usb_endpoint_is_int_in - check if the endpoint is interrupt IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has interrupt transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has interrupt transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); -} - -/** - * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has isochronous transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has isochronous transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); -} - /*-------------------------------------------------------------------*/ /* * __usb_get_extra_descriptor() finds a descriptor of specific type in the @@ -1102,18 +970,6 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); -EXPORT_SYMBOL_GPL(usb_endpoint_dir_in); -EXPORT_SYMBOL_GPL(usb_endpoint_dir_out); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc); -EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out); -EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out); -EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out); - EXPORT_SYMBOL (usb_buffer_alloc); EXPORT_SYMBOL (usb_buffer_free); diff --git a/include/linux/usb.h b/include/linux/usb.h index e5cb1690975a..e732e024a141 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -495,17 +495,137 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, /*-------------------------------------------------------------------------*/ -extern int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd); -extern int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd); +/** + * usb_endpoint_dir_in - check if the endpoint has IN direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type IN, otherwise it returns false. + */ +static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); +} + +/** + * usb_endpoint_dir_out - check if the endpoint has OUT direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type OUT, otherwise it returns false. + */ +static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); +} + +/** + * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type bulk, otherwise it returns false. + */ +static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK); +} + +/** + * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type interrupt, otherwise it returns + * false. + */ +static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT); +} + +/** + * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type isochronous, otherwise it returns + * false. + */ +static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC); +} + +/** + * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_int_in - check if the endpoint is interrupt IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); +} + +/** + * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); +} + +/** + * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) +{ + return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); +} /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-71-gd317 From 692a186c9d5f12d43cef28d40c25247dc4f302f0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Oct 2006 17:07:51 -0500 Subject: USB: expand autosuspend/autoresume API This patch (as814) adds usb_autopm_set_interface() to the autosuspend API. It also provides convenient wrapper routines, usb_autopm_enable() and usb_autopm_disable(), for drivers that want to specify directly whether autosuspend should be allowed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 22 ++++++++++++++++++++++ include/linux/usb.h | 29 ++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ca0e40ed2b72..204495fa6b3d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1322,6 +1322,28 @@ int usb_autopm_get_interface(struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usb_autopm_get_interface); +/** + * usb_autopm_set_interface - set a USB interface's autosuspend state + * @intf: the usb_interface whose state should be set + * + * This routine sets the autosuspend state of @intf's device according + * to @intf's usage counter, which the caller must have set previously. + * If the counter is <= 0, the device is autosuspended (if it isn't + * already suspended and if nothing else prevents the autosuspend). If + * the counter is > 0, the device is autoresumed (if it isn't already + * awake). + */ +int usb_autopm_set_interface(struct usb_interface *intf) +{ + int status; + + status = usb_autopm_do_interface(intf, 0); + // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, intf->pm_usage_cnt); + return status; +} +EXPORT_SYMBOL_GPL(usb_autopm_set_interface); + #endif /* CONFIG_USB_SUSPEND */ static int usb_suspend(struct device *dev, pm_message_t message) diff --git a/include/linux/usb.h b/include/linux/usb.h index e732e024a141..864c6c21c21e 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -415,14 +415,37 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); /* USB autosuspend and autoresume */ #ifdef CONFIG_USB_SUSPEND +extern int usb_autopm_set_interface(struct usb_interface *intf); extern int usb_autopm_get_interface(struct usb_interface *intf); extern void usb_autopm_put_interface(struct usb_interface *intf); +static inline void usb_autopm_enable(struct usb_interface *intf) +{ + intf->pm_usage_cnt = 0; + usb_autopm_set_interface(intf); +} + +static inline void usb_autopm_disable(struct usb_interface *intf) +{ + intf->pm_usage_cnt = 1; + usb_autopm_set_interface(intf); +} + #else -#define usb_autopm_get_interface(intf) 0 -#define usb_autopm_put_interface(intf) do {} while (0) -#endif +static inline int usb_autopm_set_interface(struct usb_interface *intf) +{ return 0; } + +static inline int usb_autopm_get_interface(struct usb_interface *intf) +{ return 0; } + +static inline void usb_autopm_put_interface(struct usb_interface *intf) +{ } +static inline void usb_autopm_enable(struct usb_interface *intf) +{ } +static inline void usb_autopm_disable(struct usb_interface *intf) +{ } +#endif /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-71-gd317 From ce3615879ae85373c03744b45b7c2d7ae5e29b2a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 20 Nov 2006 11:12:22 -0500 Subject: USB: struct usb_device: change flag to bitflag This patch (as816) changes an existing flag in the usb_device structure to a bitflag, preparing the way for more bitflags to come in the future. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 2 +- include/linux/usb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 7729c0744886..5684d8722922 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -764,7 +764,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) err = -EINVAL; goto errout; } else { - dev->have_langid = -1; + dev->have_langid = 1; dev->string_langid = tbuf[2] | (tbuf[3]<< 8); /* always use the first langid listed */ dev_dbg (&dev->dev, "default language 0x%04x\n", diff --git a/include/linux/usb.h b/include/linux/usb.h index 864c6c21c21e..5634a2d91ec0 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -362,7 +362,7 @@ struct usb_device { u8 portnum; /* Parent port number (origin 1) */ u8 level; /* Number of USB hub ancestors */ - int have_langid; /* whether string_langid is valid */ + unsigned have_langid:1; /* whether string_langid is valid */ int string_langid; /* language ID for strings */ /* static strings from the device */ -- cgit v1.2.3-71-gd317 From ee49fb5dc89d34f1794ac9362fa97c1a640f7ddd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Nov 2006 16:55:54 -0500 Subject: USB: keep count of unsuspended children This patch (as818b) simplifies autosuspend processing by keeping track of the number of unsuspended children of each USB hub. This will permit us to avoid a good deal of unnecessary work all the time; we will no longer have to create a bunch of workqueue entries to carry out autosuspend requests, only to have them fail because one of the hub's children isn't suspended. The basic idea is simple. There already is a usage counter in the usb_device structure for preventing autosuspends. The patch just increments that counter for every unsuspended child. There's only one tricky part: When a device disconnects we need to remember whether it was suspended at the time (leave the counter alone) or not (decrement the counter). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 34 +++++++++++++++++++++++----------- drivers/usb/core/hub.c | 14 ++++++++++++++ include/linux/usb.h | 1 + 3 files changed, 38 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 40c1bf09b2b7..0fa15bd62c48 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1048,7 +1048,7 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* If the suspend succeeded, propagate it up the tree */ } else if (parent) - usb_autosuspend_device(parent, 0); + usb_autosuspend_device(parent, 1); // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); return status; @@ -1096,9 +1096,25 @@ int usb_resume_both(struct usb_device *udev) /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { if (parent) { - usb_pm_lock(parent); - parent->auto_pm = 1; - status = usb_resume_both(parent); + status = usb_autoresume_device(parent, 1); + if (status == 0) { + status = usb_resume_device(udev); + if (status) { + usb_autosuspend_device(parent, 1); + + /* It's possible usb_resume_device() + * failed after the port was + * unsuspended, causing udev to be + * logically disconnected. We don't + * want usb_disconnect() to autosuspend + * the parent again, so tell it that + * udev disconnected while still + * suspended. */ + if (udev->state == + USB_STATE_NOTATTACHED) + udev->discon_suspended = 1; + } + } } else { /* We can't progagate beyond the USB subsystem, @@ -1107,11 +1123,9 @@ int usb_resume_both(struct usb_device *udev) if (udev->dev.parent->power.power_state.event != PM_EVENT_ON) status = -EHOSTUNREACH; - } - if (status == 0) - status = usb_resume_device(udev); - if (parent) - usb_pm_unlock(parent); + else + status = usb_resume_device(udev); + } } else { /* Needed only for setting udev->dev.power.power_state.event @@ -1119,8 +1133,6 @@ int usb_resume_both(struct usb_device *udev) status = usb_resume_device(udev); } - /* Now the parent won't suspend until we are finished */ - if (status == 0 && udev->actconfig) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 46df5e60764b..e46d38b18249 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1039,6 +1039,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) if (udev->children[i]) recursively_mark_NOTATTACHED(udev->children[i]); } + if (udev->state == USB_STATE_SUSPENDED) + udev->discon_suspended = 1; udev->state = USB_STATE_NOTATTACHED; } @@ -1228,6 +1230,14 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; spin_unlock_irq(&device_state_lock); + /* Decrement the parent's count of unsuspended children */ + if (udev->parent) { + usb_pm_lock(udev); + if (!udev->discon_suspended) + usb_autosuspend_device(udev->parent, 1); + usb_pm_unlock(udev); + } + put_device(&udev->dev); } @@ -1356,6 +1366,10 @@ static int __usb_new_device(void *void_data) goto fail; } + /* Increment the parent's count of unsuspended children */ + if (udev->parent) + usb_autoresume_device(udev->parent, 1); + exit: module_put(THIS_MODULE); return err; diff --git a/include/linux/usb.h b/include/linux/usb.h index 5634a2d91ec0..0cd73edeef13 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -362,6 +362,7 @@ struct usb_device { u8 portnum; /* Parent port number (origin 1) */ u8 level; /* Number of USB hub ancestors */ + unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ int string_langid; /* language ID for strings */ -- cgit v1.2.3-71-gd317 From e65e5fb5ceb02aaea7b65bf8b3b0d0c9057718b6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 7 Nov 2006 18:21:21 +1100 Subject: PCI: Make some MSI-X #defines generic Move some MSI-X #defines into pci_regs.h so they can be used outside of drivers/pci. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.h | 8 -------- include/linux/pci_regs.h | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index f0cca1772f9c..3898f5237144 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -6,14 +6,6 @@ #ifndef MSI_H #define MSI_H -/* - * MSI-X Address Register - */ -#define PCI_MSIX_FLAGS_QSIZE 0x7FF -#define PCI_MSIX_FLAGS_ENABLE (1 << 15) -#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) -#define PCI_MSIX_FLAGS_BITMASK (1 << 0) - #define PCI_MSIX_ENTRY_SIZE 16 #define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 #define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index c321316f1bc7..064b1dc71c22 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -292,6 +292,12 @@ #define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ #define PCI_MSI_MASK_BIT 16 /* Mask bits register */ +/* MSI-X registers (these are at offset PCI_MSI_FLAGS) */ +#define PCI_MSIX_FLAGS_QSIZE 0x7FF +#define PCI_MSIX_FLAGS_ENABLE (1 << 15) +#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) +#define PCI_MSIX_FLAGS_BITMASK (1 << 0) + /* CompactPCI Hotswap Register */ #define PCI_CHSWP_CSR 2 /* Control and Status Register */ -- cgit v1.2.3-71-gd317 From a2302c68d923537436b1114aa207787c1a31bd50 Mon Sep 17 00:00:00 2001 From: John Keller Date: Wed, 4 Oct 2006 16:49:52 -0500 Subject: Altix: Initial ACPI support - ROM shadowing. Support a shadowed ROM when running with an ACPI capable PROM. Define a new dev.resource flag IORESOURCE_ROM_BIOS_COPY to describe the case of a BIOS shadowed ROM, which can then be used to avoid pci_map_rom() making an unneeded call to pci_enable_rom(). Signed-off-by: John Keller Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/io_acpi_init.c | 33 +++++++++++++++++++++++++++++++++ arch/ia64/sn/kernel/io_common.c | 5 +++-- arch/ia64/sn/kernel/io_init.c | 3 +++ drivers/pci/rom.c | 9 ++++++--- include/linux/ioport.h | 1 + 5 files changed, 46 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index a9dc36901b19..99d7f278612a 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -169,6 +169,39 @@ sn_acpi_bus_fixup(struct pci_bus *bus) } } +/* + * sn_acpi_slot_fixup - Perform any SN specific slot fixup. + * At present there does not appear to be + * any generic way to handle a ROM image + * that has been shadowed by the PROM, so + * we pass a pointer to it within the + * pcidev_info structure. + */ + +void +sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) +{ + void __iomem *addr; + size_t size; + + if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { + /* + * A valid ROM image exists and has been shadowed by the + * PROM. Setup the pci_dev ROM resource to point to + * the shadowed copy. + */ + size = dev->resource[PCI_ROM_RESOURCE].end - + dev->resource[PCI_ROM_RESOURCE].start; + addr = + ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE], + size); + dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr; + dev->resource[PCI_ROM_RESOURCE].end = + (unsigned long) addr + size; + dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY; + } +} + static struct acpi_driver acpi_sn_hubdev_driver = { .name = "SGI HUBDEV Driver", .ids = "SGIHUB,SGITIO", diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c index 12531de6754c..d4dd8f4b6b8d 100644 --- a/arch/ia64/sn/kernel/io_common.c +++ b/arch/ia64/sn/kernel/io_common.c @@ -286,9 +286,10 @@ void sn_pci_fixup_slot(struct pci_dev *dev) list_add_tail(&pcidev_info->pdi_list, &(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); - if (!SN_ACPI_BASE_SUPPORT()) + if (SN_ACPI_BASE_SUPPORT()) + sn_acpi_slot_fixup(dev, pcidev_info); + else sn_more_slot_fixup(dev, pcidev_info); - /* * Using the PROMs values for the PCI host bus, get the Linux * PCI host_pci_dev struct and set up host bus linkages diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 990224a44121..9ad843e0383b 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -210,6 +210,9 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) dev->resource[idx].parent = &ioport_resource; else dev->resource[idx].parent = &iomem_resource; + /* If ROM, mark as shadowed in PROM */ + if (idx == PCI_ROM_RESOURCE) + dev->resource[idx].flags |= IORESOURCE_ROM_BIOS_COPY; } /* Create a pci_window in the pci_controller struct for * each device resource. diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index e1dcefc69bb4..d087e0817715 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -81,7 +81,8 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) start = (loff_t)0xC0000; *size = 0x20000; /* cover C000:0 through E000:0 */ } else { - if (res->flags & IORESOURCE_ROM_COPY) { + if (res->flags & + (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) { *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); return (void __iomem *)(unsigned long) pci_resource_start(pdev, PCI_ROM_RESOURCE); @@ -165,7 +166,8 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size) if (!rom) return NULL; - if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW)) + if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW | + IORESOURCE_ROM_BIOS_COPY)) return rom; res->start = (unsigned long)kmalloc(*size, GFP_KERNEL); @@ -191,7 +193,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; - if (res->flags & IORESOURCE_ROM_COPY) + if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) return; iounmap(rom); @@ -215,6 +217,7 @@ void pci_remove_rom(struct pci_dev *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | + IORESOURCE_ROM_BIOS_COPY | IORESOURCE_ROM_COPY))) pci_disable_rom(pdev); } diff --git a/include/linux/ioport.h b/include/linux/ioport.h index d42c83399071..cf8696d4a138 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -89,6 +89,7 @@ struct resource_list { #define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ #define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */ #define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */ +#define IORESOURCE_ROM_BIOS_COPY (1<<3) /* ROM is BIOS copy, resource field overlaid */ /* PC/ISA/whatever - the normal PC address spaces: IO and memory */ extern struct resource ioport_resource; -- cgit v1.2.3-71-gd317 From bae94d02371c402408a4edfb95e71e88dbd3e973 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 22 Nov 2006 12:40:31 -0800 Subject: PCI: switch pci_{enable,disable}_device() to be nestable Changes the pci_{enable,disable}_device() functions to work in a nested basis, so that eg, three calls to enable_device() require three calls to disable_device(). The reason for this is to simplify PCI drivers for multi-interface/capability devices. These are devices that cram more than one interface in a single function. A relevant example of that is the Wireless [USB] Host Controller Interface (similar to EHCI) [see http://www.intel.com/technology/comms/wusb/whci.htm]. In these kind of devices, multiple interfaces are accessed through a single bar and IRQ line. For that, the drivers map only the smallest area of the bar to access their register banks and use shared IRQ handlers. However, because the order at which those drivers load cannot be known ahead of time, the sequence in which the calls to pci_enable_device() and pci_disable_device() cannot be predicted. Thus: 1. driverA starts pci_enable_device() 2. driverB starts pci_enable_device() 3. driverA shutdown pci_disable_device() 4. driverB shutdown pci_disable_device() between steps 3 and 4, driver B would loose access to it's device, even if it didn't intend to. By using this modification, the device won't be disabled until all the callers to enable() have called disable(). This is implemented by replacing 'struct pci_dev->is_enabled' from a bitfield to an atomic use count. Each caller to enable increments it, each caller to disable decrements it. When the count increments from 0 to 1, __pci_enable_device() is called to actually enable the device. When it drops to zero, pci_disable_device() actually does the disabling. We keep the backend __pci_enable_device() for pci_default_resume() to use and also change the sysfs method implementation, so that userspace enabling/disabling the device doesn't disable it one time too much. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 4 ++-- drivers/pci/pci-sysfs.c | 33 +++++++++++++++++++++------------ drivers/pci/pci.c | 40 +++++++++++++++++++++++++++++++++------- drivers/pci/pci.h | 1 + include/linux/pci.h | 3 ++- 5 files changed, 59 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 84ec9c8f6703..e5ae3a0c13bb 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -329,8 +329,8 @@ static int pci_default_resume(struct pci_dev *pci_dev) /* restore the PCI config space */ pci_restore_state(pci_dev); /* if the device was enabled before suspend, reenable */ - if (pci_dev->is_enabled) - retval = pci_enable_device(pci_dev); + if (atomic_read(&pci_dev->enable_cnt)) + retval = __pci_enable_device(pci_dev); /* if the device was busmaster before the suspend, make it busmaster again */ if (pci_dev->is_busmaster) pci_set_master(pci_dev); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index f952bfea48a6..7a94076752d0 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -42,7 +42,6 @@ pci_config_attr(subsystem_vendor, "0x%04x\n"); pci_config_attr(subsystem_device, "0x%04x\n"); pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); -pci_config_attr(is_enabled, "%u\n"); static ssize_t broken_parity_status_show(struct device *dev, struct device_attribute *attr, @@ -112,26 +111,36 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), (u8)(pci_dev->class)); } -static ssize_t -is_enabled_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + +static ssize_t is_enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { + ssize_t result = -EINVAL; struct pci_dev *pdev = to_pci_dev(dev); - int retval = 0; /* this can crash the machine when done on the "wrong" device */ if (!capable(CAP_SYS_ADMIN)) return count; - if (*buf == '0') - pci_disable_device(pdev); + if (*buf == '0') { + if (atomic_read(&pdev->enable_cnt) != 0) + pci_disable_device(pdev); + else + result = -EIO; + } else if (*buf == '1') + result = pci_enable_device(pdev); + + return result < 0 ? result : count; +} - if (*buf == '1') - retval = pci_enable_device(pdev); +static ssize_t is_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pdev; - if (retval) - return retval; - return count; + pdev = to_pci_dev (dev); + return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt)); } static ssize_t diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 427991741cf3..5a14b73cf3a1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -612,29 +612,50 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) } /** - * pci_enable_device - Initialize device before it's used by a driver. + * __pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * * Initialize device before it's used by a driver. Ask low-level code * to enable I/O and memory. Wake up the device if it was suspended. * Beware, this function can fail. + * + * Note this function is a backend and is not supposed to be called by + * normal code, use pci_enable_device() instead. */ int -pci_enable_device(struct pci_dev *dev) +__pci_enable_device(struct pci_dev *dev) { int err; - if (dev->is_enabled) - return 0; - err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); if (err) return err; pci_fixup_device(pci_fixup_enable, dev); - dev->is_enabled = 1; return 0; } +/** + * pci_enable_device - Initialize device before it's used by a driver. + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O and memory. Wake up the device if it was suspended. + * Beware, this function can fail. + * + * Note we don't actually enable the device many times if we call + * this function repeatedly (we just increment the count). + */ +int pci_enable_device(struct pci_dev *dev) +{ + int result; + if (atomic_add_return(1, &dev->enable_cnt) > 1) + return 0; /* already enabled */ + result = __pci_enable_device(dev); + if (result < 0) + atomic_dec(&dev->enable_cnt); + return result; +} + /** * pcibios_disable_device - disable arch specific PCI resources for device dev * @dev: the PCI device to disable @@ -651,12 +672,18 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {} * * Signal to the system that the PCI device is not in use by the system * anymore. This only involves disabling PCI bus-mastering, if active. + * + * Note we don't actually disable the device until all callers of + * pci_device_enable() have called pci_device_disable(). */ void pci_disable_device(struct pci_dev *dev) { u16 pci_command; + if (atomic_sub_return(1, &dev->enable_cnt) != 0) + return; + if (dev->msi_enabled) disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), PCI_CAP_ID_MSI); @@ -672,7 +699,6 @@ pci_disable_device(struct pci_dev *dev) dev->is_busmaster = 0; pcibios_disable_device(dev); - dev->is_enabled = 0; } /** diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6bf327db5c5e..398852f526a6 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,5 +1,6 @@ /* Functions internal to the PCI core code */ +extern int __must_check __pci_enable_device(struct pci_dev *); extern int pci_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); diff --git a/include/linux/pci.h b/include/linux/pci.h index 09be0f81b27b..01c707261f9c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -51,6 +51,7 @@ #include #include #include +#include #include /* File state for mmap()s on /proc/bus/pci/X/Y */ @@ -159,7 +160,6 @@ struct pci_dev { unsigned int transparent:1; /* Transparent PCI bridge */ unsigned int multifunction:1;/* Part of multi-function device */ /* keep track of device state */ - unsigned int is_enabled:1; /* pci_enable_device has been called */ unsigned int is_busmaster:1; /* device is busmaster */ unsigned int no_msi:1; /* device may not use msi */ unsigned int no_d1d2:1; /* only allow d0 or d3 */ @@ -167,6 +167,7 @@ struct pci_dev { unsigned int broken_parity_status:1; /* Device generates false positive parity */ unsigned int msi_enabled:1; unsigned int msix_enabled:1; + atomic_t enable_cnt; /* pci_enable_device has been called */ u32 saved_config_space[16]; /* config space saved at suspend time */ struct hlist_head saved_cap_space; -- cgit v1.2.3-71-gd317 From 3b59d52d8c7925e7a9a396f2e31a66eb060c6c37 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Wed, 22 Nov 2006 15:15:08 -0800 Subject: PCI: irq: irq and pci_ids patch for Intel ICH9 This updated patch adds the Intel ICH9 LPC and SMBus Controller DID's. Signed-off-by: Jason Gaston Signed-off-by: Greg Kroah-Hartman --- arch/i386/pci/irq.c | 6 ++++++ include/linux/pci_ids.h | 7 +++++++ 2 files changed, 13 insertions(+) (limited to 'include/linux') diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 69163998adeb..e65551cd8216 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -543,6 +543,12 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route case PCI_DEVICE_ID_INTEL_ICH8_2: case PCI_DEVICE_ID_INTEL_ICH8_3: case PCI_DEVICE_ID_INTEL_ICH8_4: + case PCI_DEVICE_ID_INTEL_ICH9_0: + case PCI_DEVICE_ID_INTEL_ICH9_1: + case PCI_DEVICE_ID_INTEL_ICH9_2: + case PCI_DEVICE_ID_INTEL_ICH9_3: + case PCI_DEVICE_ID_INTEL_ICH9_4: + case PCI_DEVICE_ID_INTEL_ICH9_5: r->name = "PIIX/ICH"; r->get = pirq_piix_get; r->set = pirq_piix_set; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index fa4e1d799782..e060a7637947 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2211,6 +2211,13 @@ #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 #define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2911 +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2915 +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 -- cgit v1.2.3-71-gd317 From 116af378201ef793424cd10508ccf18b06d8a021 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 25 Oct 2006 13:44:59 +1000 Subject: Driver core: add notification of bus events I finally did as you suggested and added the notifier to the struct bus_type itself. There are still problems to be expected is something attaches to a bus type where the code can hook in different struct device sub-classes (which is imho a big bogosity but I won't even try to argue that case now) but it will solve nicely a number of issues I've had so far. That also means that clients interested in registering for such notifications have to do it before devices are added and after bus types are registered. Fortunately, most bus types that matter for the various usage scenarios I have in mind are registerd at postcore_initcall time, which means I have a really nice spot at arch_initcall time to add my notifiers. There are 4 notifications provided. Device being added (before hooked to the bus) and removed (failure of previous case or after being unhooked from the bus), along with driver being bound to a device and about to be unbound. The usage I have for these are: - The 2 first ones are used to maintain a struct device_ext that is hooked to struct device.firmware_data. This structure contains for now a pointer to the Open Firmware node related to the device (if any), the NUMA node ID (for quick access to it) and the DMA operations pointers & iommu table instance for DMA to/from this device. For bus types I own (like IBM VIO or EBUS), I just maintain that structure directly from the bus code when creating the devices. But for bus types managed by generic code like PCI or platform (actually, of_platform which is a variation of platform linked to Open Firmware device-tree), I need this notifier. - The other two ones have a completely different usage scenario. I have cases where multiple devices and their drivers depend on each other. For example, the IBM EMAC network driver needs to attach to a MAL DMA engine which is a separate device, and a PHY interface which is also a separate device. They are all of_platform_device's (well, about to be with my upcoming patches) but there is no say in what precise order the core will "probe" them and instanciate the various modules. The solution I found for that is to have the drivers for emac to use multithread_probe, and wait for a driver to be bound to the target MAL and PHY control devices (the device-tree contains reference to the MAL and PHY interface nodes, which I can then match to of_platform_devices). Right now, I've been polling, but with that notifier, I can more cleanly wait (with a timeout of course). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 14 ++++++++++++++ drivers/base/core.c | 12 ++++++++++++ drivers/base/dd.c | 10 ++++++++++ include/linux/device.h | 25 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 7d8a7ce73fb3..ed3e8a2be64a 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -724,6 +724,8 @@ int bus_register(struct bus_type * bus) { int retval; + BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); + retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name); if (retval) goto out; @@ -782,6 +784,18 @@ void bus_unregister(struct bus_type * bus) subsystem_unregister(&bus->subsys); } +int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&bus->bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(bus_register_notifier); + +int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&bus->bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(bus_unregister_notifier); + int __init buses_init(void) { return subsystem_register(&bus_subsys); diff --git a/drivers/base/core.c b/drivers/base/core.c index 002fde46d38d..d4f35d8902a2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -428,6 +429,11 @@ int device_add(struct device *dev) if (platform_notify) platform_notify(dev); + /* notify clients of device entry (new way) */ + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_ADD_DEVICE, dev); + dev->uevent_attr.attr.name = "uevent"; dev->uevent_attr.attr.mode = S_IWUSR; if (dev->driver) @@ -504,6 +510,9 @@ int device_add(struct device *dev) BusError: device_pm_remove(dev); PMError: + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); device_remove_groups(dev); GroupError: device_remove_attrs(dev); @@ -622,6 +631,9 @@ void device_del(struct device * dev) */ if (platform_notify_remove) platform_notify_remove(dev); + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); bus_remove_device(dev); device_pm_remove(dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c5d6bb4290ad..9c88b1e34bc3 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -52,6 +52,11 @@ int device_bind_driver(struct device *dev) pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id, dev->driver->name); + + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_BOUND_DRIVER, dev); + klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj)); @@ -288,6 +293,11 @@ static void __device_release_driver(struct device * dev) sysfs_remove_link(&dev->kobj, "driver"); klist_remove(&dev->knode_driver); + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_UNBIND_DRIVER, + dev); + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) diff --git a/include/linux/device.h b/include/linux/device.h index 9d4f6a963936..b00e02711393 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -42,6 +42,8 @@ struct bus_type { struct klist klist_devices; struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; @@ -75,6 +77,29 @@ int __must_check bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *)); +/* + * Bus notifiers: Get notified of addition/removal of devices + * and binding/unbinding of drivers to devices. + * In the long run, it should be a replacement for the platform + * notify hooks. + */ +struct notifier_block; + +extern int bus_register_notifier(struct bus_type *bus, + struct notifier_block *nb); +extern int bus_unregister_notifier(struct bus_type *bus, + struct notifier_block *nb); + +/* All 4 notifers below get called with the target struct device * + * as an argument. Note that those functions are likely to be called + * with the device semaphore held in the core, so be careful. + */ +#define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */ +#define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device removed */ +#define BUS_NOTIFY_BOUND_DRIVER 0x00000003 /* driver bound to device */ +#define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be + unbound */ + /* driverfs interface for exporting bus attributes */ struct bus_attribute { -- cgit v1.2.3-71-gd317 From f0ee61a6cecd100301a60d99feb187776533b2a2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 23 Oct 2006 10:40:54 -0700 Subject: Driver Core: Move virtual_device_parent() to core.c It doesn't need to be global or in device.h Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 17 ----------------- drivers/base/core.c | 17 +++++++++++++++++ include/linux/device.h | 2 -- 3 files changed, 17 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/class.c b/drivers/base/class.c index 0ff267a248db..2e705f6abb4c 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -893,23 +893,6 @@ void class_interface_unregister(struct class_interface *class_intf) class_put(parent); } -int virtual_device_parent(struct device *dev) -{ - if (!dev->class) - return -ENODEV; - - if (!dev->class->virtual_dir) { - static struct kobject *virtual_dir = NULL; - - if (!virtual_dir) - virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); - dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); - } - - dev->kobj.parent = dev->class->virtual_dir; - return 0; -} - int __init classes_init(void) { int retval; diff --git a/drivers/base/core.c b/drivers/base/core.c index d4f35d8902a2..dbcd40b987d2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -384,6 +384,23 @@ void device_initialize(struct device *dev) device_init_wakeup(dev, 0); } +static int virtual_device_parent(struct device *dev) +{ + if (!dev->class) + return -ENODEV; + + if (!dev->class->virtual_dir) { + static struct kobject *virtual_dir = NULL; + + if (!virtual_dir) + virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); + dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); + } + + dev->kobj.parent = dev->class->virtual_dir; + return 0; +} + /** * device_add - add device to device hierarchy. * @dev: device. diff --git a/include/linux/device.h b/include/linux/device.h index b00e02711393..00b29e0c5ce0 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -440,8 +440,6 @@ extern struct device *device_create(struct class *cls, struct device *parent, __attribute__((format(printf,4,5))); extern void device_destroy(struct class *cls, dev_t devt); -extern int virtual_device_parent(struct device *dev); - /* * Platform "fixup" functions - allow the platform to have their say * about devices and actions that the general device layer doesn't -- cgit v1.2.3-71-gd317 From 94fbcded4ea0dc14cbfb222a5c68372f150d1476 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Jul 2006 16:16:04 -0700 Subject: Driver core: change misc class_devices to be real devices This also ment that some of the misc drivers had to also be fixed up as they were assuming the device was a class_device. Signed-off-by: Greg Kroah-Hartman --- drivers/char/hw_random/core.c | 38 +++++++++++++++++++------------------- drivers/char/misc.c | 13 ++++--------- drivers/char/tpm/tpm.c | 2 +- drivers/input/serio/serio_raw.c | 2 +- include/linux/miscdevice.h | 5 ++--- 5 files changed, 27 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 154a81d328c1..ebace201bec6 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -162,7 +162,8 @@ static struct miscdevice rng_miscdev = { }; -static ssize_t hwrng_attr_current_store(struct class_device *class, +static ssize_t hwrng_attr_current_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) { int err; @@ -192,7 +193,8 @@ static ssize_t hwrng_attr_current_store(struct class_device *class, return err ? : len; } -static ssize_t hwrng_attr_current_show(struct class_device *class, +static ssize_t hwrng_attr_current_show(struct device *dev, + struct device_attribute *attr, char *buf) { int err; @@ -210,7 +212,8 @@ static ssize_t hwrng_attr_current_show(struct class_device *class, return ret; } -static ssize_t hwrng_attr_available_show(struct class_device *class, +static ssize_t hwrng_attr_available_show(struct device *dev, + struct device_attribute *attr, char *buf) { int err; @@ -234,20 +237,18 @@ static ssize_t hwrng_attr_available_show(struct class_device *class, return ret; } -static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, - hwrng_attr_current_show, - hwrng_attr_current_store); -static CLASS_DEVICE_ATTR(rng_available, S_IRUGO, - hwrng_attr_available_show, - NULL); +static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, + hwrng_attr_current_show, + hwrng_attr_current_store); +static DEVICE_ATTR(rng_available, S_IRUGO, + hwrng_attr_available_show, + NULL); static void unregister_miscdev(void) { - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_available); - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_current); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); misc_deregister(&rng_miscdev); } @@ -258,20 +259,19 @@ static int register_miscdev(void) err = misc_register(&rng_miscdev); if (err) goto out; - err = class_device_create_file(rng_miscdev.class, - &class_device_attr_rng_current); + err = device_create_file(rng_miscdev.this_device, + &dev_attr_rng_current); if (err) goto err_misc_dereg; - err = class_device_create_file(rng_miscdev.class, - &class_device_attr_rng_available); + err = device_create_file(rng_miscdev.this_device, + &dev_attr_rng_available); if (err) goto err_remove_current; out: return err; err_remove_current: - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_current); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); err_misc_dereg: misc_deregister(&rng_miscdev); goto out; diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 62ebe09656e3..7a484fc7cb9e 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -169,11 +169,6 @@ fail: return err; } -/* - * TODO for 2.7: - * - add a struct kref to struct miscdevice and make all usages of - * them dynamic. - */ static struct class *misc_class; static const struct file_operations misc_fops = { @@ -228,10 +223,10 @@ int misc_register(struct miscdevice * misc) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); dev = MKDEV(MISC_MAJOR, misc->minor); - misc->class = class_device_create(misc_class, NULL, dev, misc->dev, + misc->this_device = device_create(misc_class, misc->parent, dev, "%s", misc->name); - if (IS_ERR(misc->class)) { - err = PTR_ERR(misc->class); + if (IS_ERR(misc->this_device)) { + err = PTR_ERR(misc->this_device); goto out; } @@ -264,7 +259,7 @@ int misc_deregister(struct miscdevice * misc) down(&misc_sem); list_del(&misc->list); - class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); + device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6ad2d3bb945c..6e1329d404d2 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1130,7 +1130,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor.miscdev.name = devname; - chip->vendor.miscdev.dev = dev; + chip->vendor.miscdev.parent = dev; chip->dev = get_device(dev); if (misc_register(&chip->vendor.miscdev)) { diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index ba2a2035d648..7c8d0399ae82 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -297,7 +297,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) serio_raw->dev.minor = PSMOUSE_MINOR; serio_raw->dev.name = serio_raw->name; - serio_raw->dev.dev = &serio->dev; + serio_raw->dev.parent = &serio->dev; serio_raw->dev.fops = &serio_raw_fops; err = misc_register(&serio_raw->dev); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index b03cfb91e228..326da7d500c7 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -31,15 +31,14 @@ #define HPET_MINOR 228 struct device; -struct class_device; struct miscdevice { int minor; const char *name; const struct file_operations *fops; struct list_head list; - struct device *dev; - struct class_device *class; + struct device *parent; + struct device *this_device; }; extern int misc_register(struct miscdevice * misc); -- cgit v1.2.3-71-gd317 From 01107d343076c34b9e1ce5d073292bd7f3097fda Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Aug 2006 22:19:37 -0700 Subject: Driver core: convert tty core to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Also fixes up the isdn drivers that were putting something in the class device's directory. Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_io.c | 19 ++++++++++--------- drivers/isdn/gigaset/common.c | 2 +- drivers/isdn/gigaset/gigaset.h | 2 +- drivers/isdn/gigaset/interface.c | 10 +++++----- drivers/isdn/gigaset/proc.c | 19 ++++++++++--------- include/linux/tty.h | 5 ++--- 6 files changed, 29 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e90ea39c7c4b..50dc49205a23 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3612,7 +3612,8 @@ static struct class *tty_class; * This field is optional, if there is no known struct device * for this tty device it can be set to NULL safely. * - * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). + * Returns a pointer to the struct device for this tty device + * (or ERR_PTR(-EFOO) on error). * * This call is required to be made to register an individual tty device * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If @@ -3622,8 +3623,8 @@ static struct class *tty_class; * Locking: ?? */ -struct class_device *tty_register_device(struct tty_driver *driver, - unsigned index, struct device *device) +struct device *tty_register_device(struct tty_driver *driver, unsigned index, + struct device *device) { char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; @@ -3639,7 +3640,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, else tty_line_name(driver, index, name); - return class_device_create(tty_class, NULL, dev, device, "%s", name); + return device_create(tty_class, device, dev, name); } /** @@ -3655,7 +3656,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, void tty_unregister_device(struct tty_driver *driver, unsigned index) { - class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); + device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -3895,20 +3896,20 @@ static int __init tty_init(void) if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), "ptmx"); #endif #ifdef CONFIG_VT @@ -3916,7 +3917,7 @@ static int __init tty_init(void) if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), "tty0"); vty_init(); #endif diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 5800beeebb85..defd5743dba6 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -702,7 +702,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, cs->open_count = 0; cs->dev = NULL; cs->tty = NULL; - cs->class = NULL; + cs->tty_dev = NULL; cs->cidmode = cidmode != 0; //if(onechannel) { //FIXME diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 884bd72c1bf4..06298cc52bf5 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -444,7 +444,7 @@ struct cardstate { struct gigaset_driver *driver; unsigned minor_index; struct device *dev; - struct class_device *class; + struct device *tty_dev; const struct gigaset_ops *ops; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 596f3aebe2f7..7edea015867e 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -625,13 +625,13 @@ void gigaset_if_init(struct cardstate *cs) return; tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs); - cs->class = tty_register_device(drv->tty, cs->minor_index, NULL); + cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL); - if (!IS_ERR(cs->class)) - class_set_devdata(cs->class, cs); + if (!IS_ERR(cs->tty_dev)) + dev_set_drvdata(cs->tty_dev, cs); else { warn("could not register device to the tty subsystem"); - cs->class = NULL; + cs->tty_dev = NULL; } } @@ -645,7 +645,7 @@ void gigaset_if_free(struct cardstate *cs) tasklet_disable(&cs->if_wake_tasklet); tasklet_kill(&cs->if_wake_tasklet); - cs->class = NULL; + cs->tty_dev = NULL; tty_unregister_device(drv->tty, cs->minor_index); } diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index 9ad840e95dbe..e767afa55abf 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c @@ -16,11 +16,12 @@ #include "gigaset.h" #include -static ssize_t show_cidmode(struct class_device *class, char *buf) +static ssize_t show_cidmode(struct device *dev, + struct device_attribute *attr, char *buf) { int ret; unsigned long flags; - struct cardstate *cs = class_get_devdata(class); + struct cardstate *cs = dev_get_drvdata(dev); spin_lock_irqsave(&cs->lock, flags); ret = sprintf(buf, "%u\n", cs->cidmode); @@ -29,10 +30,10 @@ static ssize_t show_cidmode(struct class_device *class, char *buf) return ret; } -static ssize_t set_cidmode(struct class_device *class, +static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct cardstate *cs = class_get_devdata(class); + struct cardstate *cs = dev_get_drvdata(dev); long int value; char *end; @@ -64,25 +65,25 @@ static ssize_t set_cidmode(struct class_device *class, return count; } -static CLASS_DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); +static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); /* free sysfs for device */ void gigaset_free_dev_sysfs(struct cardstate *cs) { - if (!cs->class) + if (!cs->tty_dev) return; gig_dbg(DEBUG_INIT, "removing sysfs entries"); - class_device_remove_file(cs->class, &class_device_attr_cidmode); + device_remove_file(cs->tty_dev, &dev_attr_cidmode); } /* initialize sysfs for device */ void gigaset_init_dev_sysfs(struct cardstate *cs) { - if (!cs->class) + if (!cs->tty_dev) return; gig_dbg(DEBUG_INIT, "setting up sysfs"); - if (class_device_create_file(cs->class, &class_device_attr_cidmode)) + if (device_create_file(cs->tty_dev, &dev_attr_cidmode)) dev_err(cs->dev, "could not create sysfs attribute\n"); } diff --git a/include/linux/tty.h b/include/linux/tty.h index 44091c0db0b4..65321f911c1e 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -276,9 +276,8 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); -extern struct class_device *tty_register_device(struct tty_driver *driver, - unsigned index, - struct device *dev); +extern struct device *tty_register_device(struct tty_driver *driver, + unsigned index, struct device *dev); extern void tty_unregister_device(struct tty_driver *driver, unsigned index); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); -- cgit v1.2.3-71-gd317 From fcaf71fd51f9cfc504455d3e19ec242e4b2073ed Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 12 Sep 2006 17:00:10 +0200 Subject: Driver core: convert mmc code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/mmc_queue.c | 4 ++-- drivers/mmc/mmc_sysfs.c | 20 ++++++++++---------- drivers/mmc/wbsd.c | 6 +++--- include/linux/mmc/host.h | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 4ccdd82b680f..61a1de85cb23 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c @@ -130,8 +130,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock u64 limit = BLK_BOUNCE_HIGH; int ret; - if (host->dev->dma_mask && *host->dev->dma_mask) - limit = *host->dev->dma_mask; + if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) + limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index 10cc9734eaa0..ac5329636045 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host) memset(card, 0, sizeof(struct mmc_card)); card->host = host; device_initialize(&card->dev); - card->dev.parent = card->host->dev; + card->dev.parent = mmc_dev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; } @@ -242,7 +242,7 @@ void mmc_remove_card(struct mmc_card *card) } -static void mmc_host_classdev_release(struct class_device *dev) +static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); kfree(host); @@ -250,7 +250,7 @@ static void mmc_host_classdev_release(struct class_device *dev) static struct class mmc_host_class = { .name = "mmc_host", - .release = mmc_host_classdev_release, + .dev_release = mmc_host_classdev_release, }; static DEFINE_IDR(mmc_host_idr); @@ -267,10 +267,10 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev) if (host) { memset(host, 0, sizeof(struct mmc_host) + extra); - host->dev = dev; - host->class_dev.dev = host->dev; + host->parent = dev; + host->class_dev.parent = dev; host->class_dev.class = &mmc_host_class; - class_device_initialize(&host->class_dev); + device_initialize(&host->class_dev); } return host; @@ -292,10 +292,10 @@ int mmc_add_host_sysfs(struct mmc_host *host) if (err) return err; - snprintf(host->class_dev.class_id, BUS_ID_SIZE, + snprintf(host->class_dev.bus_id, BUS_ID_SIZE, "mmc%d", host->index); - return class_device_add(&host->class_dev); + return device_add(&host->class_dev); } /* @@ -303,7 +303,7 @@ int mmc_add_host_sysfs(struct mmc_host *host) */ void mmc_remove_host_sysfs(struct mmc_host *host) { - class_device_del(&host->class_dev); + device_del(&host->class_dev); spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); @@ -315,7 +315,7 @@ void mmc_remove_host_sysfs(struct mmc_host *host) */ void mmc_free_host_sysfs(struct mmc_host *host) { - class_device_put(&host->class_dev); + put_device(&host->class_dev); } static struct workqueue_struct *workqueue; diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index ced309b37a8f..682e62b0b09d 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1488,7 +1488,7 @@ static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma) /* * Translate the address to a physical address. */ - host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer, + host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); /* @@ -1512,7 +1512,7 @@ kfree: */ BUG_ON(1); - dma_unmap_single(host->mmc->dev, host->dma_addr, + dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); host->dma_addr = (dma_addr_t)NULL; @@ -1530,7 +1530,7 @@ err: static void __devexit wbsd_release_dma(struct wbsd_host *host) { if (host->dma_addr) { - dma_unmap_single(host->mmc->dev, host->dma_addr, + dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); } kfree(host->dma_buffer); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 587264a58d56..528e7d3fecb1 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -74,8 +74,8 @@ struct mmc_card; struct device; struct mmc_host { - struct device *dev; - struct class_device class_dev; + struct device *parent; + struct device class_dev; int index; const struct mmc_host_ops *ops; unsigned int f_min; @@ -125,8 +125,8 @@ static inline void *mmc_priv(struct mmc_host *host) return (void *)host->private; } -#define mmc_dev(x) ((x)->dev) -#define mmc_hostname(x) ((x)->class_dev.class_id) +#define mmc_dev(x) ((x)->parent) +#define mmc_hostname(x) ((x)->class_dev.bus_id) extern int mmc_suspend_host(struct mmc_host *, pm_message_t); extern int mmc_resume_host(struct mmc_host *); -- cgit v1.2.3-71-gd317 From 78cde0887930f5d11a56fc51b013f2672fba0e6f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 14 Sep 2006 07:30:59 -0700 Subject: Driver core: convert fb code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbmem.c | 16 ++--- drivers/video/fbsysfs.c | 163 +++++++++++++++++++++++++++--------------------- include/linux/fb.h | 8 +-- 3 files changed, 103 insertions(+), 84 deletions(-) (limited to 'include/linux') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 93ffcdd95f50..e973a87fbb01 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1296,14 +1296,14 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; - fb_info->class_device = class_device_create(fb_class, NULL, MKDEV(FB_MAJOR, i), - fb_info->device, "fb%d", i); - if (IS_ERR(fb_info->class_device)) { + fb_info->dev = device_create(fb_class, fb_info->device, + MKDEV(FB_MAJOR, i), "fb%d", i); + if (IS_ERR(fb_info->dev)) { /* Not fatal */ - printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device)); - fb_info->class_device = NULL; + printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); + fb_info->dev = NULL; } else - fb_init_class_device(fb_info); + fb_init_device(fb_info); if (fb_info->pixmap.addr == NULL) { fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); @@ -1356,8 +1356,8 @@ unregister_framebuffer(struct fb_info *fb_info) fb_destroy_modelist(&fb_info->modelist); registered_fb[i]=NULL; num_registered_fb--; - fb_cleanup_class_device(fb_info); - class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); + fb_cleanup_device(fb_info); + device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); return 0; diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index d3a50417ed9a..323bdf6fc7d5 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -73,7 +73,7 @@ EXPORT_SYMBOL(framebuffer_alloc); * * @info: frame buffer info structure * - * Drop the reference count of the class_device embedded in the + * Drop the reference count of the device embedded in the * framebuffer info structure. * */ @@ -120,10 +120,10 @@ static int mode_string(char *buf, unsigned int offset, m, mode->xres, mode->yres, v, mode->refresh); } -static ssize_t store_mode(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_mode(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); char mstr[100]; struct fb_var_screeninfo var; struct fb_modelist *modelist; @@ -151,9 +151,10 @@ static ssize_t store_mode(struct class_device *class_device, const char * buf, return -EINVAL; } -static ssize_t show_mode(struct class_device *class_device, char *buf) +static ssize_t show_mode(struct device *device, struct device_attribute *attr, + char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); if (!fb_info->mode) return 0; @@ -161,10 +162,11 @@ static ssize_t show_mode(struct class_device *class_device, char *buf) return mode_string(buf, 0, fb_info->mode); } -static ssize_t store_modes(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_modes(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); LIST_HEAD(old_list); int i = count / sizeof(struct fb_videomode); @@ -186,9 +188,10 @@ static ssize_t store_modes(struct class_device *class_device, const char * buf, return 0; } -static ssize_t show_modes(struct class_device *class_device, char *buf) +static ssize_t show_modes(struct device *device, struct device_attribute *attr, + char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); unsigned int i; struct list_head *pos; struct fb_modelist *modelist; @@ -203,10 +206,10 @@ static ssize_t show_modes(struct class_device *class_device, char *buf) return i; } -static ssize_t store_bpp(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_bpp(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char ** last = NULL; int err; @@ -218,16 +221,18 @@ static ssize_t store_bpp(struct class_device *class_device, const char * buf, return count; } -static ssize_t show_bpp(struct class_device *class_device, char *buf) +static ssize_t show_bpp(struct device *device, struct device_attribute *attr, + char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel); } -static ssize_t store_rotate(struct class_device *class_device, const char *buf, - size_t count) +static ssize_t store_rotate(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char **last = NULL; int err; @@ -242,17 +247,19 @@ static ssize_t store_rotate(struct class_device *class_device, const char *buf, } -static ssize_t show_rotate(struct class_device *class_device, char *buf) +static ssize_t show_rotate(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); } -static ssize_t store_virtual(struct class_device *class_device, - const char * buf, size_t count) +static ssize_t store_virtual(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char *last = NULL; int err; @@ -269,23 +276,26 @@ static ssize_t store_virtual(struct class_device *class_device, return count; } -static ssize_t show_virtual(struct class_device *class_device, char *buf) +static ssize_t show_virtual(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual, fb_info->var.yres_virtual); } -static ssize_t show_stride(struct class_device *class_device, char *buf) +static ssize_t show_stride(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length); } -static ssize_t store_blank(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_blank(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); char *last = NULL; int err; @@ -299,42 +309,48 @@ static ssize_t store_blank(struct class_device *class_device, const char * buf, return count; } -static ssize_t show_blank(struct class_device *class_device, char *buf) +static ssize_t show_blank(struct device *device, + struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t store_console(struct class_device *class_device, - const char * buf, size_t count) +static ssize_t store_console(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t show_console(struct class_device *class_device, char *buf) +static ssize_t show_console(struct device *device, + struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t store_cursor(struct class_device *class_device, - const char * buf, size_t count) +static ssize_t store_cursor(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t show_cursor(struct class_device *class_device, char *buf) +static ssize_t show_cursor(struct device *device, + struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = class_get_devdata(class_device); +// struct fb_info *fb_info = dev_get_drvdata(device); return 0; } -static ssize_t store_pan(struct class_device *class_device, const char * buf, - size_t count) +static ssize_t store_pan(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); struct fb_var_screeninfo var; char *last = NULL; int err; @@ -355,24 +371,27 @@ static ssize_t store_pan(struct class_device *class_device, const char * buf, return count; } -static ssize_t show_pan(struct class_device *class_device, char *buf) +static ssize_t show_pan(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset, fb_info->var.xoffset); } -static ssize_t show_name(struct class_device *class_device, char *buf) +static ssize_t show_name(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%s\n", fb_info->fix.id); } -static ssize_t store_fbstate(struct class_device *class_device, - const char *buf, size_t count) +static ssize_t store_fbstate(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); u32 state; char *last = NULL; @@ -385,17 +404,19 @@ static ssize_t store_fbstate(struct class_device *class_device, return count; } -static ssize_t show_fbstate(struct class_device *class_device, char *buf) +static ssize_t show_fbstate(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state); } #ifdef CONFIG_FB_BACKLIGHT -static ssize_t store_bl_curve(struct class_device *class_device, - const char *buf, size_t count) +static ssize_t store_bl_curve(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); u8 tmp_curve[FB_BACKLIGHT_LEVELS]; unsigned int i; @@ -432,9 +453,10 @@ static ssize_t store_bl_curve(struct class_device *class_device, return count; } -static ssize_t show_bl_curve(struct class_device *class_device, char *buf) +static ssize_t show_bl_curve(struct device *device, + struct device_attribute *attr, char *buf) { - struct fb_info *fb_info = class_get_devdata(class_device); + struct fb_info *fb_info = dev_get_drvdata(device); ssize_t len = 0; unsigned int i; @@ -465,7 +487,7 @@ static ssize_t show_bl_curve(struct class_device *class_device, char *buf) /* When cmap is added back in it should be a binary attribute * not a text one. Consideration should also be given to converting * fbdev to use configfs instead of sysfs */ -static struct class_device_attribute class_device_attrs[] = { +static struct device_attribute device_attrs[] = { __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp), __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank), __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console), @@ -483,17 +505,16 @@ static struct class_device_attribute class_device_attrs[] = { #endif }; -int fb_init_class_device(struct fb_info *fb_info) +int fb_init_device(struct fb_info *fb_info) { int i, error = 0; - class_set_devdata(fb_info->class_device, fb_info); + dev_set_drvdata(fb_info->dev, fb_info); fb_info->class_flag |= FB_SYSFS_FLAG_ATTR; - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { - error = class_device_create_file(fb_info->class_device, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { + error = device_create_file(fb_info->dev, &device_attrs[i]); if (error) break; @@ -501,22 +522,20 @@ int fb_init_class_device(struct fb_info *fb_info) if (error) { while (--i >= 0) - class_device_remove_file(fb_info->class_device, - &class_device_attrs[i]); + device_remove_file(fb_info->dev, &device_attrs[i]); fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; } return 0; } -void fb_cleanup_class_device(struct fb_info *fb_info) +void fb_cleanup_device(struct fb_info *fb_info) { unsigned int i; if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) { - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_remove_file(fb_info->class_device, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) + device_remove_file(fb_info->dev, &device_attrs[i]); fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; } diff --git a/include/linux/fb.h b/include/linux/fb.h index 3e69241e6a81..fa23e0671bb3 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -774,8 +774,8 @@ struct fb_info { #endif struct fb_ops *fbops; - struct device *device; - struct class_device *class_device; /* sysfs per device attrs */ + struct device *device; /* This is the parent */ + struct device *dev; /* This is this fb device */ int class_flag; /* private sysfs flags */ #ifdef CONFIG_FB_TILEBLITTING struct fb_tile_ops *tileops; /* Tile Blitting */ @@ -910,8 +910,8 @@ static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, /* drivers/video/fbsysfs.c */ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev); extern void framebuffer_release(struct fb_info *info); -extern int fb_init_class_device(struct fb_info *fb_info); -extern void fb_cleanup_class_device(struct fb_info *head); +extern int fb_init_device(struct fb_info *fb_info); +extern void fb_cleanup_device(struct fb_info *head); extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max); /* drivers/video/fbmon.c */ -- cgit v1.2.3-71-gd317 From c6dbaef22a2f78700e242915a13218dd780c89ff Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 11 Nov 2006 17:18:39 +1100 Subject: Driver core: add dev_archdata to struct device Add arch specific dev_archdata to struct device Adds an arch specific struct dev_arch to struct device. This enables architecture to add specific fields to every device in the system, like DMA operation pointers, NUMA node ID, firmware specific data, etc... Signed-off-by: Benjamin Herrenschmidt Acked-by: Andi Kleen Acked-By: David Howells Signed-off-by: Greg Kroah-Hartman --- include/asm-alpha/device.h | 7 +++++++ include/asm-arm/device.h | 7 +++++++ include/asm-arm26/device.h | 7 +++++++ include/asm-avr32/device.h | 7 +++++++ include/asm-cris/device.h | 7 +++++++ include/asm-frv/device.h | 7 +++++++ include/asm-generic/device.h | 12 ++++++++++++ include/asm-h8300/device.h | 7 +++++++ include/asm-i386/device.h | 7 +++++++ include/asm-ia64/device.h | 7 +++++++ include/asm-m32r/device.h | 7 +++++++ include/asm-m68k/device.h | 7 +++++++ include/asm-m68knommu/device.h | 7 +++++++ include/asm-mips/device.h | 7 +++++++ include/asm-parisc/device.h | 7 +++++++ include/asm-powerpc/device.h | 7 +++++++ include/asm-ppc/device.h | 7 +++++++ include/asm-s390/device.h | 7 +++++++ include/asm-sh/device.h | 7 +++++++ include/asm-sh64/device.h | 7 +++++++ include/asm-sparc/device.h | 7 +++++++ include/asm-sparc64/device.h | 7 +++++++ include/asm-um/device.h | 7 +++++++ include/asm-v850/device.h | 7 +++++++ include/asm-x86_64/device.h | 7 +++++++ include/asm-xtensa/device.h | 7 +++++++ include/linux/device.h | 3 +++ 27 files changed, 190 insertions(+) create mode 100644 include/asm-alpha/device.h create mode 100644 include/asm-arm/device.h create mode 100644 include/asm-arm26/device.h create mode 100644 include/asm-avr32/device.h create mode 100644 include/asm-cris/device.h create mode 100644 include/asm-frv/device.h create mode 100644 include/asm-generic/device.h create mode 100644 include/asm-h8300/device.h create mode 100644 include/asm-i386/device.h create mode 100644 include/asm-ia64/device.h create mode 100644 include/asm-m32r/device.h create mode 100644 include/asm-m68k/device.h create mode 100644 include/asm-m68knommu/device.h create mode 100644 include/asm-mips/device.h create mode 100644 include/asm-parisc/device.h create mode 100644 include/asm-powerpc/device.h create mode 100644 include/asm-ppc/device.h create mode 100644 include/asm-s390/device.h create mode 100644 include/asm-sh/device.h create mode 100644 include/asm-sh64/device.h create mode 100644 include/asm-sparc/device.h create mode 100644 include/asm-sparc64/device.h create mode 100644 include/asm-um/device.h create mode 100644 include/asm-v850/device.h create mode 100644 include/asm-x86_64/device.h create mode 100644 include/asm-xtensa/device.h (limited to 'include/linux') diff --git a/include/asm-alpha/device.h b/include/asm-alpha/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-alpha/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-arm/device.h b/include/asm-arm/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-arm/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-arm26/device.h b/include/asm-arm26/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-arm26/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-avr32/device.h b/include/asm-avr32/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-avr32/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-cris/device.h b/include/asm-cris/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-cris/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-frv/device.h b/include/asm-frv/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-frv/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-generic/device.h b/include/asm-generic/device.h new file mode 100644 index 000000000000..c17c9600f220 --- /dev/null +++ b/include/asm-generic/device.h @@ -0,0 +1,12 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#ifndef _ASM_GENERIC_DEVICE_H +#define _ASM_GENERIC_DEVICE_H + +struct dev_archdata { +}; + +#endif /* _ASM_GENERIC_DEVICE_H */ diff --git a/include/asm-h8300/device.h b/include/asm-h8300/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-h8300/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-i386/device.h b/include/asm-i386/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-i386/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-ia64/device.h b/include/asm-ia64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-ia64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-m32r/device.h b/include/asm-m32r/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-m32r/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-m68k/device.h b/include/asm-m68k/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-m68k/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-m68knommu/device.h b/include/asm-m68knommu/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-m68knommu/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-mips/device.h b/include/asm-mips/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-mips/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-parisc/device.h b/include/asm-parisc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-parisc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-powerpc/device.h b/include/asm-powerpc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-powerpc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-ppc/device.h b/include/asm-ppc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-ppc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-s390/device.h b/include/asm-s390/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-s390/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sh/device.h b/include/asm-sh/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sh/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sh64/device.h b/include/asm-sh64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sh64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sparc/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-sparc64/device.h b/include/asm-sparc64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-sparc64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-um/device.h b/include/asm-um/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-um/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-v850/device.h b/include/asm-v850/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-v850/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-x86_64/device.h b/include/asm-x86_64/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-x86_64/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/asm-xtensa/device.h b/include/asm-xtensa/device.h new file mode 100644 index 000000000000..d8f9872b0e2d --- /dev/null +++ b/include/asm-xtensa/device.h @@ -0,0 +1,7 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#include + diff --git a/include/linux/device.h b/include/linux/device.h index 00b29e0c5ce0..5b54d756cd54 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -21,6 +21,7 @@ #include #include #include +#include #define DEVICE_NAME_SIZE 50 #define DEVICE_NAME_HALF __stringify(20) /* Less than half to accommodate slop */ @@ -383,6 +384,8 @@ struct device { struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ + /* arch specific additions */ + struct dev_archdata archdata; /* class_device migration path */ struct list_head node; -- cgit v1.2.3-71-gd317 From 465ae641e4a3e5028aa9c85d3843259aa28a22ce Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 11 Nov 2006 17:18:42 +1100 Subject: ACPI: Change ACPI to use dev_archdata instead of firmware_data Change ACPI to use dev_archdata instead of firmware_data This patch changes ACPI to use the new dev_archdata on i386, x86_64 and ia64 (is there any other arch using ACPI ?) to store it's acpi_handle. It also removes the firmware_data field from struct device as this was the only user. Only build-tested on x86 Signed-off-by: Benjamin Herrenschmidt Cc: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/glue.c | 20 +++++++++++--------- include/acpi/acpi_bus.h | 2 +- include/asm-i386/device.h | 10 +++++++++- include/asm-ia64/device.h | 10 +++++++++- include/asm-x86_64/device.h | 10 +++++++++- include/linux/device.h | 2 -- 6 files changed, 39 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 10f160dc75b1..a2f46d587d55 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -267,9 +267,9 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) { acpi_status status; - if (dev->firmware_data) { + if (dev->archdata.acpi_handle) { printk(KERN_WARNING PREFIX - "Drivers changed 'firmware_data' for %s\n", dev->bus_id); + "Drivers changed 'acpi_handle' for %s\n", dev->bus_id); return -EINVAL; } get_device(dev); @@ -278,25 +278,26 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) put_device(dev); return -EINVAL; } - dev->firmware_data = handle; + dev->archdata.acpi_handle = handle; return 0; } static int acpi_unbind_one(struct device *dev) { - if (!dev->firmware_data) + if (!dev->archdata.acpi_handle) return 0; - if (dev == acpi_get_physical_device(dev->firmware_data)) { + if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { /* acpi_get_physical_device increase refcnt by one */ put_device(dev); - acpi_detach_data(dev->firmware_data, acpi_glue_data_handler); - dev->firmware_data = NULL; + acpi_detach_data(dev->archdata.acpi_handle, + acpi_glue_data_handler); + dev->archdata.acpi_handle = NULL; /* acpi_bind_one increase refcnt by one */ put_device(dev); } else { printk(KERN_ERR PREFIX - "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id); + "Oops, 'acpi_handle' corrupt for %s\n", dev->bus_id); } return 0; } @@ -328,7 +329,8 @@ static int acpi_platform_notify(struct device *dev) if (!ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(dev->archdata.acpi_handle, + ACPI_FULL_PATHNAME, &buffer); DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); kfree(buffer.pointer); } else diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f338e40bd544..fdd10953b2b6 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -357,7 +357,7 @@ struct device *acpi_get_physical_device(acpi_handle); /* helper */ acpi_handle acpi_get_child(acpi_handle, acpi_integer); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); -#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->firmware_data)) +#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) #endif /* CONFIG_ACPI */ diff --git a/include/asm-i386/device.h b/include/asm-i386/device.h index d8f9872b0e2d..849604c70e6b 100644 --- a/include/asm-i386/device.h +++ b/include/asm-i386/device.h @@ -3,5 +3,13 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_I386_DEVICE_H +#define _ASM_I386_DEVICE_H +struct dev_archdata { +#ifdef CONFIG_ACPI + void *acpi_handle; +#endif +}; + +#endif /* _ASM_I386_DEVICE_H */ diff --git a/include/asm-ia64/device.h b/include/asm-ia64/device.h index d8f9872b0e2d..3db6daf7f251 100644 --- a/include/asm-ia64/device.h +++ b/include/asm-ia64/device.h @@ -3,5 +3,13 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_IA64_DEVICE_H +#define _ASM_IA64_DEVICE_H +struct dev_archdata { +#ifdef CONFIG_ACPI + void *acpi_handle; +#endif +}; + +#endif /* _ASM_IA64_DEVICE_H */ diff --git a/include/asm-x86_64/device.h b/include/asm-x86_64/device.h index d8f9872b0e2d..3afa03f33a36 100644 --- a/include/asm-x86_64/device.h +++ b/include/asm-x86_64/device.h @@ -3,5 +3,13 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_X86_64_DEVICE_H +#define _ASM_X86_64_DEVICE_H +struct dev_archdata { +#ifdef CONFIG_ACPI + void *acpi_handle; +#endif +}; + +#endif /* _ASM_X86_64_DEVICE_H */ diff --git a/include/linux/device.h b/include/linux/device.h index 5b54d756cd54..2d9dc358c027 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -369,8 +369,6 @@ struct device { void *driver_data; /* data private to the driver */ void *platform_data; /* Platform specific data, device core doesn't touch it */ - void *firmware_data; /* Firmware specific data (e.g. ACPI, - BIOS data),reserved for device core*/ struct dev_pm_info power; u64 *dma_mask; /* dma mask (if dma'able device) */ -- cgit v1.2.3-71-gd317 From 5ab699810d46011ad2195c5916f3cbc684bfe3ee Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 16 Nov 2006 15:42:07 +0100 Subject: driver core: Introduce device_find_child(). Introduce device_find_child() to match device_for_each_child(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 33 +++++++++++++++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 35 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index 5d11bbdfbd2f..a29e68545462 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -750,12 +750,45 @@ int device_for_each_child(struct device * parent, void * data, return error; } +/** + * device_find_child - device iterator for locating a particular device. + * @parent: parent struct device + * @data: Data to pass to match function + * @match: Callback function to check device + * + * This is similar to the device_for_each_child() function above, but it + * returns a reference to a device that is 'found' for later use, as + * determined by the @match callback. + * + * The callback should return 0 if the device doesn't match and non-zero + * if it does. If the callback returns non-zero and a reference to the + * current device can be obtained, this function will return to the caller + * and not iterate over any more devices. + */ +struct device * device_find_child(struct device *parent, void *data, + int (*match)(struct device *, void *)) +{ + struct klist_iter i; + struct device *child; + + if (!parent) + return NULL; + + klist_iter_init(&parent->klist_children, &i); + while ((child = next_device(&i))) + if (match(child, data) && get_device(child)) + break; + klist_iter_exit(&i); + return child; +} + int __init devices_init(void) { return subsystem_register(&devices_subsys); } EXPORT_SYMBOL_GPL(device_for_each_child); +EXPORT_SYMBOL_GPL(device_find_child); EXPORT_SYMBOL_GPL(device_initialize); EXPORT_SYMBOL_GPL(device_add); diff --git a/include/linux/device.h b/include/linux/device.h index 2d9dc358c027..0a0370c74181 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -421,6 +421,8 @@ extern int __must_check device_add(struct device * dev); extern void device_del(struct device * dev); extern int device_for_each_child(struct device *, void *, int (*fn)(struct device *, void *)); +extern struct device *device_find_child(struct device *, void *data, + int (*match)(struct device *, void *)); extern int device_rename(struct device *dev, char *new_name); /* -- cgit v1.2.3-71-gd317 From 8a82472f86bf693b8e91ed56c9ca4f62fbbdcfa3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 20 Nov 2006 17:07:51 +0100 Subject: driver core: Introduce device_move(): move a device to a new parent. Provide a function device_move() to move a device to a new parent device. Add auxilliary functions kobject_move() and sysfs_move_dir(). kobject_move() generates a new uevent of type KOBJ_MOVE, containing the previous path (DEVPATH_OLD) in addition to the usual values. For this, a new interface kobject_uevent_env() is created that allows to add further environmental data to the uevent at the kobject layer. Signed-off-by: Cornelia Huck Acked-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/sysfs/dir.c | 45 ++++++++++++++++++++++++ include/linux/device.h | 1 + include/linux/kobject.h | 8 +++++ include/linux/sysfs.h | 8 +++++ lib/kobject.c | 50 +++++++++++++++++++++++++++ lib/kobject_uevent.c | 28 ++++++++++++--- 7 files changed, 228 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index 75b45a10935a..e4eaf46c4d93 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -955,3 +955,95 @@ int device_rename(struct device *dev, char *new_name) return error; } + + +static int device_move_class_links(struct device *dev, + struct device *old_parent, + struct device *new_parent) +{ +#ifdef CONFIG_SYSFS_DEPRECATED + int error; + char *class_name; + + class_name = make_class_name(dev->class->name, &dev->kobj); + if (!class_name) { + error = PTR_ERR(class_name); + class_name = NULL; + goto out; + } + if (old_parent) { + sysfs_remove_link(&dev->kobj, "device"); + sysfs_remove_link(&old_parent->kobj, class_name); + } + error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); + if (error) + goto out; + error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name); + if (error) + sysfs_remove_link(&dev->kobj, "device"); +out: + kfree(class_name); + return error; +#else + return 0; +#endif +} + +/** + * device_move - moves a device to a new parent + * @dev: the pointer to the struct device to be moved + * @new_parent: the new parent of the device + */ +int device_move(struct device *dev, struct device *new_parent) +{ + int error; + struct device *old_parent; + + dev = get_device(dev); + if (!dev) + return -EINVAL; + + if (!device_is_registered(dev)) { + error = -EINVAL; + goto out; + } + new_parent = get_device(new_parent); + if (!new_parent) { + error = -EINVAL; + goto out; + } + pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, + new_parent->bus_id); + error = kobject_move(&dev->kobj, &new_parent->kobj); + if (error) { + put_device(new_parent); + goto out; + } + old_parent = dev->parent; + dev->parent = new_parent; + if (old_parent) + klist_del(&dev->knode_parent); + klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + if (!dev->class) + goto out_put; + error = device_move_class_links(dev, old_parent, new_parent); + if (error) { + /* We ignore errors on cleanup since we're hosed anyway... */ + device_move_class_links(dev, new_parent, old_parent); + if (!kobject_move(&dev->kobj, &old_parent->kobj)) { + klist_del(&dev->knode_parent); + if (old_parent) + klist_add_tail(&dev->knode_parent, + &old_parent->klist_children); + } + put_device(new_parent); + goto out; + } +out_put: + put_device(old_parent); +out: + put_device(dev); + return error; +} + +EXPORT_SYMBOL_GPL(device_move); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 3aa3434621ca..a5782e8c7f07 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -372,6 +372,51 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) return error; } +int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent) +{ + struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry; + struct sysfs_dirent *new_parent_sd, *sd; + int error; + + if (!new_parent) + return -EINVAL; + + old_parent_dentry = kobj->parent ? + kobj->parent->dentry : sysfs_mount->mnt_sb->s_root; + new_parent_dentry = new_parent->dentry; + +again: + mutex_lock(&old_parent_dentry->d_inode->i_mutex); + if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) { + mutex_unlock(&old_parent_dentry->d_inode->i_mutex); + goto again; + } + + new_parent_sd = new_parent_dentry->d_fsdata; + sd = kobj->dentry->d_fsdata; + + new_dentry = lookup_one_len(kobj->name, new_parent_dentry, + strlen(kobj->name)); + if (IS_ERR(new_dentry)) { + error = PTR_ERR(new_dentry); + goto out; + } else + error = 0; + d_add(new_dentry, NULL); + d_move(kobj->dentry, new_dentry); + dput(new_dentry); + + /* Remove from old parent's list and insert into new parent's list. */ + list_del_init(&sd->s_sibling); + list_add(&sd->s_sibling, &new_parent_sd->s_children); + +out: + mutex_unlock(&new_parent_dentry->d_inode->i_mutex); + mutex_unlock(&old_parent_dentry->d_inode->i_mutex); + + return error; +} + static int sysfs_dir_open(struct inode *inode, struct file *file) { struct dentry * dentry = file->f_dentry; diff --git a/include/linux/device.h b/include/linux/device.h index 0a0370c74181..583a341e016c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -424,6 +424,7 @@ extern int device_for_each_child(struct device *, void *, extern struct device *device_find_child(struct device *, void *data, int (*match)(struct device *, void *)); extern int device_rename(struct device *dev, char *new_name); +extern int device_move(struct device *dev, struct device *new_parent); /* * Manual binding of a device to driver. See drivers/base/bus.c diff --git a/include/linux/kobject.h b/include/linux/kobject.h index bcd9cd173c2c..d1c8d28fa92e 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -47,6 +47,7 @@ enum kobject_action { KOBJ_UMOUNT = (__force kobject_action_t) 0x05, /* umount event for block devices (broken) */ KOBJ_OFFLINE = (__force kobject_action_t) 0x06, /* device offline */ KOBJ_ONLINE = (__force kobject_action_t) 0x07, /* device online */ + KOBJ_MOVE = (__force kobject_action_t) 0x08, /* device move */ }; struct kobject { @@ -76,6 +77,7 @@ extern int __must_check kobject_add(struct kobject *); extern void kobject_del(struct kobject *); extern int __must_check kobject_rename(struct kobject *, const char *new_name); +extern int __must_check kobject_move(struct kobject *, struct kobject *); extern int __must_check kobject_register(struct kobject *); extern void kobject_unregister(struct kobject *); @@ -264,6 +266,8 @@ extern int __must_check subsys_create_file(struct subsystem * , #if defined(CONFIG_HOTPLUG) void kobject_uevent(struct kobject *kobj, enum kobject_action action); +void kobject_uevent_env(struct kobject *kobj, enum kobject_action action, + char *envp[]); int add_uevent_var(char **envp, int num_envp, int *cur_index, char *buffer, int buffer_size, int *cur_len, @@ -271,6 +275,10 @@ int add_uevent_var(char **envp, int num_envp, int *cur_index, __attribute__((format (printf, 7, 8))); #else static inline void kobject_uevent(struct kobject *kobj, enum kobject_action action) { } +static inline void kobject_uevent_env(struct kobject *kobj, + enum kobject_action action, + char *envp[]) +{ } static inline int add_uevent_var(char **envp, int num_envp, int *cur_index, char *buffer, int buffer_size, int *cur_len, diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 6d5c43d31dec..2129d1b6c874 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -96,6 +96,9 @@ sysfs_remove_dir(struct kobject *); extern int __must_check sysfs_rename_dir(struct kobject *, const char *new_name); +extern int __must_check +sysfs_move_dir(struct kobject *, struct kobject *); + extern int __must_check sysfs_create_file(struct kobject *, const struct attribute *); @@ -142,6 +145,11 @@ static inline int sysfs_rename_dir(struct kobject * k, const char *new_name) return 0; } +static inline int sysfs_move_dir(struct kobject * k, struct kobject * new_parent) +{ + return 0; +} + static inline int sysfs_create_file(struct kobject * k, const struct attribute * a) { return 0; diff --git a/lib/kobject.c b/lib/kobject.c index 7dd5c0e9d996..744a4b102c7f 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -310,6 +310,56 @@ int kobject_rename(struct kobject * kobj, const char *new_name) return error; } +/** + * kobject_move - move object to another parent + * @kobj: object in question. + * @new_parent: object's new parent + */ + +int kobject_move(struct kobject *kobj, struct kobject *new_parent) +{ + int error; + struct kobject *old_parent; + const char *devpath = NULL; + char *devpath_string = NULL; + char *envp[2]; + + kobj = kobject_get(kobj); + if (!kobj) + return -EINVAL; + new_parent = kobject_get(new_parent); + if (!new_parent) { + error = -EINVAL; + goto out; + } + /* old object path */ + devpath = kobject_get_path(kobj, GFP_KERNEL); + if (!devpath) { + error = -ENOMEM; + goto out; + } + devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL); + if (!devpath_string) { + error = -ENOMEM; + goto out; + } + sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); + envp[0] = devpath_string; + envp[1] = NULL; + error = sysfs_move_dir(kobj, new_parent); + if (error) + goto out; + old_parent = kobj->parent; + kobj->parent = new_parent; + kobject_put(old_parent); + kobject_uevent_env(kobj, KOBJ_MOVE, envp); +out: + kobject_put(kobj); + kfree(devpath_string); + kfree(devpath); + return error; +} + /** * kobject_del - unlink kobject from hierarchy. * @kobj: object. diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7f20e7b857cb..a1922765ff31 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -50,18 +50,22 @@ static char *action_to_string(enum kobject_action action) return "offline"; case KOBJ_ONLINE: return "online"; + case KOBJ_MOVE: + return "move"; default: return NULL; } } /** - * kobject_uevent - notify userspace by ending an uevent + * kobject_uevent_env - send an uevent with environmental data * - * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE) + * @action: action that is happening (usually KOBJ_MOVE) * @kobj: struct kobject that the action is happening to + * @envp_ext: pointer to environmental data */ -void kobject_uevent(struct kobject *kobj, enum kobject_action action) +void kobject_uevent_env(struct kobject *kobj, enum kobject_action action, + char *envp_ext[]) { char **envp; char *buffer; @@ -76,6 +80,7 @@ void kobject_uevent(struct kobject *kobj, enum kobject_action action) char *seq_buff; int i = 0; int retval; + int j; pr_debug("%s\n", __FUNCTION__); @@ -134,7 +139,8 @@ void kobject_uevent(struct kobject *kobj, enum kobject_action action) scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1; envp [i++] = scratch; scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1; - + for (j = 0; envp_ext && envp_ext[j]; j++) + envp[i++] = envp_ext[j]; /* just reserve the space, overwrite it after kset call has returned */ envp[i++] = seq_buff = scratch; scratch += strlen("SEQNUM=18446744073709551616") + 1; @@ -200,6 +206,20 @@ exit: kfree(envp); return; } + +EXPORT_SYMBOL_GPL(kobject_uevent_env); + +/** + * kobject_uevent - notify userspace by ending an uevent + * + * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE) + * @kobj: struct kobject that the action is happening to + */ +void kobject_uevent(struct kobject *kobj, enum kobject_action action) +{ + kobject_uevent_env(kobj, action, NULL); +} + EXPORT_SYMBOL_GPL(kobject_uevent); /** -- cgit v1.2.3-71-gd317 From c67334fbdfbba533af767610cf3fde8a49710e62 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 16 Nov 2006 23:28:47 -0800 Subject: Driver core: platform_driver_probe(), can save codespace This defines a new platform_driver_probe() method allowing the driver's probe() method, and its support code+data, to safely live in __init sections for typical system configurations. Many system-on-chip processors could benefit from this API, to the tune of recovering hundreds to thousands of bytes per driver. That's memory which is currently wasted holding code which can never be called after system startup, yet can not be removed. It can't be removed because of the linkage requirement that pointers to init section code (like, ideally, probe support) must not live in other sections (like driver method tables) after those pointers would be invalid. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 48 +++++++++++++++++++++++++++++++++++++++++ include/linux/platform_device.h | 6 ++++++ 2 files changed, 54 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 940ce41f1887..d1df4a087924 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -388,6 +388,11 @@ static int platform_drv_probe(struct device *_dev) return drv->probe(dev); } +static int platform_drv_probe_fail(struct device *_dev) +{ + return -ENXIO; +} + static int platform_drv_remove(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); @@ -451,6 +456,49 @@ void platform_driver_unregister(struct platform_driver *drv) } EXPORT_SYMBOL_GPL(platform_driver_unregister); +/** + * platform_driver_probe - register driver for non-hotpluggable device + * @drv: platform driver structure + * @probe: the driver probe routine, probably from an __init section + * + * Use this instead of platform_driver_register() when you know the device + * is not hotpluggable and has already been registered, and you want to + * remove its run-once probe() infrastructure from memory after the driver + * has bound to the device. + * + * One typical use for this would be with drivers for controllers integrated + * into system-on-chip processors, where the controller devices have been + * configured as part of board setup. + * + * Returns zero if the driver registered and bound to a device, else returns + * a negative error code and with the driver not registered. + */ +int platform_driver_probe(struct platform_driver *drv, + int (*probe)(struct platform_device *)) +{ + int retval, code; + + /* temporary section violation during probe() */ + drv->probe = probe; + retval = code = platform_driver_register(drv); + + /* Fixup that section violation, being paranoid about code scanning + * the list of drivers in order to probe new devices. Check to see + * if the probe was successful, and make sure any forced probes of + * new devices fail. + */ + spin_lock(&platform_bus_type.klist_drivers.k_lock); + drv->probe = NULL; + if (code == 0 && list_empty(&drv->driver.klist_devices.k_list)) + retval = -ENODEV; + drv->driver.probe = platform_drv_probe_fail; + spin_unlock(&platform_bus_type.klist_drivers.k_lock); + + if (code != retval) + platform_driver_unregister(drv); + return retval; +} +EXPORT_SYMBOL_GPL(platform_driver_probe); /* modalias support enables more hands-off userspace setup: * (a) environment variable lets new-style hotplug events work once system is diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 29cd6dee13db..20f47b81d3fa 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -58,6 +58,12 @@ struct platform_driver { extern int platform_driver_register(struct platform_driver *); extern void platform_driver_unregister(struct platform_driver *); +/* non-hotpluggable platform devices may use this so that probe() and + * its support may live in __init sections, conserving runtime memory. + */ +extern int platform_driver_probe(struct platform_driver *driver, + int (*probe)(struct platform_device *)); + #define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev) #define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data)) -- cgit v1.2.3-71-gd317 From e17e0f51aeea4e59c7e450a1c0f26605b91c1260 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Fri, 24 Nov 2006 12:15:25 +0100 Subject: Driver core: show drivers in /sys/module/ Show the drivers, which belong to the module: $ ls -l /sys/module/usbcore/drivers/ hub -> ../../../bus/usb/drivers/hub usb -> ../../../bus/usb/drivers/usb usbfs -> ../../../bus/usb/drivers/usbfs Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/module.h | 1 + kernel/module.c | 31 +++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index d1d00ce8f4ed..9258ffd8a7f0 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -264,6 +264,7 @@ struct module struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; + struct kobject *drivers_dir; /* Exported symbols */ const struct kernel_symbol *syms; diff --git a/kernel/module.c b/kernel/module.c index f0166563c602..45e01cb60101 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1086,22 +1086,35 @@ static int mod_sysfs_setup(struct module *mod, goto out; kobj_set_kset_s(&mod->mkobj, module_subsys); mod->mkobj.mod = mod; - err = kobject_register(&mod->mkobj.kobj); + + /* delay uevent until full sysfs population */ + kobject_init(&mod->mkobj.kobj); + err = kobject_add(&mod->mkobj.kobj); if (err) goto out; + mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); + if (!mod->drivers_dir) + goto out_unreg; + err = module_param_sysfs_setup(mod, kparam, num_params); if (err) - goto out_unreg; + goto out_unreg_drivers; err = module_add_modinfo_attrs(mod); if (err) - goto out_unreg; + goto out_unreg_param; + kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); return 0; +out_unreg_drivers: + kobject_unregister(mod->drivers_dir); +out_unreg_param: + module_param_sysfs_remove(mod); out_unreg: - kobject_unregister(&mod->mkobj.kobj); + kobject_del(&mod->mkobj.kobj); + kobject_put(&mod->mkobj.kobj); out: return err; } @@ -1110,6 +1123,7 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); + kobject_unregister(mod->drivers_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -2275,11 +2289,14 @@ void print_modules(void) void module_add_driver(struct module *mod, struct device_driver *drv) { + int no_warn; + if (!mod || !drv) return; - /* Don't check return code; this call is idempotent */ - sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); + /* Don't check return codes; these calls are idempotent */ + no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); + no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj, drv->name); } EXPORT_SYMBOL(module_add_driver); @@ -2288,6 +2305,8 @@ void module_remove_driver(struct device_driver *drv) if (!drv) return; sysfs_remove_link(&drv->kobj, "module"); + if (drv->owner && drv->owner->drivers_dir) + sysfs_remove_link(drv->owner->drivers_dir, drv->name); } EXPORT_SYMBOL(module_remove_driver); -- cgit v1.2.3-71-gd317 From 13df29f69749a61b5209d52b71fcbf7300e5d6fb Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 3 Oct 2006 16:18:28 +0100 Subject: [PATCH] 2.6.18: sb1250-mac: Missing inclusions from The uses some types and macros defined in , , and , but fails to include these headers. Signed-off-by: Maciej W. Rozycki patch-mips-2.6.18-20060920-include-phy-16 Signed-off-by: Jeff Garzik --- include/linux/phy.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/phy.h b/include/linux/phy.h index 9447a57ee8a9..ce8bc80b3c86 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -20,6 +20,10 @@ #include #include +#include +#include +#include +#include #define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ SUPPORTED_10baseT_Full | \ -- cgit v1.2.3-71-gd317 From fe75f7471ba5604fe65435f717e3612a482c28cb Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 2 Oct 2006 19:55:22 +0200 Subject: [PATCH] wext: extend MLME support This patch adds two new defines for the SIOCSIWMLME to cover all kinds MLMEs (well, except REASSOC) through a ioctl. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- include/linux/wireless.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/wireless.h b/include/linux/wireless.h index a50a0130fd9e..7c269f4992eb 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -546,6 +546,8 @@ /* MLME requests (SIOCSIWMLME / struct iw_mlme) */ #define IW_MLME_DEAUTH 0 #define IW_MLME_DISASSOC 1 +#define IW_MLME_AUTH 2 +#define IW_MLME_ASSOC 3 /* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ #define IW_AUTH_INDEX 0x0FFF -- cgit v1.2.3-71-gd317 From 52d78d63310d9818458fd9800d24a4d5425aeac7 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Mon, 6 Nov 2006 00:43:39 -0800 Subject: [PATCH] forcedeth: add new NVIDIA pci ids Add pci device ids for the NVIDIA MCP67 chip. Signed-off-by: Ayaz Abdulla Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- include/linux/pci_ids.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index e060a7637947..fd5033b8a927 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1213,6 +1213,10 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 #define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452 #define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453 +#define PCI_DEVICE_ID_NVIDIA_NVENET_24 0x054C +#define PCI_DEVICE_ID_NVIDIA_NVENET_25 0x054D +#define PCI_DEVICE_ID_NVIDIA_NVENET_26 0x054E +#define PCI_DEVICE_ID_NVIDIA_NVENET_27 0x054F #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 #define PCI_VENDOR_ID_IMS 0x10e0 -- cgit v1.2.3-71-gd317 From f789dfdc44d5bbc04fb7f06e1e4eb682169acaaf Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Thu, 30 Nov 2006 04:27:00 -0700 Subject: [PATCH] mv643xx_eth: fix unbalanced parentheses in macros Signed-off-by: Mariusz Kozlowski Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- include/linux/mv643xx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h index edfa012fad3a..aff25c000abf 100644 --- a/include/linux/mv643xx.h +++ b/include/linux/mv643xx.h @@ -724,7 +724,7 @@ #define MV643XX_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port) (0x2470 + (port<<10)) #define MV643XX_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port) (0x2474 + (port<<10)) #define MV643XX_ETH_RX_MINIMAL_FRAME_SIZE_REG(port) (0x247c + (port<<10)) -#define MV643XX_ETH_RX_DISCARDED_FRAMES_COUNTER(port) (0x2484 + (port<<10) +#define MV643XX_ETH_RX_DISCARDED_FRAMES_COUNTER(port) (0x2484 + (port<<10)) #define MV643XX_ETH_PORT_DEBUG_0_REG(port) (0x248c + (port<<10)) #define MV643XX_ETH_PORT_DEBUG_1_REG(port) (0x2490 + (port<<10)) #define MV643XX_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port) (0x2494 + (port<<10)) @@ -1135,7 +1135,7 @@ struct mv64xxx_i2c_pdata { #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_1 (1<<19) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_2 (1<<20) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_3 ((1<<20) | (1<<19)) -#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_4 ((1<<21) +#define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_4 (1<<21) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_5 ((1<<21) | (1<<19)) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_6 ((1<<21) | (1<<20)) #define MV643XX_ETH_DEFAULT_RX_UDP_QUEUE_7 ((1<<21) | (1<<20) | (1<<19)) -- cgit v1.2.3-71-gd317 From e8a2b6a4207332a2d59628a12cece9e8c1d769e4 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Fri, 1 Dec 2006 12:01:06 -0600 Subject: [PATCH] PHY: Add support for configuring the PHY connection interface Most PHYs connect to an ethernet controller over a GMII or MII interface. However, a growing number are connected over different interfaces, such as RGMII or SGMII. The ethernet driver will tell the PHY what type of connection it is by setting it manually, or passing it in through phy_connect (or phy_attach). Changes include: * Updates to documentation * Updates to PHY Lib consumers * Changes to PHY Lib to add interface support * Some minor changes to whitespace in phy.h * gianfar driver now detects interface and passes appropriate value to PHY Lib Signed-off-by: Andrew Fleming Signed-off-by: Jeff Garzik --- Documentation/networking/phy.txt | 13 +++++++++---- drivers/net/au1000_eth.c | 3 ++- drivers/net/fs_enet/fs_enet-main.c | 3 ++- drivers/net/gianfar.c | 39 ++++++++++++++++++++++++++++++++++++-- drivers/net/gianfar.h | 3 +++ drivers/net/phy/phy_device.c | 29 +++++++++++++++++++--------- include/linux/phy.h | 26 +++++++++++++++++++------ 7 files changed, 93 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index 29ccae409031..0bc95eab1512 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt @@ -1,7 +1,7 @@ ------- PHY Abstraction Layer -(Updated 2005-07-21) +(Updated 2006-11-30) Purpose @@ -97,11 +97,12 @@ Letting the PHY Abstraction Layer do Everything Next, you need to know the device name of the PHY connected to this device. The name will look something like, "phy0:0", where the first number is the - bus id, and the second is the PHY's address on that bus. + bus id, and the second is the PHY's address on that bus. Typically, + the bus is responsible for making its ID unique. Now, to connect, just call this function: - phydev = phy_connect(dev, phy_name, &adjust_link, flags); + phydev = phy_connect(dev, phy_name, &adjust_link, flags, interface); phydev is a pointer to the phy_device structure which represents the PHY. If phy_connect is successful, it will return the pointer. dev, here, is the @@ -115,6 +116,10 @@ Letting the PHY Abstraction Layer do Everything This is useful if the system has put hardware restrictions on the PHY/controller, of which the PHY needs to be aware. + interface is a u32 which specifies the connection type used + between the controller and the PHY. Examples are GMII, MII, + RGMII, and SGMII. For a full list, see include/linux/phy.h + Now just make sure that phydev->supported and phydev->advertising have any values pruned from them which don't make sense for your controller (a 10/100 controller may be connected to a gigabit capable PHY, so you would need to @@ -191,7 +196,7 @@ Doing it all yourself start, or disables then frees them for stop. struct phy_device * phy_attach(struct net_device *dev, const char *phy_id, - u32 flags); + u32 flags, phy_interface_t interface); Attaches a network device to a particular PHY, binding the PHY to a generic driver if none was found during bus initialization. Passes in diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 7db3c8af0894..f0b6879a1c7d 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -360,7 +360,8 @@ static int mii_probe (struct net_device *dev) BUG_ON(!phydev); BUG_ON(phydev->attached_dev); - phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0); + phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0, + PHY_INTERFACE_MODE_MII); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index cb3958704a87..889d3a13e95e 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -779,7 +779,8 @@ static int fs_init_phy(struct net_device *dev) fep->oldspeed = 0; fep->oldduplex = -1; if(fep->fpi->bus_id) - phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0); + phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0, + PHY_INTERFACE_MODE_MII); else { printk("No phy bus ID specified in BSP code\n"); return -EINVAL; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6bf18c82083d..baa35144134c 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -9,7 +9,7 @@ * Author: Andy Fleming * Maintainer: Kumar Gala * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * Copyright (c) 2002-2006 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -398,6 +398,38 @@ static int gfar_remove(struct platform_device *pdev) } +/* Reads the controller's registers to determine what interface + * connects it to the PHY. + */ +static phy_interface_t gfar_get_interface(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + u32 ecntrl = gfar_read(&priv->regs->ecntrl); + + if (ecntrl & ECNTRL_SGMII_MODE) + return PHY_INTERFACE_MODE_SGMII; + + if (ecntrl & ECNTRL_TBI_MODE) { + if (ecntrl & ECNTRL_REDUCED_MODE) + return PHY_INTERFACE_MODE_RTBI; + else + return PHY_INTERFACE_MODE_TBI; + } + + if (ecntrl & ECNTRL_REDUCED_MODE) { + if (ecntrl & ECNTRL_REDUCED_MII_MODE) + return PHY_INTERFACE_MODE_RMII; + else + return PHY_INTERFACE_MODE_RGMII; + } + + if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) + return PHY_INTERFACE_MODE_GMII; + + return PHY_INTERFACE_MODE_MII; +} + + /* Initializes driver's PHY state, and attaches to the PHY. * Returns 0 on success. */ @@ -409,6 +441,7 @@ static int init_phy(struct net_device *dev) SUPPORTED_1000baseT_Full : 0; struct phy_device *phydev; char phy_id[BUS_ID_SIZE]; + phy_interface_t interface; priv->oldlink = 0; priv->oldspeed = 0; @@ -416,7 +449,9 @@ static int init_phy(struct net_device *dev) snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); - phydev = phy_connect(dev, phy_id, &adjust_link, 0); + interface = gfar_get_interface(dev); + + phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 9e81a50cf2be..39e9e321fcbc 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -160,7 +160,10 @@ extern const char gfar_driver_version[]; #define ECNTRL_INIT_SETTINGS 0x00001000 #define ECNTRL_TBI_MODE 0x00000020 +#define ECNTRL_REDUCED_MODE 0x00000010 #define ECNTRL_R100 0x00000008 +#define ECNTRL_REDUCED_MII_MODE 0x00000004 +#define ECNTRL_SGMII_MODE 0x00000002 #define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2a08b2b62c4c..b01fc70a57db 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -59,6 +59,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) dev->duplex = -1; dev->pause = dev->asym_pause = 0; dev->link = 1; + dev->interface = PHY_INTERFACE_MODE_GMII; dev->autoneg = AUTONEG_ENABLE; @@ -137,11 +138,12 @@ void phy_prepare_link(struct phy_device *phydev, * the desired functionality. */ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, - void (*handler)(struct net_device *), u32 flags) + void (*handler)(struct net_device *), u32 flags, + u32 interface) { struct phy_device *phydev; - phydev = phy_attach(dev, phy_id, flags); + phydev = phy_attach(dev, phy_id, flags, interface); if (IS_ERR(phydev)) return phydev; @@ -186,7 +188,7 @@ static int phy_compare_id(struct device *dev, void *data) } struct phy_device *phy_attach(struct net_device *dev, - const char *phy_id, u32 flags) + const char *phy_id, u32 flags, u32 interface) { struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; @@ -231,6 +233,20 @@ struct phy_device *phy_attach(struct net_device *dev, phydev->dev_flags = flags; + phydev->interface = interface; + + /* Do initial configuration here, now that + * we have certain key parameters + * (dev_flags and interface) */ + if (phydev->drv->config_init) { + int err; + + err = phydev->drv->config_init(phydev); + + if (err < 0) + return ERR_PTR(err); + } + return phydev; } EXPORT_SYMBOL(phy_attach); @@ -612,13 +628,8 @@ static int phy_probe(struct device *dev) spin_unlock(&phydev->lock); - if (err < 0) - return err; - - if (phydev->drv->config_init) - err = phydev->drv->config_init(phydev); - return err; + } static int phy_remove(struct device *dev) diff --git a/include/linux/phy.h b/include/linux/phy.h index ce8bc80b3c86..edd4c88ca7d8 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -47,15 +47,26 @@ #define PHY_HAS_INTERRUPT 0x00000001 #define PHY_HAS_MAGICANEG 0x00000002 +/* Interface Mode definitions */ +typedef enum { + PHY_INTERFACE_MODE_MII, + PHY_INTERFACE_MODE_GMII, + PHY_INTERFACE_MODE_SGMII, + PHY_INTERFACE_MODE_TBI, + PHY_INTERFACE_MODE_RMII, + PHY_INTERFACE_MODE_RGMII, + PHY_INTERFACE_MODE_RTBI +} phy_interface_t; + #define MII_BUS_MAX 4 -#define PHY_INIT_TIMEOUT 100000 +#define PHY_INIT_TIMEOUT 100000 #define PHY_STATE_TIME 1 #define PHY_FORCE_TIMEOUT 10 #define PHY_AN_TIMEOUT 10 -#define PHY_MAX_ADDR 32 +#define PHY_MAX_ADDR 32 /* Used when trying to connect to a specific phy (mii bus id:phy device id) */ #define PHY_ID_FMT "%x:%02x" @@ -87,8 +98,8 @@ struct mii_bus { int *irq; }; -#define PHY_INTERRUPT_DISABLED 0x0 -#define PHY_INTERRUPT_ENABLED 0x80000000 +#define PHY_INTERRUPT_DISABLED 0x0 +#define PHY_INTERRUPT_ENABLED 0x80000000 /* PHY state machine states: * @@ -230,6 +241,8 @@ struct phy_device { u32 dev_flags; + phy_interface_t interface; + /* Bus address of the PHY (0-32) */ int addr; @@ -345,9 +358,10 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr); int phy_clear_interrupt(struct phy_device *phydev); int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); struct phy_device * phy_attach(struct net_device *dev, - const char *phy_id, u32 flags); + const char *phy_id, u32 flags, phy_interface_t interface); struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, - void (*handler)(struct net_device *), u32 flags); + void (*handler)(struct net_device *), u32 flags, + phy_interface_t interface); void phy_disconnect(struct phy_device *phydev); void phy_detach(struct phy_device *phydev); void phy_start(struct phy_device *phydev); -- cgit v1.2.3-71-gd317 From 3e6c8cd5669c1202fe806ce3e13d701f20a71c7e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:19:09 -0800 Subject: [TIPC]: endianness annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/tipc_config.h | 32 ++++++++++++++++---------------- include/net/tipc/tipc_bearer.h | 2 +- include/net/tipc/tipc_msg.h | 2 +- net/tipc/config.c | 32 +++++++++++--------------------- net/tipc/dbg.c | 3 +-- net/tipc/name_distr.c | 10 +++++----- net/tipc/node.c | 9 +++------ 7 files changed, 38 insertions(+), 52 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tipc_config.h b/include/linux/tipc_config.h index 33a653913d94..b0c916d1f375 100644 --- a/include/linux/tipc_config.h +++ b/include/linux/tipc_config.h @@ -194,34 +194,34 @@ struct tipc_node_info { - __u32 addr; /* network address of node */ - __u32 up; /* 0=down, 1= up */ + __be32 addr; /* network address of node */ + __be32 up; /* 0=down, 1= up */ }; struct tipc_link_info { - __u32 dest; /* network address of peer node */ - __u32 up; /* 0=down, 1=up */ + __be32 dest; /* network address of peer node */ + __be32 up; /* 0=down, 1=up */ char str[TIPC_MAX_LINK_NAME]; /* link name */ }; struct tipc_bearer_config { - __u32 priority; /* Range [1,31]. Override per link */ - __u32 detect_scope; + __be32 priority; /* Range [1,31]. Override per link */ + __be32 detect_scope; char name[TIPC_MAX_BEARER_NAME]; }; struct tipc_link_config { - __u32 value; + __be32 value; char name[TIPC_MAX_LINK_NAME]; }; #define TIPC_NTQ_ALLTYPES 0x80000000 struct tipc_name_table_query { - __u32 depth; /* 1:type, 2:+name info, 3:+port info, 4+:+debug info */ - __u32 type; /* {t,l,u} info ignored if high bit of "depth" is set */ - __u32 lowbound; /* (i.e. displays all entries of name table) */ - __u32 upbound; + __be32 depth; /* 1:type, 2:+name info, 3:+port info, 4+:+debug info */ + __be32 type; /* {t,l,u} info ignored if high bit of "depth" is set */ + __be32 lowbound; /* (i.e. displays all entries of name table) */ + __be32 upbound; }; /* @@ -262,8 +262,8 @@ struct tipc_route_info { */ struct tlv_desc { - __u16 tlv_len; /* TLV length (descriptor + value) */ - __u16 tlv_type; /* TLV identifier */ + __be16 tlv_len; /* TLV length (descriptor + value) */ + __be16 tlv_type; /* TLV identifier */ }; #define TLV_ALIGNTO 4 @@ -377,9 +377,9 @@ struct tipc_genlmsghdr { struct tipc_cfg_msg_hdr { - __u32 tcm_len; /* Message length (including header) */ - __u16 tcm_type; /* Command type */ - __u16 tcm_flags; /* Additional flags */ + __be32 tcm_len; /* Message length (including header) */ + __be16 tcm_type; /* Command type */ + __be16 tcm_flags; /* Additional flags */ char tcm_reserved[8]; /* Unused */ }; diff --git a/include/net/tipc/tipc_bearer.h b/include/net/tipc/tipc_bearer.h index e07136d74c2f..2151a80cdf30 100644 --- a/include/net/tipc/tipc_bearer.h +++ b/include/net/tipc/tipc_bearer.h @@ -58,7 +58,7 @@ */ struct tipc_media_addr { - __u32 type; /* bearer type (network byte order) */ + __be32 type; /* bearer type (network byte order) */ union { __u8 eth_addr[6]; /* 48 bit Ethernet addr (byte array) */ #if 0 diff --git a/include/net/tipc/tipc_msg.h b/include/net/tipc/tipc_msg.h index 4d096eebc93f..fb42eb7a86a5 100644 --- a/include/net/tipc/tipc_msg.h +++ b/include/net/tipc/tipc_msg.h @@ -40,7 +40,7 @@ #ifdef __KERNEL__ struct tipc_msg { - u32 hdr[15]; + __be32 hdr[15]; }; diff --git a/net/tipc/config.c b/net/tipc/config.c index ed1351ed05e1..458a2c46cef3 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -107,7 +107,7 @@ int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type, struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value) { struct sk_buff *buf; - u32 value_net; + __be32 value_net; buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value))); if (buf) { @@ -284,8 +284,7 @@ static struct sk_buff *cfg_set_own_addr(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - addr = *(u32 *)TLV_DATA(req_tlv_area); - addr = ntohl(addr); + addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (addr == tipc_own_addr) return tipc_cfg_reply_none(); if (!tipc_addr_node_valid(addr)) @@ -319,8 +318,7 @@ static struct sk_buff *cfg_set_remote_mng(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); tipc_remote_management = (value != 0); return tipc_cfg_reply_none(); } @@ -332,8 +330,7 @@ static struct sk_buff *cfg_set_max_publications(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 65535)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max publications must be 1-65535)"); @@ -348,8 +345,7 @@ static struct sk_buff *cfg_set_max_subscriptions(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 65535)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max subscriptions must be 1-65535"); @@ -363,8 +359,7 @@ static struct sk_buff *cfg_set_max_ports(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_ports) return tipc_cfg_reply_none(); if (value != delimit(value, 127, 65535)) @@ -383,8 +378,7 @@ static struct sk_buff *cfg_set_max_zones(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_zones) return tipc_cfg_reply_none(); if (value != delimit(value, 1, 255)) @@ -403,8 +397,7 @@ static struct sk_buff *cfg_set_max_clusters(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 1)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max clusters fixed at 1)"); @@ -417,8 +410,7 @@ static struct sk_buff *cfg_set_max_nodes(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_nodes) return tipc_cfg_reply_none(); if (value != delimit(value, 8, 2047)) @@ -437,8 +429,7 @@ static struct sk_buff *cfg_set_max_slaves(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != 0) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (max secondary nodes fixed at 0)"); @@ -451,8 +442,7 @@ static struct sk_buff *cfg_set_netid(void) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_net_id) return tipc_cfg_reply_none(); if (value != delimit(value, 1, 9999)) diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c index d8af4c28695d..627f99b7afdf 100644 --- a/net/tipc/dbg.c +++ b/net/tipc/dbg.c @@ -393,8 +393,7 @@ struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - value = *(u32 *)TLV_DATA(req_tlv_area); - value = ntohl(value); + value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 0, 32768)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (log size must be 0-32768)"); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 03bd659c43ca..7bf87cb26ef3 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -66,11 +66,11 @@ */ struct distr_item { - u32 type; - u32 lower; - u32 upper; - u32 ref; - u32 key; + __be32 type; + __be32 lower; + __be32 upper; + __be32 ref; + __be32 key; }; /** diff --git a/net/tipc/node.c b/net/tipc/node.c index 886bda5e88db..106cd0dfac78 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -597,8 +597,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - domain = *(u32 *)TLV_DATA(req_tlv_area); - domain = ntohl(domain); + domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (!tipc_addr_domain_valid(domain)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network address)"); @@ -642,8 +641,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - domain = *(u32 *)TLV_DATA(req_tlv_area); - domain = ntohl(domain); + domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (!tipc_addr_domain_valid(domain)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network address)"); @@ -664,8 +662,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) /* Add TLV for broadcast link */ - link_info.dest = tipc_own_addr & 0xfffff00; - link_info.dest = htonl(link_info.dest); + link_info.dest = htonl(tipc_own_addr & 0xfffff00); link_info.up = htonl(1); sprintf(link_info.str, tipc_bclink_name); tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info)); -- cgit v1.2.3-71-gd317 From 5a874db4d9bfd8a4c6324d844a4d1c7cfa5cf2c4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:19:38 -0800 Subject: [NET]: ipconfig and nfsroot annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- fs/nfs/nfsroot.c | 13 +++--- include/linux/nfs_fs.h | 2 +- include/net/ipconfig.h | 8 ++-- net/ipv4/ipconfig.c | 105 +++++++++++++++++++++++++------------------------ 4 files changed, 64 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 8dfefe41a8da..75f819dc0255 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -98,7 +98,7 @@ static char nfs_root_name[256] __initdata = ""; /* Address of NFS server */ -static __u32 servaddr __initdata = 0; +static __be32 servaddr __initdata = 0; /* Name of directory to mount */ static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, }; @@ -327,7 +327,7 @@ static int __init root_nfs_name(char *name) */ static int __init root_nfs_addr(void) { - if ((servaddr = root_server_addr) == INADDR_NONE) { + if ((servaddr = root_server_addr) == htonl(INADDR_NONE)) { printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n"); return -1; } @@ -411,7 +411,7 @@ __setup("nfsroot=", nfs_root_setup); * Construct sockaddr_in from address and port number. */ static inline void -set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port) +set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr; @@ -468,14 +468,13 @@ static int __init root_nfs_ports(void) dprintk("Root-NFS: Portmapper on server returned %d " "as nfsd port\n", port); } - nfs_port = htons(nfs_port); if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) { printk(KERN_ERR "Root-NFS: Unable to get mountd port " "number from server, using default\n"); port = mountd_port; } - mount_port = htons(port); + mount_port = port; dprintk("Root-NFS: mountd port is %d\n", port); return 0; @@ -496,7 +495,7 @@ static int __init root_nfs_get_handle(void) int version = (nfs_data.flags & NFS_MOUNT_VER3) ? NFS_MNT3_VERSION : NFS_MNT_VERSION; - set_sockaddr(&sin, servaddr, mount_port); + set_sockaddr(&sin, servaddr, htons(mount_port)); status = nfsroot_mount(&sin, nfs_path, &fh, version, protocol); if (status < 0) printk(KERN_ERR "Root-NFS: Server returned error %d " @@ -519,6 +518,6 @@ void * __init nfs_root_data(void) || root_nfs_ports() < 0 || root_nfs_get_handle() < 0) return NULL; - set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port); + set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, htons(nfs_port)); return (void*)&nfs_data; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 45228c1a1195..625ffea98561 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -318,7 +318,7 @@ extern void put_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode); /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ -extern u32 root_nfs_parse_addr(char *name); /*__init*/ +extern __be32 root_nfs_parse_addr(char *name); /*__init*/ static inline void nfs_fattr_init(struct nfs_fattr *fattr) { diff --git a/include/net/ipconfig.h b/include/net/ipconfig.h index 2a1fe996fbc6..3924d7d2cb11 100644 --- a/include/net/ipconfig.h +++ b/include/net/ipconfig.h @@ -11,12 +11,12 @@ extern int ic_proto_enabled; /* Protocols enabled (see IC_xxx) */ extern int ic_set_manually; /* IPconfig parameters set manually */ -extern u32 ic_myaddr; /* My IP address */ -extern u32 ic_gateway; /* Gateway IP address */ +extern __be32 ic_myaddr; /* My IP address */ +extern __be32 ic_gateway; /* Gateway IP address */ -extern u32 ic_servaddr; /* Boot server IP address */ +extern __be32 ic_servaddr; /* Boot server IP address */ -extern u32 root_server_addr; /* Address of NFS server */ +extern __be32 root_server_addr; /* Address of NFS server */ extern u8 root_server_path[]; /* Path to mount as root */ diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 955a07abb91d..afa60b9a003f 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -101,6 +101,7 @@ #define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers - '3' from resolv.h */ +#define NONE __constant_htonl(INADDR_NONE) /* * Public IP configuration @@ -129,19 +130,19 @@ int ic_proto_enabled __initdata = 0 static int ic_host_name_set __initdata = 0; /* Host name set by us? */ -u32 ic_myaddr = INADDR_NONE; /* My IP address */ -static u32 ic_netmask = INADDR_NONE; /* Netmask for local subnet */ -u32 ic_gateway = INADDR_NONE; /* Gateway IP address */ +__be32 ic_myaddr = NONE; /* My IP address */ +static __be32 ic_netmask = NONE; /* Netmask for local subnet */ +__be32 ic_gateway = NONE; /* Gateway IP address */ -u32 ic_servaddr = INADDR_NONE; /* Boot server IP address */ +__be32 ic_servaddr = NONE; /* Boot server IP address */ -u32 root_server_addr = INADDR_NONE; /* Address of NFS server */ +__be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ /* Persistent data: */ static int ic_proto_used; /* Protocol used, if any */ -static u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ +static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ static u8 ic_domain[64]; /* DNS (not NIS) domain name */ /* @@ -172,7 +173,7 @@ struct ic_device { struct net_device *dev; unsigned short flags; short able; - u32 xid; + __be32 xid; }; static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ @@ -223,7 +224,7 @@ static int __init ic_open_devs(void) d->flags = oflags; d->able = able; if (able & IC_BOOTP) - get_random_bytes(&d->xid, sizeof(u32)); + get_random_bytes(&d->xid, sizeof(__be32)); else d->xid = 0; ic_proto_have_if |= able; @@ -269,7 +270,7 @@ static void __init ic_close_devs(void) */ static inline void -set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port) +set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr; @@ -332,7 +333,7 @@ static int __init ic_setup_routes(void) { /* No need to setup device routes, only the default route... */ - if (ic_gateway != INADDR_NONE) { + if (ic_gateway != NONE) { struct rtentry rm; int err; @@ -368,10 +369,10 @@ static int __init ic_defaults(void) if (!ic_host_name_set) sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); - if (root_server_addr == INADDR_NONE) + if (root_server_addr == NONE) root_server_addr = ic_servaddr; - if (ic_netmask == INADDR_NONE) { + if (ic_netmask == NONE) { if (IN_CLASSA(ntohl(ic_myaddr))) ic_netmask = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(ic_myaddr))) @@ -420,7 +421,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt { struct arphdr *rarp; unsigned char *rarp_ptr; - u32 sip, tip; + __be32 sip, tip; unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; @@ -485,12 +486,12 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt goto drop_unlock; /* Discard packets which are not from specified server. */ - if (ic_servaddr != INADDR_NONE && ic_servaddr != sip) + if (ic_servaddr != NONE && ic_servaddr != sip) goto drop_unlock; /* We have a winner! */ ic_dev = dev; - if (ic_myaddr == INADDR_NONE) + if (ic_myaddr == NONE) ic_myaddr = tip; ic_servaddr = sip; ic_got_reply = IC_RARP; @@ -530,13 +531,13 @@ struct bootp_pkt { /* BOOTP packet format */ u8 htype; /* HW address type */ u8 hlen; /* HW address length */ u8 hops; /* Used only by gateways */ - u32 xid; /* Transaction ID */ - u16 secs; /* Seconds since we started */ - u16 flags; /* Just what it says */ - u32 client_ip; /* Client's IP address if known */ - u32 your_ip; /* Assigned IP address */ - u32 server_ip; /* (Next, e.g. NFS) Server's IP address */ - u32 relay_ip; /* IP address of BOOTP relay */ + __be32 xid; /* Transaction ID */ + __be16 secs; /* Seconds since we started */ + __be16 flags; /* Just what it says */ + __be32 client_ip; /* Client's IP address if known */ + __be32 your_ip; /* Assigned IP address */ + __be32 server_ip; /* (Next, e.g. NFS) Server's IP address */ + __be32 relay_ip; /* IP address of BOOTP relay */ u8 hw_addr[16]; /* Client's HW address */ u8 serv_name[64]; /* Server host name */ u8 boot_file[128]; /* Name of boot file */ @@ -576,7 +577,7 @@ static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 }; static void __init ic_dhcp_init_options(u8 *options) { - u8 mt = ((ic_servaddr == INADDR_NONE) + u8 mt = ((ic_servaddr == NONE) ? DHCPDISCOVER : DHCPREQUEST); u8 *e = options; @@ -666,7 +667,7 @@ static inline void ic_bootp_init(void) int i; for (i = 0; i < CONF_NAMESERVERS_MAX; i++) - ic_nameservers[i] = INADDR_NONE; + ic_nameservers[i] = NONE; dev_add_pack(&bootp_packet_type); } @@ -708,7 +709,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d h->frag_off = htons(IP_DF); h->ttl = 64; h->protocol = IPPROTO_UDP; - h->daddr = INADDR_BROADCAST; + h->daddr = htonl(INADDR_BROADCAST); h->check = ip_fast_csum((unsigned char *) h, h->ihl); /* Construct UDP header */ @@ -730,8 +731,8 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d b->htype = dev->type; /* can cause undefined behavior */ } b->hlen = dev->addr_len; - b->your_ip = INADDR_NONE; - b->server_ip = INADDR_NONE; + b->your_ip = NONE; + b->server_ip = NONE; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies_diff / HZ); b->xid = d->xid; @@ -788,11 +789,11 @@ static void __init ic_do_bootp_ext(u8 *ext) switch (*ext++) { case 1: /* Subnet mask */ - if (ic_netmask == INADDR_NONE) + if (ic_netmask == NONE) memcpy(&ic_netmask, ext+1, 4); break; case 3: /* Default gateway */ - if (ic_gateway == INADDR_NONE) + if (ic_gateway == NONE) memcpy(&ic_gateway, ext+1, 4); break; case 6: /* DNS server */ @@ -800,7 +801,7 @@ static void __init ic_do_bootp_ext(u8 *ext) if (servers > CONF_NAMESERVERS_MAX) servers = CONF_NAMESERVERS_MAX; for (i = 0; i < servers; i++) { - if (ic_nameservers[i] == INADDR_NONE) + if (ic_nameservers[i] == NONE) memcpy(&ic_nameservers[i], ext+1+4*i, 4); } break; @@ -917,7 +918,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str #ifdef IPCONFIG_DHCP if (ic_proto_enabled & IC_USE_DHCP) { - u32 server_id = INADDR_NONE; + __be32 server_id = NONE; int mt = 0; ext = &b->exten[4]; @@ -949,7 +950,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str /* While in the process of accepting one offer, * ignore all others. */ - if (ic_myaddr != INADDR_NONE) + if (ic_myaddr != NONE) goto drop_unlock; /* Let's accept that offer. */ @@ -965,7 +966,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str * precedence over the bootp header one if * they are different. */ - if ((server_id != INADDR_NONE) && + if ((server_id != NONE) && (b->server_ip != server_id)) b->server_ip = ic_servaddr; break; @@ -979,8 +980,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str default: /* Urque. Forget it*/ - ic_myaddr = INADDR_NONE; - ic_servaddr = INADDR_NONE; + ic_myaddr = NONE; + ic_servaddr = NONE; goto drop_unlock; }; @@ -1004,9 +1005,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ic_dev = dev; ic_myaddr = b->your_ip; ic_servaddr = b->server_ip; - if (ic_gateway == INADDR_NONE && b->relay_ip) + if (ic_gateway == NONE && b->relay_ip) ic_gateway = b->relay_ip; - if (ic_nameservers[0] == INADDR_NONE) + if (ic_nameservers[0] == NONE) ic_nameservers[0] = ic_servaddr; ic_got_reply = IC_BOOTP; @@ -1150,7 +1151,7 @@ static int __init ic_dynamic(void) #endif if (!ic_got_reply) { - ic_myaddr = INADDR_NONE; + ic_myaddr = NONE; return -1; } @@ -1182,12 +1183,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "domain %s\n", ic_domain); for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { - if (ic_nameservers[i] != INADDR_NONE) + if (ic_nameservers[i] != NONE) seq_printf(seq, "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameservers[i])); } - if (ic_servaddr != INADDR_NONE) + if (ic_servaddr != NONE) seq_printf(seq, "bootserver %u.%u.%u.%u\n", NIPQUAD(ic_servaddr)); @@ -1213,9 +1214,9 @@ static struct file_operations pnp_seq_fops = { * need to have root_server_addr set _before_ IPConfig gets called as it * can override it. */ -u32 __init root_nfs_parse_addr(char *name) +__be32 __init root_nfs_parse_addr(char *name) { - u32 addr; + __be32 addr; int octets = 0; char *cp, *cq; @@ -1237,7 +1238,7 @@ u32 __init root_nfs_parse_addr(char *name) addr = in_aton(name); memmove(name, cp, strlen(cp) + 1); } else - addr = INADDR_NONE; + addr = NONE; return addr; } @@ -1248,7 +1249,7 @@ u32 __init root_nfs_parse_addr(char *name) static int __init ip_auto_config(void) { - u32 addr; + __be32 addr; #ifdef CONFIG_PROC_FS proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); @@ -1277,11 +1278,11 @@ static int __init ip_auto_config(void) * interfaces and no default was set), use BOOTP or RARP to get the * missing values. */ - if (ic_myaddr == INADDR_NONE || + if (ic_myaddr == NONE || #ifdef CONFIG_ROOT_NFS (MAJOR(ROOT_DEV) == UNNAMED_MAJOR - && root_server_addr == INADDR_NONE - && ic_servaddr == INADDR_NONE) || + && root_server_addr == NONE + && ic_servaddr == NONE) || #endif ic_first_dev->next) { #ifdef IPCONFIG_DYNAMIC @@ -1334,7 +1335,7 @@ static int __init ip_auto_config(void) } addr = root_nfs_parse_addr(root_server_path); - if (root_server_addr == INADDR_NONE) + if (root_server_addr == NONE) root_server_addr = addr; /* @@ -1461,19 +1462,19 @@ static int __init ip_auto_config_setup(char *addrs) switch (num) { case 0: if ((ic_myaddr = in_aton(ip)) == INADDR_ANY) - ic_myaddr = INADDR_NONE; + ic_myaddr = NONE; break; case 1: if ((ic_servaddr = in_aton(ip)) == INADDR_ANY) - ic_servaddr = INADDR_NONE; + ic_servaddr = NONE; break; case 2: if ((ic_gateway = in_aton(ip)) == INADDR_ANY) - ic_gateway = INADDR_NONE; + ic_gateway = NONE; break; case 3: if ((ic_netmask = in_aton(ip)) == INADDR_ANY) - ic_netmask = INADDR_NONE; + ic_netmask = NONE; break; case 4: if ((dp = strchr(ip, '.'))) { -- cgit v1.2.3-71-gd317 From a27ee7a4dd30feda1954950b5840455a51ae1507 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:21:21 -0800 Subject: [IPV6]: annotate icmpv6 headers Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index c771a7db9871..dc79396aac25 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -7,17 +7,17 @@ struct icmp6hdr { __u8 icmp6_type; __u8 icmp6_code; - __u16 icmp6_cksum; + __be16 icmp6_cksum; union { - __u32 un_data32[1]; - __u16 un_data16[2]; + __be32 un_data32[1]; + __be16 un_data16[2]; __u8 un_data8[4]; struct icmpv6_echo { - __u16 identifier; - __u16 sequence; + __be16 identifier; + __be16 sequence; } u_echo; struct icmpv6_nd_advt { @@ -53,7 +53,7 @@ struct icmp6hdr { #else #error "Please fix " #endif - __u16 rt_lifetime; + __be16 rt_lifetime; } u_nd_ra; } icmp6_dataun; -- cgit v1.2.3-71-gd317 From d5a0a1e3109339090769e40fdaa62482fcf2a717 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:23:14 -0800 Subject: [IPV4]: encapsulation annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/if_tunnel.h | 8 ++++---- include/linux/xfrm.h | 4 ++-- net/ipv4/ah4.c | 4 ++-- net/ipv4/esp4.c | 4 ++-- net/ipv4/ip_gre.c | 52 +++++++++++++++++++++++------------------------ net/ipv4/ipip.c | 16 +++++++-------- 6 files changed, 44 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index bef9f8fd93b3..8de079ba1107 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -19,10 +19,10 @@ struct ip_tunnel_parm { char name[IFNAMSIZ]; int link; - __u16 i_flags; - __u16 o_flags; - __u32 i_key; - __u32 o_key; + __be16 i_flags; + __be16 o_flags; + __be32 i_key; + __be32 o_key; struct iphdr iph; }; diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 8ae7f744917b..7907c42bd4e4 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -211,8 +211,8 @@ struct xfrm_user_tmpl { struct xfrm_encap_tmpl { __u16 encap_type; - __u16 encap_sport; - __u16 encap_dport; + __be16 encap_sport; + __be16 encap_dport; xfrm_address_t encap_oa; }; diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 99542977e47e..67a5509e26fc 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -14,7 +14,7 @@ * into IP header for icv calculation. Options are already checked * for validity, so paranoia is not required. */ -static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) +static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) { unsigned char * optptr = (unsigned char*)(iph+1); int l = iph->ihl*4 - sizeof(struct iphdr); @@ -162,7 +162,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) iph->frag_off = 0; iph->check = 0; if (ihl > sizeof(*iph)) { - u32 dummy; + __be32 dummy; if (ip_clear_mutable_options(iph, &dummy)) goto out; } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b5c205b57669..f2c6776ea0e6 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -67,7 +67,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) if (x->encap) { struct xfrm_encap_tmpl *encap = x->encap; struct udphdr *uh; - u32 *udpdata32; + __be32 *udpdata32; uh = (struct udphdr *)esph; uh->source = encap->encap_sport; @@ -81,7 +81,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) esph = (struct ip_esp_hdr *)(uh + 1); break; case UDP_ENCAP_ESPINUDP_NON_IKE: - udpdata32 = (u32 *)(uh + 1); + udpdata32 = (__be32 *)(uh + 1); udpdata32[0] = udpdata32[1] = 0; esph = (struct ip_esp_hdr *)(udpdata32 + 2); break; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d5b5dec075b8..25221146debb 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -144,7 +144,7 @@ static struct net_device *ipgre_fb_tunnel_dev; */ #define HASH_SIZE 16 -#define HASH(addr) ((addr^(addr>>4))&0xF) +#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) static struct ip_tunnel *tunnels[4][HASH_SIZE]; @@ -157,7 +157,7 @@ static DEFINE_RWLOCK(ipgre_lock); /* Given src, dst and key, find appropriate for input tunnel. */ -static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) +static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be32 key) { unsigned h0 = HASH(remote); unsigned h1 = HASH(key); @@ -194,9 +194,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t) { - u32 remote = t->parms.iph.daddr; - u32 local = t->parms.iph.saddr; - u32 key = t->parms.i_key; + __be32 remote = t->parms.iph.daddr; + __be32 local = t->parms.iph.saddr; + __be32 key = t->parms.i_key; unsigned h = HASH(key); int prio = 0; @@ -236,9 +236,9 @@ static void ipgre_tunnel_unlink(struct ip_tunnel *t) static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create) { - u32 remote = parms->iph.daddr; - u32 local = parms->iph.saddr; - u32 key = parms->i_key; + __be32 remote = parms->iph.daddr; + __be32 local = parms->iph.saddr; + __be32 key = parms->i_key; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; unsigned h = HASH(key); @@ -319,12 +319,12 @@ static void ipgre_err(struct sk_buff *skb, u32 info) */ struct iphdr *iph = (struct iphdr*)skb->data; - u16 *p = (u16*)(skb->data+(iph->ihl<<2)); + __be16 *p = (__be16*)(skb->data+(iph->ihl<<2)); int grehlen = (iph->ihl<<2) + 4; int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; - u16 flags; + __be16 flags; flags = p[0]; if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { @@ -370,7 +370,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) } read_lock(&ipgre_lock); - t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0); + t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0); if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr)) goto out; @@ -388,14 +388,14 @@ out: #else struct iphdr *iph = (struct iphdr*)dp; struct iphdr *eiph; - u16 *p = (u16*)(dp+(iph->ihl<<2)); + __be16 *p = (__be16*)(dp+(iph->ihl<<2)); int type = skb->h.icmph->type; int code = skb->h.icmph->code; int rel_type = 0; int rel_code = 0; __be32 rel_info = 0; __u32 n = 0; - u16 flags; + __be16 flags; int grehlen = (iph->ihl<<2) + 4; struct sk_buff *skb2; struct flowi fl; @@ -556,9 +556,9 @@ static int ipgre_rcv(struct sk_buff *skb) { struct iphdr *iph; u8 *h; - u16 flags; + __be16 flags; u16 csum = 0; - u32 key = 0; + __be32 key = 0; u32 seqno = 0; struct ip_tunnel *tunnel; int offset = 4; @@ -568,7 +568,7 @@ static int ipgre_rcv(struct sk_buff *skb) iph = skb->nh.iph; h = skb->data; - flags = *(u16*)h; + flags = *(__be16*)h; if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { /* - Version must be 0. @@ -592,11 +592,11 @@ static int ipgre_rcv(struct sk_buff *skb) offset += 4; } if (flags&GRE_KEY) { - key = *(u32*)(h + offset); + key = *(__be32*)(h + offset); offset += 4; } if (flags&GRE_SEQ) { - seqno = ntohl(*(u32*)(h + offset)); + seqno = ntohl(*(__be32*)(h + offset)); offset += 4; } } @@ -605,7 +605,7 @@ static int ipgre_rcv(struct sk_buff *skb) if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { secpath_reset(skb); - skb->protocol = *(u16*)(h + 2); + skb->protocol = *(__be16*)(h + 2); /* WCCP version 1 and 2 protocol decoding. * - Change protocol to IP * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header @@ -673,13 +673,13 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct iphdr *old_iph = skb->nh.iph; struct iphdr *tiph; u8 tos; - u16 df; + __be16 df; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ int gre_hlen; - u32 dst; + __be32 dst; int mtu; if (tunnel->recursion++) { @@ -860,11 +860,11 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT); } - ((u16*)(iph+1))[0] = tunnel->parms.o_flags; - ((u16*)(iph+1))[1] = skb->protocol; + ((__be16*)(iph+1))[0] = tunnel->parms.o_flags; + ((__be16*)(iph+1))[1] = skb->protocol; if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { - u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4); + __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4); if (tunnel->parms.o_flags&GRE_SEQ) { ++tunnel->o_seqno; @@ -877,7 +877,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (tunnel->parms.o_flags&GRE_CSUM) { *ptr = 0; - *(__u16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); + *(__be16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); } } @@ -1068,7 +1068,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh { struct ip_tunnel *t = netdev_priv(dev); struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); - u16 *p = (u16*)(iph+1); + __be16 *p = (__be16*)(iph+1); memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); p[0] = t->parms.o_flags; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 0c4556529228..9d719d664e5b 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -118,7 +118,7 @@ #include #define HASH_SIZE 16 -#define HASH(addr) ((addr^(addr>>4))&0xF) +#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) static int ipip_fb_tunnel_init(struct net_device *dev); static int ipip_tunnel_init(struct net_device *dev); @@ -134,7 +134,7 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne static DEFINE_RWLOCK(ipip_lock); -static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) +static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -160,8 +160,8 @@ static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local) static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t) { - u32 remote = t->parms.iph.daddr; - u32 local = t->parms.iph.saddr; + __be32 remote = t->parms.iph.daddr; + __be32 local = t->parms.iph.saddr; unsigned h = 0; int prio = 0; @@ -203,8 +203,8 @@ static void ipip_tunnel_link(struct ip_tunnel *t) static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) { - u32 remote = parms->iph.daddr; - u32 local = parms->iph.saddr; + __be32 remote = parms->iph.daddr; + __be32 local = parms->iph.saddr; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; unsigned h = 0; @@ -519,13 +519,13 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct net_device_stats *stats = &tunnel->stat; struct iphdr *tiph = &tunnel->parms.iph; u8 tos = tunnel->parms.iph.tos; - u16 df = tiph->frag_off; + __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *old_iph = skb->nh.iph; struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ - u32 dst = tiph->daddr; + __be32 dst = tiph->daddr; int mtu; if (tunnel->recursion++) { -- cgit v1.2.3-71-gd317 From d29ef86b0a497dd2c4f9601644a15392f7e21f73 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:23:42 -0800 Subject: [AF_KEY]: annotate Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/pfkeyv2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index d5dd471da225..0f0b880c4280 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -32,7 +32,7 @@ struct sadb_ext { struct sadb_sa { uint16_t sadb_sa_len; uint16_t sadb_sa_exttype; - uint32_t sadb_sa_spi; + __be32 sadb_sa_spi; uint8_t sadb_sa_replay; uint8_t sadb_sa_state; uint8_t sadb_sa_auth; @@ -211,7 +211,7 @@ struct sadb_x_nat_t_type { struct sadb_x_nat_t_port { uint16_t sadb_x_nat_t_port_len; uint16_t sadb_x_nat_t_port_exttype; - uint16_t sadb_x_nat_t_port_port; + __be16 sadb_x_nat_t_port_port; uint16_t sadb_x_nat_t_port_reserved; } __attribute__((packed)); /* sizeof(struct sadb_x_nat_t_port) == 8 */ -- cgit v1.2.3-71-gd317 From 90bcaf7b4a33bb9b100cc06869f0c033a870d4a0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:25:17 -0800 Subject: [IPV6]: flowlabels are net-endian Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/in6.h | 4 ++-- include/linux/ip6_tunnel.h | 2 +- include/linux/ipv6.h | 2 +- include/net/flow.h | 2 +- include/net/ipv6.h | 4 ++-- net/ipv6/af_inet6.c | 2 +- net/ipv6/datagram.c | 10 +++++----- net/ipv6/ip6_flowlabel.c | 8 ++++---- net/ipv6/ip6_output.c | 4 ++-- net/ipv6/ip6_tunnel.c | 6 +++--- net/ipv6/route.c | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/include/linux/in6.h b/include/linux/in6.h index f28621f638e0..4e8350ae8869 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -54,7 +54,7 @@ extern const struct in6_addr in6addr_loopback; struct sockaddr_in6 { unsigned short int sin6_family; /* AF_INET6 */ __be16 sin6_port; /* Transport layer port # */ - __u32 sin6_flowinfo; /* IPv6 flow information */ + __be32 sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ __u32 sin6_scope_id; /* scope id (new in RFC2553) */ }; @@ -72,7 +72,7 @@ struct ipv6_mreq { struct in6_flowlabel_req { struct in6_addr flr_dst; - __u32 flr_label; + __be32 flr_label; __u8 flr_action; __u8 flr_share; __u16 flr_flags; diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h index 5c23aeb104ca..af3f4a70f3df 100644 --- a/include/linux/ip6_tunnel.h +++ b/include/linux/ip6_tunnel.h @@ -25,7 +25,7 @@ struct ip6_tnl_parm { __u8 proto; /* tunnel protocol */ __u8 encap_limit; /* encapsulation limit for tunnel */ __u8 hop_limit; /* hop limit for tunnel */ - __u32 flowinfo; /* traffic class and flowlabel for tunnel */ + __be32 flowinfo; /* traffic class and flowlabel for tunnel */ __u32 flags; /* tunnel flags */ struct in6_addr laddr; /* local tunnel end-point address */ struct in6_addr raddr; /* remote tunnel end-point address */ diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4f435c59de06..f8241130f5ea 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -274,7 +274,7 @@ struct ipv6_pinfo { struct in6_addr *saddr_cache; #endif - __u32 flow_label; + __be32 flow_label; __u32 frag_size; __s16 hop_limit; __s16 mcast_hops; diff --git a/include/net/flow.h b/include/net/flow.h index 5cda27cd9deb..270d4c1761af 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -27,7 +27,7 @@ struct flowi { struct in6_addr daddr; struct in6_addr saddr; __u32 fwmark; - __u32 flowlabel; + __be32 flowlabel; } ip6_u; struct { diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4953fac1d070..0b8c9b990ac4 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -191,7 +191,7 @@ struct ipv6_txoptions struct ip6_flowlabel { struct ip6_flowlabel *next; - u32 label; + __be32 label; struct in6_addr dst; struct ipv6_txoptions *opt; atomic_t users; @@ -211,7 +211,7 @@ struct ipv6_fl_socklist struct ip6_flowlabel *fl; }; -extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, u32 label); +extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); extern struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, struct ip6_flowlabel * fl, struct ipv6_txoptions * fopt); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 858cae29581c..92bfccf62cb7 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -678,7 +678,7 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) if (np->rxopt.all) { if ((opt->hop && (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) || - ((IPV6_FLOWINFO_MASK & *(u32*)skb->nh.raw) && + ((IPV6_FLOWINFO_MASK & *(__be32*)skb->nh.raw) && np->rxopt.bits.rxflow) || (opt->srcrt && (np->rxopt.bits.srcrt || np->rxopt.bits.osrcrt)) || diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 7206747022fc..a67434af691f 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -318,7 +318,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) ipv6_addr_copy(&sin->sin6_addr, (struct in6_addr *)(skb->nh.raw + serr->addr_offset)); if (np->sndflow) - sin->sin6_flowinfo = *(u32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK; + sin->sin6_flowinfo = *(__be32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK; if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id = IP6CB(skb)->iif; } else { @@ -401,8 +401,8 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); } - if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) { - u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK; + if (np->rxopt.bits.rxflow && (*(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) { + __be32 flowinfo = *(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK; put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); } @@ -560,12 +560,12 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, } if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) { - if ((fl->fl6_flowlabel^*(u32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) { + if ((fl->fl6_flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) { err = -EINVAL; goto exit_f; } } - fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(u32 *)CMSG_DATA(cmsg); + fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg); break; case IPV6_2292HOPOPTS: diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 6d4533b58dca..624fae251f4e 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -61,7 +61,7 @@ static DEFINE_RWLOCK(ip6_fl_lock); static DEFINE_RWLOCK(ip6_sk_fl_lock); -static __inline__ struct ip6_flowlabel * __fl_lookup(u32 label) +static __inline__ struct ip6_flowlabel * __fl_lookup(__be32 label) { struct ip6_flowlabel *fl; @@ -72,7 +72,7 @@ static __inline__ struct ip6_flowlabel * __fl_lookup(u32 label) return NULL; } -static struct ip6_flowlabel * fl_lookup(u32 label) +static struct ip6_flowlabel * fl_lookup(__be32 label) { struct ip6_flowlabel *fl; @@ -153,7 +153,7 @@ static void ip6_fl_gc(unsigned long dummy) write_unlock(&ip6_fl_lock); } -static int fl_intern(struct ip6_flowlabel *fl, __u32 label) +static int fl_intern(struct ip6_flowlabel *fl, __be32 label) { fl->label = label & IPV6_FLOWLABEL_MASK; @@ -182,7 +182,7 @@ static int fl_intern(struct ip6_flowlabel *fl, __u32 label) /* Socket flowlabel lists */ -struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, u32 label) +struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label) { struct ipv6_fl_socklist *sfl; struct ipv6_pinfo *np = inet6_sk(sk); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 66716911962e..9ff1be1bc2e7 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -217,7 +217,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, if (tclass < 0) tclass = 0; - *(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; + *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; hdr->payload_len = htons(seg_len); hdr->nexthdr = proto; @@ -1311,7 +1311,7 @@ int ip6_push_pending_frames(struct sock *sk) skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr)); - *(u32*)hdr = fl->fl6_flowlabel | + *(__be32*)hdr = fl->fl6_flowlabel | htonl(0x60000000 | ((int)np->cork.tclass << 20)); if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 6a3026dd865a..4919f9294e2a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -665,9 +665,9 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) dsfield = ipv6_get_dsfield(ipv6h); if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) - fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK); + fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)) - fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK); + fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); if (encap_limit >= 0 && (opt = create_tel(encap_limit)) == NULL) goto tx_err; @@ -735,7 +735,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) skb->nh.raw = skb_push(skb, sizeof(struct ipv6hdr)); ipv6h = skb->nh.ipv6h; - *(u32*)ipv6h = fl.fl6_flowlabel | htonl(0x60000000); + *(__be32*)ipv6h = fl.fl6_flowlabel | htonl(0x60000000); dsfield = INET_ECN_encapsulate(0, dsfield); ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b39ae99122d5..e9c1fc5f21b1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -714,7 +714,7 @@ void ip6_route_input(struct sk_buff *skb) #ifdef CONFIG_IPV6_ROUTE_FWMARK .fwmark = skb->nfmark, #endif - .flowlabel = (* (u32 *) iph)&IPV6_FLOWINFO_MASK, + .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, }, }, .proto = iph->nexthdr, -- cgit v1.2.3-71-gd317 From 0e11c91e1e912bc4db5b71607d149e7e9a77e756 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:26:29 -0800 Subject: [AF_PACKET]: annotate Weirdness: the third argument of socket() is net-endian here. Oh, well - it's documented in packet(7). Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/if_packet.h | 6 ++++-- net/packet/af_packet.c | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index b92558549d27..99393ef3af39 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -1,17 +1,19 @@ #ifndef __LINUX_IF_PACKET_H #define __LINUX_IF_PACKET_H +#include + struct sockaddr_pkt { unsigned short spkt_family; unsigned char spkt_device[14]; - unsigned short spkt_protocol; + __be16 spkt_protocol; }; struct sockaddr_ll { unsigned short sll_family; - unsigned short sll_protocol; + __be16 sll_protocol; int sll_ifindex; unsigned short sll_hatype; unsigned char sll_pkttype; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f4ccb90e6739..271d2eed0699 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -201,7 +201,7 @@ struct packet_sock { spinlock_t bind_lock; char running; /* prot_hook is attached*/ int ifindex; /* bound device */ - unsigned short num; + __be16 num; #ifdef CONFIG_PACKET_MULTICAST struct packet_mclist *mclist; #endif @@ -331,7 +331,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name; struct sk_buff *skb; struct net_device *dev; - unsigned short proto=0; + __be16 proto=0; int err; /* @@ -704,7 +704,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name; struct sk_buff *skb; struct net_device *dev; - unsigned short proto; + __be16 proto; unsigned char *addr; int ifindex, err, reserve = 0; @@ -858,7 +858,7 @@ static int packet_release(struct socket *sock) * Attach a packet hook. */ -static int packet_do_bind(struct sock *sk, struct net_device *dev, int protocol) +static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol) { struct packet_sock *po = pkt_sk(sk); /* @@ -983,6 +983,7 @@ static int packet_create(struct socket *sock, int protocol) { struct sock *sk; struct packet_sock *po; + __be16 proto = (__force __be16)protocol; /* weird, but documented */ int err; if (!capable(CAP_NET_RAW)) @@ -1010,7 +1011,7 @@ static int packet_create(struct socket *sock, int protocol) po = pkt_sk(sk); sk->sk_family = PF_PACKET; - po->num = protocol; + po->num = proto; sk->sk_destruct = packet_sock_destruct; atomic_inc(&packet_socks_nr); @@ -1027,8 +1028,8 @@ static int packet_create(struct socket *sock, int protocol) #endif po->prot_hook.af_packet_priv = sk; - if (protocol) { - po->prot_hook.type = protocol; + if (proto) { + po->prot_hook.type = proto; dev_add_pack(&po->prot_hook); sock_hold(sk); po->running = 1; @@ -1624,7 +1625,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing { char **pg_vec = NULL; struct packet_sock *po = pkt_sk(sk); - int was_running, num, order = 0; + int was_running, order = 0; + __be16 num; int err = 0; if (req->tp_block_nr) { -- cgit v1.2.3-71-gd317 From 98a4a86128d7179b22365e16bf880e849e20bc7d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:26:51 -0800 Subject: [NETFILTER]: trivial annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink.h | 2 +- include/linux/netfilter/nfnetlink_log.h | 10 +++++----- include/linux/netfilter/nfnetlink_queue.h | 18 +++++++++--------- include/linux/netfilter/xt_conntrack.h | 4 ++-- include/linux/netfilter/xt_policy.h | 2 +- include/linux/types.h | 2 ++ net/netfilter/nfnetlink_log.c | 22 ++++++++++------------ net/netfilter/nfnetlink_queue.c | 9 ++++----- net/netfilter/xt_multiport.c | 4 ++-- 9 files changed, 36 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 6d8e3e5a80e9..1e9c821f152d 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -78,7 +78,7 @@ struct nfattr struct nfgenmsg { u_int8_t nfgen_family; /* AF_xxx */ u_int8_t version; /* nfnetlink version */ - u_int16_t res_id; /* resource id */ + __be16 res_id; /* resource id */ }; #define NFNETLINK_V0 0 diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h index 87b92f8b988f..55a2a2b814ed 100644 --- a/include/linux/netfilter/nfnetlink_log.h +++ b/include/linux/netfilter/nfnetlink_log.h @@ -16,20 +16,20 @@ enum nfulnl_msg_types { }; struct nfulnl_msg_packet_hdr { - u_int16_t hw_protocol; /* hw protocol (network order) */ + __be16 hw_protocol; /* hw protocol (network order) */ u_int8_t hook; /* netfilter hook */ u_int8_t _pad; }; struct nfulnl_msg_packet_hw { - u_int16_t hw_addrlen; + __be16 hw_addrlen; u_int16_t _pad; u_int8_t hw_addr[8]; }; struct nfulnl_msg_packet_timestamp { - aligned_u64 sec; - aligned_u64 usec; + aligned_be64 sec; + aligned_be64 usec; }; #define NFULNL_PREFIXLEN 30 /* just like old log target */ @@ -67,7 +67,7 @@ struct nfulnl_msg_config_cmd { } __attribute__ ((packed)); struct nfulnl_msg_config_mode { - u_int32_t copy_range; + __be32 copy_range; u_int8_t copy_mode; u_int8_t _pad; } __attribute__ ((packed)); diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h index 36af0360b56d..4beea3d6fda8 100644 --- a/include/linux/netfilter/nfnetlink_queue.h +++ b/include/linux/netfilter/nfnetlink_queue.h @@ -13,20 +13,20 @@ enum nfqnl_msg_types { }; struct nfqnl_msg_packet_hdr { - u_int32_t packet_id; /* unique ID of packet in queue */ - u_int16_t hw_protocol; /* hw protocol (network order) */ + __be32 packet_id; /* unique ID of packet in queue */ + __be16 hw_protocol; /* hw protocol (network order) */ u_int8_t hook; /* netfilter hook */ } __attribute__ ((packed)); struct nfqnl_msg_packet_hw { - u_int16_t hw_addrlen; + __be16 hw_addrlen; u_int16_t _pad; u_int8_t hw_addr[8]; }; struct nfqnl_msg_packet_timestamp { - aligned_u64 sec; - aligned_u64 usec; + aligned_be64 sec; + aligned_be64 usec; }; enum nfqnl_attr_type { @@ -47,8 +47,8 @@ enum nfqnl_attr_type { #define NFQA_MAX (__NFQA_MAX - 1) struct nfqnl_msg_verdict_hdr { - u_int32_t verdict; - u_int32_t id; + __be32 verdict; + __be32 id; }; @@ -63,7 +63,7 @@ enum nfqnl_msg_config_cmds { struct nfqnl_msg_config_cmd { u_int8_t command; /* nfqnl_msg_config_cmds */ u_int8_t _pad; - u_int16_t pf; /* AF_xxx for PF_[UN]BIND */ + __be16 pf; /* AF_xxx for PF_[UN]BIND */ }; enum nfqnl_config_mode { @@ -73,7 +73,7 @@ enum nfqnl_config_mode { }; struct nfqnl_msg_config_params { - u_int32_t copy_range; + __be32 copy_range; u_int8_t copy_mode; /* enum nfqnl_config_mode */ } __attribute__ ((packed)); diff --git a/include/linux/netfilter/xt_conntrack.h b/include/linux/netfilter/xt_conntrack.h index 4c2d9945ca54..70b6f718cf4c 100644 --- a/include/linux/netfilter/xt_conntrack.h +++ b/include/linux/netfilter/xt_conntrack.h @@ -29,14 +29,14 @@ struct ip_conntrack_old_tuple { struct { - __u32 ip; + __be32 ip; union { __u16 all; } u; } src; struct { - __u32 ip; + __be32 ip; union { __u16 all; } u; diff --git a/include/linux/netfilter/xt_policy.h b/include/linux/netfilter/xt_policy.h index a8132ec076fb..45654d359a68 100644 --- a/include/linux/netfilter/xt_policy.h +++ b/include/linux/netfilter/xt_policy.h @@ -39,7 +39,7 @@ struct xt_policy_elem union xt_policy_addr smask; union xt_policy_addr daddr; union xt_policy_addr dmask; - u_int32_t spi; + __be32 spi; u_int32_t reqid; u_int8_t proto; u_int8_t mode; diff --git a/include/linux/types.h b/include/linux/types.h index 750f085fa564..9f11fdd2bd72 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -128,6 +128,8 @@ typedef __s64 int64_t; /* this is a special 64bit data type that is 8-byte aligned */ #define aligned_u64 unsigned long long __attribute__((aligned(8))) +#define aligned_be64 __be64 __attribute__((aligned(8))) +#define aligned_le64 __le64 __attribute__((aligned(8))) /** * The type used for indexing onto a disc or disc partition. diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 1e5207b80fe5..856ed0d19974 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -414,7 +414,7 @@ __build_packet_message(struct nfulnl_instance *inst, struct nfulnl_msg_packet_hdr pmsg; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - u_int32_t tmp_uint; + __be32 tmp_uint; UDEBUG("entered\n"); @@ -508,11 +508,9 @@ __build_packet_message(struct nfulnl_instance *inst, if (indev && skb->dev && skb->dev->hard_header_parse) { struct nfulnl_msg_packet_hw phw; - - phw.hw_addrlen = - skb->dev->hard_header_parse((struct sk_buff *)skb, + int len = skb->dev->hard_header_parse((struct sk_buff *)skb, phw.hw_addr); - phw.hw_addrlen = htons(phw.hw_addrlen); + phw.hw_addrlen = htons(len); NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); } @@ -529,7 +527,7 @@ __build_packet_message(struct nfulnl_instance *inst, if (skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) { - u_int32_t uid = htonl(skb->sk->sk_socket->file->f_uid); + __be32 uid = htonl(skb->sk->sk_socket->file->f_uid); /* need to unlock here since NFA_PUT may goto */ read_unlock_bh(&skb->sk->sk_callback_lock); NFA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid); @@ -882,15 +880,15 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } if (nfula[NFULA_CFG_TIMEOUT-1]) { - u_int32_t timeout = - *(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_TIMEOUT-1]); + __be32 timeout = + *(__be32 *)NFA_DATA(nfula[NFULA_CFG_TIMEOUT-1]); nfulnl_set_timeout(inst, ntohl(timeout)); } if (nfula[NFULA_CFG_NLBUFSIZ-1]) { - u_int32_t nlbufsiz = - *(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_NLBUFSIZ-1]); + __be32 nlbufsiz = + *(__be32 *)NFA_DATA(nfula[NFULA_CFG_NLBUFSIZ-1]); nfulnl_set_nlbufsiz(inst, ntohl(nlbufsiz)); } @@ -903,8 +901,8 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } if (nfula[NFULA_CFG_FLAGS-1]) { - u_int16_t flags = - *(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]); + __be16 flags = + *(__be16 *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]); nfulnl_set_flags(inst, ntohs(flags)); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index e815a9aa6e95..4ab7b1416bb5 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -349,7 +349,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, struct sk_buff *entskb = entry->skb; struct net_device *indev; struct net_device *outdev; - unsigned int tmp_uint; + __be32 tmp_uint; QDEBUG("entered\n"); @@ -489,10 +489,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, && entskb->dev->hard_header_parse) { struct nfqnl_msg_packet_hw phw; - phw.hw_addrlen = - entskb->dev->hard_header_parse(entskb, + int len = entskb->dev->hard_header_parse(entskb, phw.hw_addr); - phw.hw_addrlen = htons(phw.hw_addrlen); + phw.hw_addrlen = htons(len); NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); } @@ -835,7 +834,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, } if (nfqa[NFQA_MARK-1]) - entry->skb->nfmark = ntohl(*(u_int32_t *) + entry->skb->nfmark = ntohl(*(__be32 *) NFA_DATA(nfqa[NFQA_MARK-1])); issue_verdict(entry, verdict); diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index d3aefd380930..b4293058c6ff 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c @@ -104,7 +104,7 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - u16 _ports[2], *pptr; + __be16 _ports[2], *pptr; const struct xt_multiport *multiinfo = matchinfo; if (offset) @@ -135,7 +135,7 @@ match_v1(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - u16 _ports[2], *pptr; + __be16 _ports[2], *pptr; const struct xt_multiport_v1 *multiinfo = matchinfo; if (offset) -- cgit v1.2.3-71-gd317 From ae08e1f092210619fe49551aa3ed0dc0003d5880 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 8 Nov 2006 00:27:11 -0800 Subject: [IPV6]: ip6_output annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 +- net/ipv6/ip6_output.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 85577a4ffa61..7fc9a3aaa1c9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -139,7 +139,7 @@ struct skb_shared_info { /* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; unsigned short gso_type; - unsigned int ip6_frag_id; + __be32 ip6_frag_id; struct sk_buff *frag_list; skb_frag_t frags[MAX_SKB_FRAGS]; }; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9ff1be1bc2e7..93330685adfc 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -267,7 +267,7 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr)); skb->nh.ipv6h = hdr; - *(u32*)hdr = htonl(0x60000000); + *(__be32*)hdr = htonl(0x60000000); hdr->payload_len = htons(len); hdr->nexthdr = proto; @@ -571,7 +571,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; unsigned int mtu, hlen, left, len; - u32 frag_id = 0; + __be32 frag_id = 0; int ptr, offset = 0, err=0; u8 *prevhdr, nexthdr = 0; -- cgit v1.2.3-71-gd317 From c1a856c9640c9ff3d70bbd8214b6a0974609eef8 Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Wed, 8 Nov 2006 17:03:44 -0600 Subject: SELinux: Various xfrm labeling fixes Since the upstreaming of the mlsxfrm modification a few months back, testing has resulted in the identification of the following issues/bugs that are resolved in this patch set. 1. Fix the security context used in the IKE negotiation to be the context of the socket as opposed to the context of the SPD rule. 2. Fix SO_PEERSEC for tcp sockets to return the security context of the peer as opposed to the source. 3. Fix the selection of an SA for an outgoing packet to be at the same context as the originating socket/flow. The following would be the result of applying this patchset: - SO_PEERSEC will now correctly return the peer's context. - IKE deamons will receive the context of the source socket/flow as opposed to the SPD rule's context so that the negotiated SA will be at the same context as the source socket/flow. - The SELinux policy will require one or more of the following for a socket to be able to communicate with/without SAs: 1. To enable a socket to communicate without using labeled-IPSec SAs: allow socket_t unlabeled_t:association { sendto recvfrom } 2. To enable a socket to communicate with labeled-IPSec SAs: allow socket_t self:association { sendto }; allow socket_t peer_sa_t:association { recvfrom }; This Patch: Pass correct security context to IKE for use in negotiation Fix the security context passed to IKE for use in negotiation to be the context of the socket as opposed to the context of the SPD rule so that the SA carries the label of the originating socket/flow. Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- include/linux/security.h | 21 ++++++++++----------- security/dummy.c | 4 ++-- security/selinux/include/xfrm.h | 4 ++-- security/selinux/xfrm.c | 35 +++++++++-------------------------- 4 files changed, 23 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index b200b9856f32..a509329a669b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -836,10 +836,8 @@ struct request_sock; * used by the XFRM system. * @sec_ctx contains the security context information being provided by * the user-level policy update program (e.g., setkey). - * @sk refers to the sock from which to derive the security context. * Allocate a security structure to the xp->security field; the security - * field is initialized to NULL when the xfrm_policy is allocated. Only - * one of sec_ctx or sock can be specified. + * field is initialized to NULL when the xfrm_policy is allocated. * Return 0 if operation was successful (memory to allocate, legal context) * @xfrm_policy_clone_security: * @old contains an existing xfrm_policy in the SPD. @@ -858,9 +856,6 @@ struct request_sock; * Database by the XFRM system. * @sec_ctx contains the security context information being provided by * the user-level SA generation program (e.g., setkey or racoon). - * @polsec contains the security context information associated with a xfrm - * policy rule from which to take the base context. polsec must be NULL - * when sec_ctx is specified. * @secid contains the secid from which to take the mls portion of the context. * Allocate a security structure to the x->security field; the security * field is initialized to NULL when the xfrm_state is allocated. Set the @@ -1378,12 +1373,12 @@ struct security_operations { #ifdef CONFIG_SECURITY_NETWORK_XFRM int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); + struct xfrm_user_sec_ctx *sec_ctx); int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); void (*xfrm_policy_free_security) (struct xfrm_policy *xp); int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); int (*xfrm_state_alloc_security) (struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *polsec, + struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void (*xfrm_state_free_security) (struct xfrm_state *x); int (*xfrm_state_delete_security) (struct xfrm_state *x); @@ -3120,7 +3115,7 @@ static inline void security_inet_csk_clone(struct sock *newsk, #ifdef CONFIG_SECURITY_NETWORK_XFRM static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) { - return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL); + return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); } static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) @@ -3141,7 +3136,7 @@ static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) { - return security_ops->xfrm_state_alloc_security(x, sec_ctx, NULL, 0); + return security_ops->xfrm_state_alloc_security(x, sec_ctx, 0); } static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, @@ -3149,7 +3144,11 @@ static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, { if (!polsec) return 0; - return security_ops->xfrm_state_alloc_security(x, NULL, polsec, secid); + /* + * We want the context to be taken from secid which is usually + * from the sock. + */ + return security_ops->xfrm_state_alloc_security(x, NULL, secid); } static inline int security_xfrm_state_delete(struct xfrm_state *x) diff --git a/security/dummy.c b/security/dummy.c index 43874c1e6e23..838d8442cf3c 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -836,7 +836,7 @@ static inline void dummy_req_classify_flow(const struct request_sock *req, #ifdef CONFIG_SECURITY_NETWORK_XFRM static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk) + struct xfrm_user_sec_ctx *sec_ctx) { return 0; } @@ -856,7 +856,7 @@ static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) } static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid) + struct xfrm_user_sec_ctx *sec_ctx, u32 secid) { return 0; } diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 526b28019aca..8e329ddb5e37 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -8,12 +8,12 @@ #define _SELINUX_XFRM_H_ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); + struct xfrm_user_sec_ctx *sec_ctx); int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); void selinux_xfrm_policy_free(struct xfrm_policy *xp); int selinux_xfrm_policy_delete(struct xfrm_policy *xp); int selinux_xfrm_state_alloc(struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid); + struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void selinux_xfrm_state_free(struct xfrm_state *x); int selinux_xfrm_state_delete(struct xfrm_state *x); int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 675b995a67c3..4d5a043cdfa1 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -226,16 +226,15 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) * CTX does not have a meaningful value on input */ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, - struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid) + struct xfrm_user_sec_ctx *uctx, u32 sid) { int rc = 0; struct task_security_struct *tsec = current->security; struct xfrm_sec_ctx *ctx = NULL; char *ctx_str = NULL; u32 str_len; - u32 ctx_sid; - BUG_ON(uctx && pol); + BUG_ON(uctx && sid); if (!uctx) goto not_from_user; @@ -279,15 +278,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, return rc; not_from_user: - if (pol) { - rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid); - if (rc) - goto out; - } - else - ctx_sid = sid; - - rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len); + rc = security_sid_to_context(sid, &ctx_str, &str_len); if (rc) goto out; @@ -302,7 +293,7 @@ not_from_user: ctx->ctx_doi = XFRM_SC_DOI_LSM; ctx->ctx_alg = XFRM_SC_ALG_SELINUX; - ctx->ctx_sid = ctx_sid; + ctx->ctx_sid = sid; ctx->ctx_len = str_len; memcpy(ctx->ctx_str, ctx_str, @@ -323,22 +314,14 @@ out2: * xfrm_policy. */ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *uctx, struct sock *sk) + struct xfrm_user_sec_ctx *uctx) { int err; - u32 sid; BUG_ON(!xp); - BUG_ON(uctx && sk); - - if (sk) { - struct sk_security_struct *ssec = sk->sk_security; - sid = ssec->sid; - } - else - sid = SECSID_NULL; + BUG_ON(!uctx); - err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, sid); + err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); return err; } @@ -399,13 +382,13 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp) * xfrm_state. */ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, - struct xfrm_sec_ctx *pol, u32 secid) + u32 secid) { int err; BUG_ON(!x); - err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid); + err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); return err; } -- cgit v1.2.3-71-gd317 From 6b877699c6f1efede4545bcecc367786a472eedb Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Wed, 8 Nov 2006 17:04:09 -0600 Subject: SELinux: Return correct context for SO_PEERSEC Fix SO_PEERSEC for tcp sockets to return the security context of the peer (as represented by the SA from the peer) as opposed to the SA used by the local/source socket. Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- include/linux/security.h | 16 +++++++++++++++- include/net/request_sock.h | 1 + net/ipv4/tcp_input.c | 2 ++ security/dummy.c | 6 ++++++ security/selinux/hooks.c | 21 +++++++++++++++++---- security/selinux/include/xfrm.h | 12 ++++++------ security/selinux/xfrm.c | 40 +++------------------------------------- 7 files changed, 50 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index a509329a669b..84cebcdb3f83 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -826,6 +826,8 @@ struct request_sock; * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid. * @inet_csk_clone: * Sets the new child socket's sid to the openreq sid. + * @inet_conn_established: + * Sets the connection's peersid to the secmark on skb. * @req_classify_flow: * Sets the flow's sid to the openreq sid. * @@ -1368,6 +1370,7 @@ struct security_operations { int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb, struct request_sock *req); void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req); + void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb); void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl); #endif /* CONFIG_SECURITY_NETWORK */ @@ -2961,9 +2964,15 @@ static inline void security_inet_csk_clone(struct sock *newsk, { security_ops->inet_csk_clone(newsk, req); } + +static inline void security_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ + security_ops->inet_conn_established(sk, skb); +} #else /* CONFIG_SECURITY_NETWORK */ static inline int security_unix_stream_connect(struct socket * sock, - struct socket * other, + struct socket * other, struct sock * newsk) { return 0; @@ -3110,6 +3119,11 @@ static inline void security_inet_csk_clone(struct sock *newsk, const struct request_sock *req) { } + +static inline void security_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ +} #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 8e165ca16bd8..f743a941a4f2 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -54,6 +54,7 @@ struct request_sock { struct request_sock_ops *rsk_ops; struct sock *sk; u32 secid; + u32 peer_secid; }; static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cf06accbe687..4a8c96cdec7d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4230,6 +4230,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, mb(); tcp_set_state(sk, TCP_ESTABLISHED); + security_inet_conn_established(sk, skb); + /* Make sure socket is routed, for correct metrics. */ icsk->icsk_af_ops->rebuild_header(sk); diff --git a/security/dummy.c b/security/dummy.c index 838d8442cf3c..0148d1518dd1 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -828,6 +828,11 @@ static inline void dummy_inet_csk_clone(struct sock *newsk, { } +static inline void dummy_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ +} + static inline void dummy_req_classify_flow(const struct request_sock *req, struct flowi *fl) { @@ -1108,6 +1113,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, sock_graft); set_to_dummy_if_null(ops, inet_conn_request); set_to_dummy_if_null(ops, inet_csk_clone); + set_to_dummy_if_null(ops, inet_conn_established); set_to_dummy_if_null(ops, req_classify_flow); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 28ee187ed224..5bbd599a4471 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3535,8 +3535,10 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op } else if (isec->sclass == SECCLASS_TCP_SOCKET) { peer_sid = selinux_netlbl_socket_getpeersec_stream(sock); - if (peer_sid == SECSID_NULL) - peer_sid = selinux_socket_getpeer_stream(sock->sk); + if (peer_sid == SECSID_NULL) { + ssec = sock->sk->sk_security; + peer_sid = ssec->peer_sid; + } if (peer_sid == SECSID_NULL) { err = -ENOPROTOOPT; goto out; @@ -3647,11 +3649,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, return 0; } - err = selinux_xfrm_decode_session(skb, &peersid, 0); - BUG_ON(err); + selinux_skb_xfrm_sid(skb, &peersid); if (peersid == SECSID_NULL) { req->secid = sksec->sid; + req->peer_secid = 0; return 0; } @@ -3660,6 +3662,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, return err; req->secid = newsid; + req->peer_secid = peersid; return 0; } @@ -3669,6 +3672,7 @@ static void selinux_inet_csk_clone(struct sock *newsk, struct sk_security_struct *newsksec = newsk->sk_security; newsksec->sid = req->secid; + newsksec->peer_sid = req->peer_secid; /* NOTE: Ideally, we should also get the isec->sid for the new socket in sync, but we don't have the isec available yet. So we will wait until sock_graft to do it, by which @@ -3677,6 +3681,14 @@ static void selinux_inet_csk_clone(struct sock *newsk, selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family); } +static void selinux_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ + struct sk_security_struct *sksec = sk->sk_security; + + selinux_skb_xfrm_sid(skb, &sksec->peer_sid); +} + static void selinux_req_classify_flow(const struct request_sock *req, struct flowi *fl) { @@ -4739,6 +4751,7 @@ static struct security_operations selinux_ops = { .sock_graft = selinux_sock_graft, .inet_conn_request = selinux_inet_conn_request, .inet_csk_clone = selinux_inet_csk_clone, + .inet_conn_established = selinux_inet_conn_established, .req_classify_flow = selinux_req_classify_flow, #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 8e329ddb5e37..27502365d706 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -39,7 +39,6 @@ int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, struct avc_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, struct avc_audit_data *ad); -u32 selinux_socket_getpeer_stream(struct sock *sk); u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); #else @@ -55,11 +54,6 @@ static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, return 0; } -static inline int selinux_socket_getpeer_stream(struct sock *sk) -{ - return SECSID_NULL; -} - static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb) { return SECSID_NULL; @@ -71,4 +65,10 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int } #endif +static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid) +{ + int err = selinux_xfrm_decode_session(skb, sid, 0); + BUG_ON(err); +} + #endif /* _SELINUX_XFRM_H_ */ diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 4d5a043cdfa1..8fef74271f22 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -184,7 +184,8 @@ int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, } /* - * LSM hook implementation that determines the sid for the session. + * LSM hook implementation that checks and/or returns the xfrm sid for the + * incoming packet. */ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) @@ -402,44 +403,9 @@ void selinux_xfrm_state_free(struct xfrm_state *x) kfree(ctx); } -/* - * SELinux internal function to retrieve the context of a connected - * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security - * association used to connect to the remote socket. - * - * Retrieve via getsockopt SO_PEERSEC. - */ -u32 selinux_socket_getpeer_stream(struct sock *sk) -{ - struct dst_entry *dst, *dst_test; - u32 peer_sid = SECSID_NULL; - - if (sk->sk_state != TCP_ESTABLISHED) - goto out; - - dst = sk_dst_get(sk); - if (!dst) - goto out; - - for (dst_test = dst; dst_test != 0; - dst_test = dst_test->child) { - struct xfrm_state *x = dst_test->xfrm; - - if (x && selinux_authorizable_xfrm(x)) { - struct xfrm_sec_ctx *ctx = x->security; - peer_sid = ctx->ctx_sid; - break; - } - } - dst_release(dst); - -out: - return peer_sid; -} - /* * SELinux internal function to retrieve the context of a UDP packet - * based on its security association used to connect to the remote socket. + * based on its security association. * * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message * type SCM_SECURITY. -- cgit v1.2.3-71-gd317 From 67f83cbf081a70426ff667e8d14f94e13ed3bdca Mon Sep 17 00:00:00 2001 From: Venkat Yekkirala Date: Wed, 8 Nov 2006 17:04:26 -0600 Subject: SELinux: Fix SA selection semantics Fix the selection of an SA for an outgoing packet to be at the same context as the originating socket/flow. This eliminates the SELinux policy's ability to use/sendto SAs with contexts other than the socket's. With this patch applied, the SELinux policy will require one or more of the following for a socket to be able to communicate with/without SAs: 1. To enable a socket to communicate without using labeled-IPSec SAs: allow socket_t unlabeled_t:association { sendto recvfrom } 2. To enable a socket to communicate with labeled-IPSec SAs: allow socket_t self:association { sendto }; allow socket_t peer_sa_t:association { recvfrom }; Signed-off-by: Venkat Yekkirala Signed-off-by: James Morris --- include/linux/security.h | 19 -------- net/xfrm/xfrm_policy.c | 3 +- security/dummy.c | 7 --- security/selinux/hooks.c | 26 +++++++---- security/selinux/include/xfrm.h | 7 +-- security/selinux/xfrm.c | 101 +++++++++++++++++++--------------------- 6 files changed, 70 insertions(+), 93 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index 84cebcdb3f83..83cdefae9931 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -886,11 +886,6 @@ struct request_sock; * @xp contains the policy to check for a match. * @fl contains the flow to check for a match. * Return 1 if there is a match. - * @xfrm_flow_state_match: - * @fl contains the flow key to match. - * @xfrm points to the xfrm_state to match. - * @xp points to the xfrm_policy to match. - * Return 1 if there is a match. * @xfrm_decode_session: * @skb points to skb to decode. * @secid points to the flow key secid to set. @@ -1388,8 +1383,6 @@ struct security_operations { int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); - int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp); int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); #endif /* CONFIG_SECURITY_NETWORK_XFRM */ @@ -3186,12 +3179,6 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, return security_ops->xfrm_state_pol_flow_match(x, xp, fl); } -static inline int security_xfrm_flow_state_match(struct flowi *fl, - struct xfrm_state *xfrm, struct xfrm_policy *xp) -{ - return security_ops->xfrm_flow_state_match(fl, xfrm, xp); -} - static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) { return security_ops->xfrm_decode_session(skb, secid, 1); @@ -3255,12 +3242,6 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, return 1; } -static inline int security_xfrm_flow_state_match(struct flowi *fl, - struct xfrm_state *xfrm, struct xfrm_policy *xp) -{ - return 1; -} - static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) { return 0; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 7736b23c3f03..b88b038530c9 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1894,7 +1894,8 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) return 0; - if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol)) + if (fl && pol && + !security_xfrm_state_pol_flow_match(dst->xfrm, pol, fl)) return 0; if (dst->xfrm->km.state != XFRM_STATE_VALID) return 0; diff --git a/security/dummy.c b/security/dummy.c index 0148d1518dd1..558795b237d6 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -886,12 +886,6 @@ static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x, return 1; } -static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp) -{ - return 1; -} - static int dummy_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall) { return 0; @@ -1126,7 +1120,6 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, xfrm_state_delete_security); set_to_dummy_if_null(ops, xfrm_policy_lookup); set_to_dummy_if_null(ops, xfrm_state_pol_flow_match); - set_to_dummy_if_null(ops, xfrm_flow_state_match); set_to_dummy_if_null(ops, xfrm_decode_session); #endif /* CONFIG_SECURITY_NETWORK_XFRM */ #ifdef CONFIG_KEYS diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5bbd599a4471..956137baf3e7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2889,7 +2889,8 @@ static void selinux_task_to_inode(struct task_struct *p, } /* Returns error only if unable to parse addresses */ -static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad) +static int selinux_parse_skb_ipv4(struct sk_buff *skb, + struct avc_audit_data *ad, u8 *proto) { int offset, ihlen, ret = -EINVAL; struct iphdr _iph, *ih; @@ -2907,6 +2908,9 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad ad->u.net.v4info.daddr = ih->daddr; ret = 0; + if (proto) + *proto = ih->protocol; + switch (ih->protocol) { case IPPROTO_TCP: { struct tcphdr _tcph, *th; @@ -2950,7 +2954,8 @@ out: #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) /* Returns error only if unable to parse addresses */ -static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad) +static int selinux_parse_skb_ipv6(struct sk_buff *skb, + struct avc_audit_data *ad, u8 *proto) { u8 nexthdr; int ret = -EINVAL, offset; @@ -2971,6 +2976,9 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad if (offset < 0) goto out; + if (proto) + *proto = nexthdr; + switch (nexthdr) { case IPPROTO_TCP: { struct tcphdr _tcph, *th; @@ -3007,13 +3015,13 @@ out: #endif /* IPV6 */ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, - char **addrp, int *len, int src) + char **addrp, int *len, int src, u8 *proto) { int ret = 0; switch (ad->u.net.family) { case PF_INET: - ret = selinux_parse_skb_ipv4(skb, ad); + ret = selinux_parse_skb_ipv4(skb, ad, proto); if (ret || !addrp) break; *len = 4; @@ -3023,7 +3031,7 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case PF_INET6: - ret = selinux_parse_skb_ipv6(skb, ad); + ret = selinux_parse_skb_ipv6(skb, ad, proto); if (ret || !addrp) break; *len = 16; @@ -3494,7 +3502,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; ad.u.net.family = family; - err = selinux_parse_skb(skb, &ad, &addrp, &len, 1); + err = selinux_parse_skb(skb, &ad, &addrp, &len, 1, NULL); if (err) goto out; @@ -3820,6 +3828,7 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, struct avc_audit_data ad; struct net_device *dev = (struct net_device *)out; struct sk_security_struct *sksec; + u8 proto; sk = skb->sk; if (!sk) @@ -3831,7 +3840,7 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, ad.u.net.netif = dev->name; ad.u.net.family = family; - err = selinux_parse_skb(skb, &ad, &addrp, &len, 0); + err = selinux_parse_skb(skb, &ad, &addrp, &len, 0, &proto); if (err) goto out; @@ -3845,7 +3854,7 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, if (err) goto out; - err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad); + err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto); out: return err ? NF_DROP : NF_ACCEPT; } @@ -4764,7 +4773,6 @@ static struct security_operations selinux_ops = { .xfrm_state_delete_security = selinux_xfrm_state_delete, .xfrm_policy_lookup = selinux_xfrm_policy_lookup, .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match, - .xfrm_flow_state_match = selinux_xfrm_flow_state_match, .xfrm_decode_session = selinux_xfrm_decode_session, #endif diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 27502365d706..ebd7246a4be5 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -19,9 +19,6 @@ int selinux_xfrm_state_delete(struct xfrm_state *x); int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); -int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp); - /* * Extract the security blob from the sock (it's actually on the socket) @@ -38,7 +35,7 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk) int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, struct avc_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad); + struct avc_audit_data *ad, u8 proto); u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); #else @@ -49,7 +46,7 @@ static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, } static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct avc_audit_data *ad, u8 proto) { return 0; } diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 8fef74271f22..9b777140068f 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -115,71 +115,40 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * struct flowi *fl) { u32 state_sid; - u32 pol_sid; - int err; + int rc; - if (xp->security) { - if (!x->security) - /* unlabeled SA and labeled policy can't match */ - return 0; - else - state_sid = x->security->ctx_sid; - pol_sid = xp->security->ctx_sid; - } else + if (!xp->security) if (x->security) /* unlabeled policy and labeled SA can't match */ return 0; else /* unlabeled policy and unlabeled SA match all flows */ return 1; - - err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, - ASSOCIATION__POLMATCH, - NULL); - - if (err) - return 0; - - err = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, - ASSOCIATION__SENDTO, - NULL)? 0:1; - - return err; -} - -/* - * LSM hook implementation that authorizes that a particular outgoing flow - * can use a given security association. - */ - -int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, - struct xfrm_policy *xp) -{ - int rc = 0; - u32 sel_sid = SECINITSID_UNLABELED; - struct xfrm_sec_ctx *ctx; - - if (!xp->security) - if (!xfrm->security) - return 1; - else - return 0; else - if (!xfrm->security) + if (!x->security) + /* unlabeled SA and labeled policy can't match */ return 0; + else + if (!selinux_authorizable_xfrm(x)) + /* Not a SELinux-labeled SA */ + return 0; - /* Context sid is either set to label or ANY_ASSOC */ - if ((ctx = xfrm->security)) { - if (!selinux_authorizable_ctx(ctx)) - return 0; + state_sid = x->security->ctx_sid; - sel_sid = ctx->ctx_sid; - } + if (fl->secid != state_sid) + return 0; - rc = avc_has_perm(fl->secid, sel_sid, SECCLASS_ASSOCIATION, + rc = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, NULL)? 0:1; + /* + * We don't need a separate SA Vs. policy polmatch check + * since the SA is now of the same label as the flow and + * a flow Vs. policy polmatch check had already happened + * in selinux_xfrm_policy_lookup() above. + */ + return rc; } @@ -481,6 +450,13 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, } } + /* + * This check even when there's no association involved is + * intended, according to Trent Jaeger, to make sure a + * process can't engage in non-ipsec communication unless + * explicitly allowed by policy. + */ + rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad); @@ -492,10 +468,10 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, * If we have no security association, then we need to determine * whether the socket is allowed to send to an unlabelled destination. * If we do have a authorizable security association, then it has already been - * checked in xfrm_policy_lookup hook. + * checked in the selinux_xfrm_state_pol_flow_match hook above. */ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct avc_audit_data *ad, u8 proto) { struct dst_entry *dst; int rc = 0; @@ -514,6 +490,27 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, } } + switch (proto) { + case IPPROTO_AH: + case IPPROTO_ESP: + case IPPROTO_COMP: + /* + * We should have already seen this packet once before + * it underwent xfrm(s). No need to subject it to the + * unlabeled check. + */ + goto out; + default: + break; + } + + /* + * This check even when there's no association involved is + * intended, according to Trent Jaeger, to make sure a + * process can't engage in non-ipsec communication unless + * explicitly allowed by policy. + */ + rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad); out: -- cgit v1.2.3-71-gd317 From 82e91ffef60e6eba9848fe149ce1eecd2b5aef12 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:19:14 -0800 Subject: [NET]: Turn nfmark into generic mark nfmark is being used in various subsystems and has become the defacto mark field for all kinds of packets. Therefore it makes sense to rename it to `mark' and remove the dependency on CONFIG_NETFILTER. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- net/bridge/netfilter/ebt_mark.c | 8 ++++---- net/bridge/netfilter/ebt_mark_m.c | 4 ++-- net/bridge/netfilter/ebt_ulog.c | 2 +- net/core/skbuff.c | 4 ++-- net/decnet/dn_route.c | 4 ++-- net/ipv4/ip_output.c | 2 +- net/ipv4/ipvs/ip_vs_proto_tcp.c | 2 +- net/ipv4/ipvs/ip_vs_proto_udp.c | 2 +- net/ipv4/netfilter.c | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv4/netfilter/ipt_REJECT.c | 2 +- net/ipv4/netfilter/ipt_ULOG.c | 2 +- net/ipv4/netfilter/iptable_mangle.c | 6 +++--- net/ipv4/route.c | 10 +++++----- net/ipv6/ip6_output.c | 2 +- net/ipv6/netfilter/ip6_queue.c | 2 +- net/ipv6/netfilter/ip6table_mangle.c | 9 ++++----- net/ipv6/route.c | 2 +- net/netfilter/nfnetlink_log.c | 4 ++-- net/netfilter/nfnetlink_queue.c | 8 ++++---- net/netfilter/xt_CONNMARK.c | 10 +++++----- net/netfilter/xt_MARK.c | 12 ++++++------ net/netfilter/xt_mark.c | 2 +- net/sched/Kconfig | 2 +- net/sched/cls_fw.c | 6 +----- net/sched/cls_u32.c | 2 +- net/sched/em_meta.c | 10 +++------- 28 files changed, 59 insertions(+), 68 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7fc9a3aaa1c9..e3ae544b3956 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -216,7 +216,7 @@ enum { * @tail: Tail pointer * @end: End pointer * @destructor: Destruct function - * @nfmark: Can be used for communication between hooks + * @mark: Generic packet mark * @nfct: Associated connection, if any * @ipvs_property: skbuff is owned by ipvs * @nfctinfo: Relationship of this skb to the connection @@ -295,7 +295,6 @@ struct sk_buff { #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info *nf_bridge; #endif - __u32 nfmark; #endif /* CONFIG_NETFILTER */ #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ @@ -310,6 +309,7 @@ struct sk_buff { __u32 secmark; #endif + __u32 mark; /* These elements must be at the end, see alloc_skb() for details. */ unsigned int truesize; diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c index b54306a934e5..2458638561cb 100644 --- a/net/bridge/netfilter/ebt_mark.c +++ b/net/bridge/netfilter/ebt_mark.c @@ -25,13 +25,13 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, int action = info->target & -16; if (action == MARK_SET_VALUE) - (*pskb)->nfmark = info->mark; + (*pskb)->mark = info->mark; else if (action == MARK_OR_VALUE) - (*pskb)->nfmark |= info->mark; + (*pskb)->mark |= info->mark; else if (action == MARK_AND_VALUE) - (*pskb)->nfmark &= info->mark; + (*pskb)->mark &= info->mark; else - (*pskb)->nfmark ^= info->mark; + (*pskb)->mark ^= info->mark; return info->target | -16; } diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c index a6413e4b4982..025869ee0b68 100644 --- a/net/bridge/netfilter/ebt_mark_m.c +++ b/net/bridge/netfilter/ebt_mark_m.c @@ -19,8 +19,8 @@ static int ebt_filter_mark(const struct sk_buff *skb, struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; if (info->bitmask & EBT_MARK_OR) - return !(!!(skb->nfmark & info->mask) ^ info->invert); - return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert); + return !(!!(skb->mark & info->mask) ^ info->invert); + return !(((skb->mark & info->mask) == info->mark) ^ info->invert); } static int ebt_mark_check(const char *tablename, unsigned int hookmask, diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 9f950db3b76f..c1af68b5a29c 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -168,7 +168,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, if (ub->qlen == 1) skb_set_timestamp(ub->skb, &pm->stamp); pm->data_len = copy_len; - pm->mark = skb->nfmark; + pm->mark = skb->mark; pm->hook = hooknr; if (uloginfo->prefix != NULL) strcpy(pm->prefix, uloginfo->prefix); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b8b106358040..b3dea1ef9535 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -473,8 +473,8 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) #endif C(protocol); n->destructor = NULL; + C(mark); #ifdef CONFIG_NETFILTER - C(nfmark); C(nfct); nf_conntrack_get(skb->nfct); C(nfctinfo); @@ -534,8 +534,8 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->pkt_type = old->pkt_type; new->tstamp = old->tstamp; new->destructor = NULL; + new->mark = old->mark; #ifdef CONFIG_NETFILTER - new->nfmark = old->nfmark; new->nfct = old->nfct; nf_conntrack_get(old->nfct); new->nfctinfo = old->nfctinfo; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 23489f7232d2..3482839af280 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1236,7 +1236,7 @@ static int dn_route_input_slow(struct sk_buff *skb) .saddr = cb->src, .scope = RT_SCOPE_UNIVERSE, #ifdef CONFIG_DECNET_ROUTE_FWMARK - .fwmark = skb->nfmark + .fwmark = skb->mark #endif } }, .iif = skb->dev->ifindex }; @@ -1458,7 +1458,7 @@ int dn_route_input(struct sk_buff *skb) (rt->fl.fld_dst == cb->dst) && (rt->fl.oif == 0) && #ifdef CONFIG_DECNET_ROUTE_FWMARK - (rt->fl.fld_fwmark == skb->nfmark) && + (rt->fl.fld_fwmark == skb->mark) && #endif (rt->fl.iif == cb->iif)) { rt->u.dst.lastuse = jiffies; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index fc195a44fc2e..23633bf042ba 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -386,6 +386,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) dst_release(to->dst); to->dst = dst_clone(from->dst); to->dev = from->dev; + to->mark = from->mark; /* Copy the flags to each fragment. */ IPCB(to)->flags = IPCB(from)->flags; @@ -394,7 +395,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->tc_index = from->tc_index; #endif #ifdef CONFIG_NETFILTER - to->nfmark = from->nfmark; /* Connection association is same as pre-frag packet */ nf_conntrack_put(to->nfct); to->nfct = from->nfct; diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index 6ff05c3a32e6..7de385267b33 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -84,7 +84,7 @@ tcp_conn_schedule(struct sk_buff *skb, } if (th->syn && - (svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, + (svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, skb->nh.iph->daddr, th->dest))) { if (ip_vs_todrop()) { /* diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 691c8b637b29..452cb9c384b3 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -89,7 +89,7 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, return 0; } - if ((svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol, + if ((svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol, skb->nh.iph->daddr, uh->dest))) { if (ip_vs_todrop()) { /* diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index e2005c6810a4..bfc8d753a23a 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -28,7 +28,7 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; #ifdef CONFIG_IP_ROUTE_FWMARK - fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; + fl.nl_u.ip4_u.fwmark = (*pskb)->mark; #endif if (ip_route_output_key(&rt, &fl) != 0) return -1; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 97556cc2e4e0..cd520df4dcf4 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -243,7 +243,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) pmsg->data_len = data_len; pmsg->timestamp_sec = entry->skb->tstamp.off_sec; pmsg->timestamp_usec = entry->skb->tstamp.off_usec; - pmsg->mark = entry->skb->nfmark; + pmsg->mark = entry->skb->mark; pmsg->hook = entry->info->hook; pmsg->hw_protocol = entry->skb->protocol; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 264763adc39b..f0319e5ee437 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -76,7 +76,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); - nskb->nfmark = 0; + nskb->mark = 0; skb_init_secmark(nskb); tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 2b104ea54f48..dbd34783a64d 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -239,7 +239,7 @@ static void ipt_ulog_packet(unsigned int hooknum, pm->data_len = copy_len; pm->timestamp_sec = skb->tstamp.off_sec; pm->timestamp_usec = skb->tstamp.off_usec; - pm->mark = skb->nfmark; + pm->mark = skb->mark; pm->hook = hooknum; if (prefix != NULL) strncpy(pm->prefix, prefix, sizeof(pm->prefix)); diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index b91f3582359b..62d4ccc259ca 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -132,7 +132,7 @@ ipt_local_hook(unsigned int hook, unsigned int ret; u_int8_t tos; __be32 saddr, daddr; - unsigned long nfmark; + u_int32_t mark; /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) @@ -143,7 +143,7 @@ ipt_local_hook(unsigned int hook, } /* Save things which could affect route */ - nfmark = (*pskb)->nfmark; + mark = (*pskb)->mark; saddr = (*pskb)->nh.iph->saddr; daddr = (*pskb)->nh.iph->daddr; tos = (*pskb)->nh.iph->tos; @@ -154,7 +154,7 @@ ipt_local_hook(unsigned int hook, && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr #ifdef CONFIG_IP_ROUTE_FWMARK - || (*pskb)->nfmark != nfmark + || (*pskb)->mark != mark #endif || (*pskb)->nh.iph->tos != tos)) if (ip_route_me_harder(pskb, RTN_UNSPEC)) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 925ee4dfc32c..4de3e38fa1a8 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1644,7 +1644,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -1790,7 +1790,7 @@ static inline int __mkroute_input(struct sk_buff *skb, rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -1921,7 +1921,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, .tos = tos, .scope = RT_SCOPE_UNIVERSE, #ifdef CONFIG_IP_ROUTE_FWMARK - .fwmark = skb->nfmark + .fwmark = skb->mark #endif } }, .iif = dev->ifindex }; @@ -2035,7 +2035,7 @@ local_input: rth->rt_dst = daddr; rth->fl.fl4_tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark= skb->nfmark; + rth->fl.fl4_fwmark= skb->mark; #endif rth->fl.fl4_src = saddr; rth->rt_src = saddr; @@ -2114,7 +2114,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.iif == iif && rth->fl.oif == 0 && #ifdef CONFIG_IP_ROUTE_FWMARK - rth->fl.fl4_fwmark == skb->nfmark && + rth->fl.fl4_fwmark == skb->mark && #endif rth->fl.fl4_tos == tos) { rth->u.dst.lastuse = jiffies; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 93330685adfc..1bde3aca3466 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -499,12 +499,12 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) dst_release(to->dst); to->dst = dst_clone(from->dst); to->dev = from->dev; + to->mark = from->mark; #ifdef CONFIG_NET_SCHED to->tc_index = from->tc_index; #endif #ifdef CONFIG_NETFILTER - to->nfmark = from->nfmark; /* Connection association is same as pre-frag packet */ nf_conntrack_put(to->nfct); to->nfct = from->nfct; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 9fec832ee08b..21908c9a10da 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -241,7 +241,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) pmsg->data_len = data_len; pmsg->timestamp_sec = entry->skb->tstamp.off_sec; pmsg->timestamp_usec = entry->skb->tstamp.off_usec; - pmsg->mark = entry->skb->nfmark; + pmsg->mark = entry->skb->mark; pmsg->hook = entry->info->hook; pmsg->hw_protocol = entry->skb->protocol; diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 386ea260e767..6250e86a6ddc 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -149,11 +149,10 @@ ip6t_local_hook(unsigned int hook, int (*okfn)(struct sk_buff *)) { - unsigned long nfmark; unsigned int ret; struct in6_addr saddr, daddr; u_int8_t hop_limit; - u_int32_t flowlabel; + u_int32_t flowlabel, mark; #if 0 /* root is playing with raw sockets. */ @@ -165,10 +164,10 @@ ip6t_local_hook(unsigned int hook, } #endif - /* save source/dest address, nfmark, hoplimit, flowlabel, priority, */ + /* save source/dest address, mark, hoplimit, flowlabel, priority, */ memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr)); memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr)); - nfmark = (*pskb)->nfmark; + mark = (*pskb)->mark; hop_limit = (*pskb)->nh.ipv6h->hop_limit; /* flowlabel and prio (includes version, which shouldn't change either */ @@ -179,7 +178,7 @@ ip6t_local_hook(unsigned int hook, if (ret != NF_DROP && ret != NF_STOLEN && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) - || (*pskb)->nfmark != nfmark + || (*pskb)->mark != mark || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e9c1fc5f21b1..aaabb1fad1cf 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -712,7 +712,7 @@ void ip6_route_input(struct sk_buff *skb) .daddr = iph->daddr, .saddr = iph->saddr, #ifdef CONFIG_IPV6_ROUTE_FWMARK - .fwmark = skb->nfmark, + .fwmark = skb->mark, #endif .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, }, diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 856ed0d19974..bd3ffa6f1a6d 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -501,8 +501,8 @@ __build_packet_message(struct nfulnl_instance *inst, #endif } - if (skb->nfmark) { - tmp_uint = htonl(skb->nfmark); + if (skb->mark) { + tmp_uint = htonl(skb->mark); NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 4ab7b1416bb5..82e4454659bf 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -480,8 +480,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, #endif } - if (entskb->nfmark) { - tmp_uint = htonl(entskb->nfmark); + if (entskb->mark) { + tmp_uint = htonl(entskb->mark); NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); } @@ -834,8 +834,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, } if (nfqa[NFQA_MARK-1]) - entry->skb->nfmark = ntohl(*(__be32 *) - NFA_DATA(nfqa[NFQA_MARK-1])); + entry->skb->mark = ntohl(*(__be32 *) + NFA_DATA(nfqa[NFQA_MARK-1])); issue_verdict(entry, verdict); instance_put(queue); diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c index c01524f817f0..67ed53152999 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c @@ -42,7 +42,7 @@ target(struct sk_buff **pskb, { const struct xt_connmark_target_info *markinfo = targinfo; u_int32_t diff; - u_int32_t nfmark; + u_int32_t mark; u_int32_t newmark; u_int32_t ctinfo; u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo); @@ -62,7 +62,7 @@ target(struct sk_buff **pskb, break; case XT_CONNMARK_SAVE: newmark = (*ctmark & ~markinfo->mask) | - ((*pskb)->nfmark & markinfo->mask); + ((*pskb)->mark & markinfo->mask); if (*ctmark != newmark) { *ctmark = newmark; #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) @@ -73,10 +73,10 @@ target(struct sk_buff **pskb, } break; case XT_CONNMARK_RESTORE: - nfmark = (*pskb)->nfmark; - diff = (*ctmark ^ nfmark) & markinfo->mask; + mark = (*pskb)->mark; + diff = (*ctmark ^ mark) & markinfo->mask; if (diff != 0) - (*pskb)->nfmark = nfmark ^ diff; + (*pskb)->mark = mark ^ diff; break; } } diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c index c6e860a7114f..0b48547e8d64 100644 --- a/net/netfilter/xt_MARK.c +++ b/net/netfilter/xt_MARK.c @@ -31,8 +31,8 @@ target_v0(struct sk_buff **pskb, { const struct xt_mark_target_info *markinfo = targinfo; - if((*pskb)->nfmark != markinfo->mark) - (*pskb)->nfmark = markinfo->mark; + if((*pskb)->mark != markinfo->mark) + (*pskb)->mark = markinfo->mark; return XT_CONTINUE; } @@ -54,16 +54,16 @@ target_v1(struct sk_buff **pskb, break; case XT_MARK_AND: - mark = (*pskb)->nfmark & markinfo->mark; + mark = (*pskb)->mark & markinfo->mark; break; case XT_MARK_OR: - mark = (*pskb)->nfmark | markinfo->mark; + mark = (*pskb)->mark | markinfo->mark; break; } - if((*pskb)->nfmark != mark) - (*pskb)->nfmark = mark; + if((*pskb)->mark != mark) + (*pskb)->mark = mark; return XT_CONTINUE; } diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c index 934dddfbcd23..dfa1ee6914c0 100644 --- a/net/netfilter/xt_mark.c +++ b/net/netfilter/xt_mark.c @@ -31,7 +31,7 @@ match(const struct sk_buff *skb, { const struct xt_mark_info *info = matchinfo; - return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; + return ((skb->mark & info->mask) == info->mark) ^ info->invert; } static int diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 8298ea9ffe19..b2437092978c 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -320,7 +320,7 @@ config CLS_U32_PERF config CLS_U32_MARK bool "Netfilter marks support" - depends on NET_CLS_U32 && NETFILTER + depends on NET_CLS_U32 ---help--- Say Y here to be able to use netfilter marks as u32 key. diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index e54acc6bcccd..f59a2c4aa039 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -101,11 +101,7 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, struct fw_head *head = (struct fw_head*)tp->root; struct fw_filter *f; int r; -#ifdef CONFIG_NETFILTER - u32 id = skb->nfmark & head->mask; -#else - u32 id = 0; -#endif + u32 id = skb->mark & head->mask; if (head != NULL) { for (f=head->ht[fw_hash(id)]; f; f=f->next) { diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 0a6cfa0005be..8b5194801995 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -143,7 +143,7 @@ next_knode: #endif #ifdef CONFIG_CLS_U32_MARK - if ((skb->nfmark & n->mark.mask) != n->mark.val) { + if ((skb->mark & n->mark.mask) != n->mark.val) { n = n->next; goto next_knode; } else { diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 61e3b740ab1a..d3ff3503326a 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -208,13 +208,9 @@ META_COLLECTOR(int_maclen) * Netfilter **************************************************************************/ -META_COLLECTOR(int_nfmark) +META_COLLECTOR(int_mark) { -#ifdef CONFIG_NETFILTER - dst->value = skb->nfmark; -#else - dst->value = 0; -#endif + dst->value = skb->mark; } /************************************************************************** @@ -490,7 +486,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = { [META_ID(PKTLEN)] = META_FUNC(int_pktlen), [META_ID(DATALEN)] = META_FUNC(int_datalen), [META_ID(MACLEN)] = META_FUNC(int_maclen), - [META_ID(NFMARK)] = META_FUNC(int_nfmark), + [META_ID(NFMARK)] = META_FUNC(int_mark), [META_ID(TCINDEX)] = META_FUNC(int_tcindex), [META_ID(RTCLASSID)] = META_FUNC(int_rtclassid), [META_ID(RTIIF)] = META_FUNC(int_rtiif), -- cgit v1.2.3-71-gd317 From b8964ed9fa727109c9084abc807652ebfb681c18 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:22:18 -0800 Subject: [NET] rules: Protocol independant mark selector Move mark selector currently implemented per protocol into the protocol independant part. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/fib_rules.h | 2 +- include/net/fib_rules.h | 2 ++ net/core/fib_rules.c | 29 +++++++++++++++++++++++++++++ net/decnet/dn_rules.c | 27 --------------------------- net/ipv4/fib_rules.c | 29 ----------------------------- net/ipv6/fib6_rules.c | 32 -------------------------------- 6 files changed, 32 insertions(+), 89 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 4418c8d9d479..adcdfbdd14d5 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -34,7 +34,7 @@ enum FRA_UNUSED3, FRA_UNUSED4, FRA_UNUSED5, - FRA_FWMARK, /* netfilter mark */ + FRA_FWMARK, /* mark */ FRA_FLOW, /* flow/class id */ FRA_UNUSED6, FRA_UNUSED7, diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 8e2f473d3e82..68542b565cf7 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -13,6 +13,8 @@ struct fib_rule atomic_t refcnt; int ifindex; char ifname[IFNAMSIZ]; + u32 mark; + u32 mark_mask; u32 pref; u32 flags; u32 table; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 6b0e63cacd93..da91bf2e6151 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -119,6 +119,9 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, if (rule->ifindex && (rule->ifindex != fl->iif)) continue; + if ((rule->mark ^ fl->mark) & rule->mark_mask) + continue; + if (!ops->match(rule, fl, flags)) continue; @@ -179,6 +182,18 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) rule->ifindex = dev->ifindex; } + if (tb[FRA_FWMARK]) { + rule->mark = nla_get_u32(tb[FRA_FWMARK]); + if (rule->mark) + /* compatibility: if the mark value is non-zero all bits + * are compared unless a mask is explicitly specified. + */ + rule->mark_mask = 0xFFFFFFFF; + } + + if (tb[FRA_FWMASK]) + rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]); + rule->action = frh->action; rule->flags = frh->flags; rule->table = frh_get_table(frh, tb); @@ -250,6 +265,14 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) nla_strcmp(tb[FRA_IFNAME], rule->ifname)) continue; + if (tb[FRA_FWMARK] && + (rule->mark != nla_get_u32(tb[FRA_FWMARK]))) + continue; + + if (tb[FRA_FWMASK] && + (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK]))) + continue; + if (!ops->compare(rule, frh, tb)) continue; @@ -298,6 +321,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, if (rule->pref) NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref); + if (rule->mark) + NLA_PUT_U32(skb, FRA_FWMARK, rule->mark); + + if (rule->mark_mask || rule->mark) + NLA_PUT_U32(skb, FRA_FWMASK, rule->mark_mask); + if (ops->fill(rule, skb, nlh, frh) < 0) goto nla_put_failure; diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index a09c09f5572d..1f5d23c96681 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -45,8 +45,6 @@ struct dn_fib_rule __le16 dstmask; __le16 srcmap; u8 flags; - u32 fwmark; - u32 fwmask; }; static struct dn_fib_rule default_rule = { @@ -129,9 +127,6 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) ((daddr ^ r->dst) & r->dstmask)) return 0; - if ((r->fwmark ^ fl->mark) & r->fwmask) - return 0; - return 1; } @@ -165,18 +160,6 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (tb[FRA_DST]) r->dst = nla_get_u16(tb[FRA_DST]); - if (tb[FRA_FWMARK]) { - r->fwmark = nla_get_u32(tb[FRA_FWMARK]); - if (r->fwmark) - /* compatibility: if the mark value is non-zero all bits - * are compared unless a mask is explicitly specified. - */ - r->fwmask = 0xFFFFFFFF; - } - - if (tb[FRA_FWMASK]) - r->fwmask = nla_get_u32(tb[FRA_FWMASK]); - r->src_len = frh->src_len; r->srcmask = dnet_make_mask(r->src_len); r->dst_len = frh->dst_len; @@ -197,12 +180,6 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, if (frh->dst_len && (r->dst_len != frh->dst_len)) return 0; - if (tb[FRA_FWMARK] && (r->fwmark != nla_get_u32(tb[FRA_FWMARK]))) - return 0; - - if (tb[FRA_FWMASK] && (r->fwmask != nla_get_u32(tb[FRA_FWMASK]))) - return 0; - if (tb[FRA_SRC] && (r->src != nla_get_u16(tb[FRA_SRC]))) return 0; @@ -240,10 +217,6 @@ static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb, frh->src_len = r->src_len; frh->tos = 0; - if (r->fwmark) - NLA_PUT_U32(skb, FRA_FWMARK, r->fwmark); - if (r->fwmask || r->fwmark) - NLA_PUT_U32(skb, FRA_FWMASK, r->fwmask); if (r->dst_len) NLA_PUT_U16(skb, FRA_DST, r->dst); if (r->src_len) diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index de8d5dd7099b..d2a190a35d65 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -44,8 +44,6 @@ struct fib4_rule __be32 srcmask; __be32 dst; __be32 dstmask; - u32 fwmark; - u32 fwmask; #ifdef CONFIG_NET_CLS_ROUTE u32 tclassid; #endif @@ -158,9 +156,6 @@ static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) if (r->tos && (r->tos != fl->fl4_tos)) return 0; - if ((r->fwmark ^ fl->mark) & r->fwmask) - return 0; - return 1; } @@ -216,18 +211,6 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (tb[FRA_DST]) rule4->dst = nla_get_be32(tb[FRA_DST]); - if (tb[FRA_FWMARK]) { - rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]); - if (rule4->fwmark) - /* compatibility: if the mark value is non-zero all bits - * are compared unless a mask is explicitly specified. - */ - rule4->fwmask = 0xFFFFFFFF; - } - - if (tb[FRA_FWMASK]) - rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]); - #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW]) rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); @@ -258,12 +241,6 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, if (frh->tos && (rule4->tos != frh->tos)) return 0; - if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK]))) - return 0; - - if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK]))) - return 0; - #ifdef CONFIG_NET_CLS_ROUTE if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) return 0; @@ -288,12 +265,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, frh->src_len = rule4->src_len; frh->tos = rule4->tos; - if (rule4->fwmark) - NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark); - - if (rule4->fwmask || rule4->fwmark) - NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask); - if (rule4->dst_len) NLA_PUT_BE32(skb, FRA_DST, rule4->dst); diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 89bea64eee1c..26374cbe2bc2 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -25,8 +25,6 @@ struct fib6_rule struct fib_rule common; struct rt6key src; struct rt6key dst; - u32 fwmark; - u32 fwmask; u8 tclass; }; @@ -128,9 +126,6 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) return 0; - if ((r->fwmark ^ fl->mark) & r->fwmask) - return 0; - return 1; } @@ -173,21 +168,6 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, nla_memcpy(&rule6->dst.addr, tb[FRA_DST], sizeof(struct in6_addr)); - if (tb[FRA_FWMARK]) { - rule6->fwmark = nla_get_u32(tb[FRA_FWMARK]); - if (rule6->fwmark) { - /* - * if the mark value is non-zero, - * all bits are compared by default - * unless a mask is explicitly specified. - */ - rule6->fwmask = 0xFFFFFFFF; - } - } - - if (tb[FRA_FWMASK]) - rule6->fwmask = nla_get_u32(tb[FRA_FWMASK]); - rule6->src.plen = frh->src_len; rule6->dst.plen = frh->dst_len; rule6->tclass = frh->tos; @@ -219,12 +199,6 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) return 0; - if (tb[FRA_FWMARK] && (rule6->fwmark != nla_get_u32(tb[FRA_FWMARK]))) - return 0; - - if (tb[FRA_FWMASK] && (rule6->fwmask != nla_get_u32(tb[FRA_FWMASK]))) - return 0; - return 1; } @@ -246,12 +220,6 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, NLA_PUT(skb, FRA_SRC, sizeof(struct in6_addr), &rule6->src.addr); - if (rule6->fwmark) - NLA_PUT_U32(skb, FRA_FWMARK, rule6->fwmark); - - if (rule6->fwmask || rule6->fwmark) - NLA_PUT_U32(skb, FRA_FWMASK, rule6->fwmask); - return 0; nla_put_failure: -- cgit v1.2.3-71-gd317 From 3dfbcc411e461db51a1ac1aa1c6ebe2c5a0275a0 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 9 Nov 2006 15:23:20 -0800 Subject: [NET] rules: Add support to invert selectors Introduces a new flag FIB_RULE_INVERT causing rules to apply if the specified selector doesn't match. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/fib_rules.h | 1 + net/core/fib_rules.c | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index adcdfbdd14d5..8270aac2aa5d 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -6,6 +6,7 @@ /* rule is permanent, and cannot be deleted */ #define FIB_RULE_PERMANENT 1 +#define FIB_RULE_INVERT 2 struct fib_rule_hdr { diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index da91bf2e6151..4148e274a204 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -107,6 +107,22 @@ out: EXPORT_SYMBOL_GPL(fib_rules_unregister); +static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, + struct flowi *fl, int flags) +{ + int ret = 0; + + if (rule->ifindex && (rule->ifindex != fl->iif)) + goto out; + + if ((rule->mark ^ fl->mark) & rule->mark_mask) + goto out; + + ret = ops->match(rule, fl, flags); +out: + return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; +} + int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, int flags, struct fib_lookup_arg *arg) { @@ -116,13 +132,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, rcu_read_lock(); list_for_each_entry_rcu(rule, ops->rules_list, list) { - if (rule->ifindex && (rule->ifindex != fl->iif)) - continue; - - if ((rule->mark ^ fl->mark) & rule->mark_mask) - continue; - - if (!ops->match(rule, fl, flags)) + if (!fib_rule_match(rule, ops, fl, flags)) continue; err = ops->action(rule, fl, flags, arg); -- cgit v1.2.3-71-gd317 From 3ff825b28d3345ef381eceae22bf9d92231f23dc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Nov 2006 16:32:06 -0800 Subject: [TCP]: Add tcp_available_congestion_control sysctl. Create /proc/sys/net/ipv4/tcp_available_congestion_control that reflects currently available TCP choices. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 6 ++++++ include/linux/sysctl.h | 1 + include/net/tcp.h | 4 ++++ net/ipv4/sysctl_net_ipv4.c | 24 ++++++++++++++++++++++++ net/ipv4/tcp_cong.c | 16 ++++++++++++++++ 5 files changed, 51 insertions(+) (limited to 'include/linux') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index fd3c0c012351..db4280856588 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -351,10 +351,16 @@ tcp_frto - BOOLEAN where packet loss is typically due to random radio interference rather than intermediate router congestion. +tcp_available_congestion_control - STRING + Shows the available congestion control choices that are registered. + More congestion control algorithms may be available as modules, + but not loaded. + tcp_congestion_control - STRING Set the congestion control algorithm to be used for new connections. The algorithm "reno" is always available, but additional choices may be available based on kernel configuration. + Default is set as part of kernel configuration. somaxconn - INTEGER Limit of socket listen() backlog, known in userspace as SOMAXCONN. diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index d98562f1df76..28a48279654d 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -426,6 +426,7 @@ enum NET_CIPSOV4_CACHE_BUCKET_SIZE=119, NET_CIPSOV4_RBM_OPTFMT=120, NET_CIPSOV4_RBM_STRICTVALID=121, + NET_TCP_AVAIL_CONG_CONTROL=122, }; enum { diff --git a/include/net/tcp.h b/include/net/tcp.h index 246916c2321e..6af4baf5b769 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -620,6 +620,9 @@ enum tcp_ca_event { * Interface for adding new TCP congestion control handlers */ #define TCP_CA_NAME_MAX 16 +#define TCP_CA_MAX 128 +#define TCP_CA_BUF_MAX (TCP_CA_NAME_MAX*TCP_CA_MAX) + struct tcp_congestion_ops { struct list_head list; @@ -659,6 +662,7 @@ extern void tcp_init_congestion_control(struct sock *sk); extern void tcp_cleanup_congestion_control(struct sock *sk); extern int tcp_set_default_congestion_control(const char *name); extern void tcp_get_default_congestion_control(char *name); +extern void tcp_get_available_congestion_control(char *buf, size_t len); extern int tcp_set_congestion_control(struct sock *sk, const char *name); extern void tcp_slow_start(struct tcp_sock *tp); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 15061b314411..2e770f45d829 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -129,6 +129,23 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, return ret; } +static int proc_tcp_available_congestion_control(ctl_table *ctl, + int write, struct file * filp, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX, }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + tcp_get_available_congestion_control(tbl.data, TCP_CA_BUF_MAX); + ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + kfree(tbl.data); + return ret; +} + ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_TCP_TIMESTAMPS, @@ -731,6 +748,13 @@ ctl_table ipv4_table[] = { .proc_handler = &proc_dointvec, }, #endif /* CONFIG_NETLABEL */ + { + .ctl_name = NET_TCP_AVAIL_CONG_CONTROL, + .procname = "tcp_available_congestion_control", + .maxlen = TCP_CA_BUF_MAX, + .mode = 0444, + .proc_handler = &proc_tcp_available_congestion_control, + }, { .ctl_name = 0 } }; diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 1e2982f4acd4..d846d7b95e1f 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -139,6 +139,22 @@ static int __init tcp_congestion_default(void) late_initcall(tcp_congestion_default); +/* Build string with list of available congestion control values */ +void tcp_get_available_congestion_control(char *buf, size_t maxlen) +{ + struct tcp_congestion_ops *ca; + size_t offs = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(ca, &tcp_cong_list, list) { + offs += snprintf(buf + offs, maxlen - offs, + "%s%s", + offs == 0 ? "" : " ", ca->name); + + } + rcu_read_unlock(); +} + /* Get current default congestion control */ void tcp_get_default_congestion_control(char *name) { -- cgit v1.2.3-71-gd317 From ce7bc3bf15cbf5dc5a5587ccb6b04c5b4dde4336 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Nov 2006 16:35:15 -0800 Subject: [TCP]: Restrict congestion control choices. Allow normal users to only choose among a restricted set of congestion control choices. The default is reno and what ever has been configured as default. But the policy can be changed by administrator at any time. For example, to allow any choice: cp /proc/sys/net/ipv4/tcp_available_congestion_control \ /proc/sys/net/ipv4/tcp_allowed_congestion_control Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 6 ++++ include/linux/sysctl.h | 1 + include/net/tcp.h | 3 ++ net/ipv4/sysctl_net_ipv4.c | 52 ++++++++++++++++++++++++++++ net/ipv4/tcp_cong.c | 63 ++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+) (limited to 'include/linux') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index db4280856588..bbcc8deda172 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -351,6 +351,12 @@ tcp_frto - BOOLEAN where packet loss is typically due to random radio interference rather than intermediate router congestion. +tcp_allowed_congestion_control - STRING + Show/set the congestion control choices available to non-privileged + processes. The list is a subset of those listed in + tcp_available_congestion_control. + Default is "reno" and the default setting (tcp_congestion_control). + tcp_available_congestion_control - STRING Shows the available congestion control choices that are registered. More congestion control algorithms may be available as modules, diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 28a48279654d..0725441621d0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -427,6 +427,7 @@ enum NET_CIPSOV4_RBM_OPTFMT=120, NET_CIPSOV4_RBM_STRICTVALID=121, NET_TCP_AVAIL_CONG_CONTROL=122, + NET_TCP_ALLOWED_CONG_CONTROL=123, }; enum { diff --git a/include/net/tcp.h b/include/net/tcp.h index 6af4baf5b769..e1a5d29d0a1f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -625,6 +625,7 @@ enum tcp_ca_event { struct tcp_congestion_ops { struct list_head list; + int non_restricted; /* initialize private data (optional) */ void (*init)(struct sock *sk); @@ -663,6 +664,8 @@ extern void tcp_cleanup_congestion_control(struct sock *sk); extern int tcp_set_default_congestion_control(const char *name); extern void tcp_get_default_congestion_control(char *name); extern void tcp_get_available_congestion_control(char *buf, size_t len); +extern void tcp_get_allowed_congestion_control(char *buf, size_t len); +extern int tcp_set_allowed_congestion_control(char *allowed); extern int tcp_set_congestion_control(struct sock *sk, const char *name); extern void tcp_slow_start(struct tcp_sock *tp); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 2e770f45d829..dfcf47f10f88 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -146,6 +146,50 @@ static int proc_tcp_available_congestion_control(ctl_table *ctl, return ret; } +static int proc_allowed_congestion_control(ctl_table *ctl, + int write, struct file * filp, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + + tcp_get_allowed_congestion_control(tbl.data, tbl.maxlen); + ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + if (write && ret == 0) + ret = tcp_set_allowed_congestion_control(tbl.data); + kfree(tbl.data); + return ret; +} + +static int strategy_allowed_congestion_control(ctl_table *table, int __user *name, + int nlen, void __user *oldval, + size_t __user *oldlenp, + void __user *newval, size_t newlen, + void **context) +{ + ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; + int ret; + + tbl.data = kmalloc(tbl.maxlen, GFP_USER); + if (!tbl.data) + return -ENOMEM; + + tcp_get_available_congestion_control(tbl.data, tbl.maxlen); + ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen, + context); + if (ret == 0 && newval && newlen) + ret = tcp_set_allowed_congestion_control(tbl.data); + kfree(tbl.data); + + return ret; + +} + ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_TCP_TIMESTAMPS, @@ -755,6 +799,14 @@ ctl_table ipv4_table[] = { .mode = 0444, .proc_handler = &proc_tcp_available_congestion_control, }, + { + .ctl_name = NET_TCP_ALLOWED_CONG_CONTROL, + .procname = "tcp_allowed_congestion_control", + .maxlen = TCP_CA_BUF_MAX, + .mode = 0644, + .proc_handler = &proc_allowed_congestion_control, + .strategy = &strategy_allowed_congestion_control, + }, { .ctl_name = 0 } }; diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index d846d7b95e1f..343d6197c92e 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name) #endif if (ca) { + ca->non_restricted = 1; /* default is always allowed */ list_move(&ca->list, &tcp_cong_list); ret = 0; } @@ -168,6 +169,64 @@ void tcp_get_default_congestion_control(char *name) rcu_read_unlock(); } +/* Built list of non-restricted congestion control values */ +void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) +{ + struct tcp_congestion_ops *ca; + size_t offs = 0; + + *buf = '\0'; + rcu_read_lock(); + list_for_each_entry_rcu(ca, &tcp_cong_list, list) { + if (!ca->non_restricted) + continue; + offs += snprintf(buf + offs, maxlen - offs, + "%s%s", + offs == 0 ? "" : " ", ca->name); + + } + rcu_read_unlock(); +} + +/* Change list of non-restricted congestion control */ +int tcp_set_allowed_congestion_control(char *val) +{ + struct tcp_congestion_ops *ca; + char *clone, *name; + int ret = 0; + + clone = kstrdup(val, GFP_USER); + if (!clone) + return -ENOMEM; + + spin_lock(&tcp_cong_list_lock); + /* pass 1 check for bad entries */ + while ((name = strsep(&clone, " ")) && *name) { + ca = tcp_ca_find(name); + if (!ca) { + ret = -ENOENT; + goto out; + } + } + + /* pass 2 clear */ + list_for_each_entry_rcu(ca, &tcp_cong_list, list) + ca->non_restricted = 0; + + /* pass 3 mark as allowed */ + while ((name = strsep(&val, " ")) && *name) { + ca = tcp_ca_find(name); + WARN_ON(!ca); + if (ca) + ca->non_restricted = 1; + } +out: + spin_unlock(&tcp_cong_list_lock); + + return ret; +} + + /* Change congestion control for socket */ int tcp_set_congestion_control(struct sock *sk, const char *name) { @@ -183,6 +242,9 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) if (!ca) err = -ENOENT; + else if (!(ca->non_restricted || capable(CAP_NET_ADMIN))) + err = -EPERM; + else if (!try_module_get(ca->owner)) err = -EBUSY; @@ -284,6 +346,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd); struct tcp_congestion_ops tcp_reno = { .name = "reno", + .non_restricted = 1, .owner = THIS_MODULE, .ssthresh = tcp_reno_ssthresh, .cong_avoid = tcp_reno_cong_avoid, -- cgit v1.2.3-71-gd317 From 9b42078ed6edfe04e9dc9a59b946ad912aeef717 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Fri, 10 Nov 2006 11:22:32 -0200 Subject: [DCCP]: Combine allocating & zeroing header space on skb This is a code simplification: it combines three often recurring operations into one inline function, * allocate `len' bytes header space in skb * fill these `len' bytes with zeroes * cast the start of this header space as dccp_hdr Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 7 +++++++ net/dccp/ipv4.c | 9 ++------- net/dccp/ipv6.c | 8 ++------ net/dccp/output.c | 14 +++----------- 4 files changed, 14 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 53553c99cad6..90d04ffddae8 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -256,6 +256,13 @@ static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb) return (struct dccp_hdr *)skb->h.raw; } +static inline struct dccp_hdr *dccp_zeroed_hdr(struct sk_buff *skb, int headlen) +{ + skb->h.raw = skb_push(skb, headlen); + memset(skb->h.raw, 0, headlen); + return dccp_hdr(skb); +} + static inline struct dccp_hdr_ext *dccp_hdrx(const struct sk_buff *skb) { return (struct dccp_hdr_ext *)(skb->h.raw + sizeof(struct dccp_hdr)); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index de64e6c7f93d..ce8eed32dbeb 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -212,12 +212,9 @@ static void dccp_v4_reqsk_send_ack(struct sk_buff *rxskb, /* Reserve space for headers. */ skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); - skb->dst = dst_clone(rxskb->dst); - skb->h.raw = skb_push(skb, dccp_hdr_ack_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_ack_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_ack_len); /* Build DCCP header and checksum it. */ dh->dccph_type = DCCP_PKT_ACK; @@ -720,9 +717,7 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); skb->dst = dst_clone(dst); - skb->h.raw = skb_push(skb, dccp_hdr_reset_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_reset_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); /* Build DCCP header and checksum it. */ dh->dccph_type = DCCP_PKT_RESET; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 6f1c2ad88608..116bddb64b80 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -537,9 +537,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); - skb->h.raw = skb_push(skb, dccp_hdr_reset_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_reset_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); /* Swap the send and the receive. */ dh->dccph_type = DCCP_PKT_RESET; @@ -601,9 +599,7 @@ static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb, skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); - skb->h.raw = skb_push(skb, dccp_hdr_ack_len); - dh = dccp_hdr(skb); - memset(dh, 0, dccp_hdr_ack_len); + dh = dccp_zeroed_hdr(skb, dccp_hdr_ack_len); /* Build DCCP header and checksum it. */ dh->dccph_type = DCCP_PKT_ACK; diff --git a/net/dccp/output.c b/net/dccp/output.c index 2cc4f4b2a9dd..1ae2248557c6 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -88,11 +88,9 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) return -EPROTO; } - skb->h.raw = skb_push(skb, dccp_header_size); - dh = dccp_hdr(skb); /* Build DCCP header and checksum it. */ - memset(dh, 0, dccp_header_size); + dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_type = dcb->dccpd_type; dh->dccph_sport = inet->sport; dh->dccph_dport = inet->dport; @@ -340,10 +338,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, return NULL; } - skb->h.raw = skb_push(skb, dccp_header_size); - - dh = dccp_hdr(skb); - memset(dh, 0, dccp_header_size); + dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_sport = inet_sk(sk)->sport; dh->dccph_dport = inet_rsk(req)->rmt_port; @@ -392,10 +387,7 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, return NULL; } - skb->h.raw = skb_push(skb, dccp_header_size); - - dh = dccp_hdr(skb); - memset(dh, 0, dccp_header_size); + dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_sport = inet_sk(sk)->sport; dh->dccph_dport = inet_sk(sk)->dport; -- cgit v1.2.3-71-gd317 From 6f4e5fff1e4d46714ea554fd83e44eab534e8b11 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Fri, 10 Nov 2006 17:43:06 -0200 Subject: [DCCP]: Support for partial checksums (RFC 4340, sec. 9.2) This patch does the following: a) introduces variable-length checksums as specified in [RFC 4340, sec. 9.2] b) provides necessary socket options and documentation as to how to use them c) basic support and infrastructure for the Minimum Checksum Coverage feature [RFC 4340, sec. 9.2.1]: acceptability tests, user notification and user interface In addition, it (1) fixes two bugs in the DCCPv4 checksum computation: * pseudo-header used checksum_len instead of skb->len * incorrect checksum coverage calculation based on dccph_x (2) removes dccp_v4_verify_checksum() since it reduplicates code of the checksum computation; code calling this function is updated accordingly. (3) now uses skb_checksum(), which is safer than checksum_partial() if the sk_buff has is a non-linear buffer (has pages attached to it). (4) fixes an outstanding TODO item: * If P.CsCov is too large for the packet size, drop packet and return. The code has been tested with applications, the latest version of tcpdump now comes with support for partial DCCP checksums. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/dccp.txt | 16 ++++++ include/linux/dccp.h | 7 +++ net/dccp/dccp.h | 29 +++++++++-- net/dccp/ipv4.c | 105 +++++++++++++++++++------------------- net/dccp/ipv6.c | 74 +++++++++++++++++---------- net/dccp/output.c | 13 ++--- net/dccp/proto.c | 26 ++++++++-- 7 files changed, 173 insertions(+), 97 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 74563b38ffd9..a8142a81038a 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -47,6 +47,22 @@ the socket will fall back to 0 (which means that no meaningful service code is present). Connecting sockets set at most one service option; for listening sockets, multiple service codes can be specified. +DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the +partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums +always cover the entire packet and that only fully covered application data is +accepted by the receiver. Hence, when using this feature on the sender, it must +be enabled at the receiver, too with suitable choice of CsCov. + +DCCP_SOCKOPT_SEND_CSCOV sets the sender checksum coverage. Values in the + range 0..15 are acceptable. The default setting is 0 (full coverage), + values between 1..15 indicate partial coverage. +DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it + sets a threshold, where again values 0..15 are acceptable. The default + of 0 means that all packets with a partial coverage will be discarded. + Values in the range 1..15 indicate that packets with minimally such a + coverage value are also acceptable. The higher the number, the more + restrictive this setting (see [RFC 4340, sec. 9.2.1]). + Notes ===== diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 90d04ffddae8..0502dfa7f32c 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -183,6 +183,7 @@ enum { DCCPF_ACK_RATIO = 5, DCCPF_SEND_ACK_VECTOR = 6, DCCPF_SEND_NDP_COUNT = 7, + DCCPF_MIN_CSUM_COVER = 8, /* 10-127 reserved */ DCCPF_MIN_CCID_SPECIFIC = 128, DCCPF_MAX_CCID_SPECIFIC = 255, @@ -200,6 +201,8 @@ struct dccp_so_feat { #define DCCP_SOCKOPT_SERVICE 2 #define DCCP_SOCKOPT_CHANGE_L 3 #define DCCP_SOCKOPT_CHANGE_R 4 +#define DCCP_SOCKOPT_SEND_CSCOV 10 +#define DCCP_SOCKOPT_RECV_CSCOV 11 #define DCCP_SOCKOPT_CCID_RX_INFO 128 #define DCCP_SOCKOPT_CCID_TX_INFO 192 @@ -450,6 +453,8 @@ struct dccp_ackvec; * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option * @dccps_packet_size - Set thru setsockopt * @dccps_role - Role of this sock, one of %dccp_role + * @dccps_pcslen - sender partial checksum coverage (via sockopt) + * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) * @dccps_ndp_count - number of Non Data Packets since last data packet * @dccps_hc_rx_ackvec - rx half connection ack vector * @dccps_xmit_timer - timer for when CCID is not ready to send @@ -474,6 +479,8 @@ struct dccp_sock { __u32 dccps_packet_size; __u16 dccps_l_ack_ratio; __u16 dccps_r_ack_ratio; + __u16 dccps_pcslen; + __u16 dccps_pcrlen; unsigned long dccps_ndp_count; __u32 dccps_mss_cache; struct dccp_minisock dccps_minisock; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 2990bfb12587..d5c414bf7819 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -129,6 +129,30 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics); #define DCCP_ADD_STATS_USER(field, val) \ SNMP_ADD_STATS_USER(dccp_statistics, field, val) +/* + * Checksumming routines + */ +static inline int dccp_csum_coverage(const struct sk_buff *skb) +{ + const struct dccp_hdr* dh = dccp_hdr(skb); + + if (dh->dccph_cscov == 0) + return skb->len; + return (dh->dccph_doff + dh->dccph_cscov - 1) * sizeof(u32); +} + +static inline void dccp_csum_outgoing(struct sk_buff *skb) +{ + int cov = dccp_csum_coverage(skb); + + if (cov >= skb->len) + dccp_hdr(skb)->dccph_cscov = 0; + + skb->csum = skb_checksum(skb, 0, (cov > skb->len)? skb->len : cov, 0); +} + +extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); + extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); extern void dccp_send_ack(struct sock *sk); @@ -214,14 +238,9 @@ extern void dccp_shutdown(struct sock *sk, int how); extern int inet_dccp_listen(struct socket *sock, int backlog); extern unsigned int dccp_poll(struct file *file, struct socket *sock, poll_table *wait); -extern void dccp_v4_send_check(struct sock *sk, int len, - struct sk_buff *skb); extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -extern int dccp_v4_checksum(const struct sk_buff *skb, - const __be32 saddr, const __be32 daddr); - extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); extern int dccp_invalid_packet(struct sk_buff *skb); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 91bffaa761a6..496112080f3d 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -349,13 +349,19 @@ out: sock_put(sk); } -/* This routine computes an IPv4 DCCP checksum. */ -void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) +static inline u16 dccp_v4_csum_finish(struct sk_buff *skb, + __be32 src, __be32 dst) +{ + return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum); +} + +void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb) { const struct inet_sock *inet = inet_sk(sk); struct dccp_hdr *dh = dccp_hdr(skb); - dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr, inet->daddr); + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v4_csum_finish(skb, inet->saddr, inet->daddr); } EXPORT_SYMBOL_GPL(dccp_v4_send_check); @@ -454,47 +460,6 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr, - const __be32 daddr) -{ - const struct dccp_hdr* dh = dccp_hdr(skb); - int checksum_len; - u32 tmp; - - if (dh->dccph_cscov == 0) - checksum_len = skb->len; - else { - checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32); - checksum_len = checksum_len < skb->len ? checksum_len : - skb->len; - } - - tmp = csum_partial((unsigned char *)dh, checksum_len, 0); - return csum_tcpudp_magic(saddr, daddr, checksum_len, - IPPROTO_DCCP, tmp); -} - -EXPORT_SYMBOL_GPL(dccp_v4_checksum); - -static int dccp_v4_verify_checksum(struct sk_buff *skb, - const __be32 saddr, const __be32 daddr) -{ - struct dccp_hdr *dh = dccp_hdr(skb); - int checksum_len; - u32 tmp; - - if (dh->dccph_cscov == 0) - checksum_len = skb->len; - else { - checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32); - checksum_len = checksum_len < skb->len ? checksum_len : - skb->len; - } - tmp = csum_partial((unsigned char *)dh, checksum_len, 0); - return csum_tcpudp_magic(saddr, daddr, checksum_len, - IPPROTO_DCCP, tmp) == 0 ? 0 : -1; -} - static struct dst_entry* dccp_v4_route_skb(struct sock *sk, struct sk_buff *skb) { @@ -536,8 +501,8 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, const struct inet_request_sock *ireq = inet_rsk(req); struct dccp_hdr *dh = dccp_hdr(skb); - dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, - ireq->rmt_addr); + dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->loc_addr, + ireq->rmt_addr); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, @@ -602,8 +567,9 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); - dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, - rxskb->nh.iph->daddr); + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr, + rxskb->nh.iph->daddr); bh_lock_sock(dccp_v4_ctl_socket->sk); err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, @@ -779,6 +745,7 @@ EXPORT_SYMBOL_GPL(dccp_v4_do_rcv); int dccp_invalid_packet(struct sk_buff *skb) { const struct dccp_hdr *dh; + unsigned int cscov; if (skb->pkt_type != PACKET_HOST) return 1; @@ -830,6 +797,22 @@ int dccp_invalid_packet(struct sk_buff *skb) return 1; } + /* + * If P.CsCov is too large for the packet size, drop packet and return. + * This must come _before_ checksumming (not as RFC 4340 suggests). + */ + cscov = dccp_csum_coverage(skb); + if (cscov > skb->len) { + LIMIT_NETDEBUG(KERN_WARNING + "DCCP: P.CsCov %u exceeds packet length %d\n", + dh->dccph_cscov, skb->len); + return 1; + } + + /* If header checksum is incorrect, drop packet and return. + * (This step is completed in the AF-dependent functions.) */ + skb->csum = skb_checksum(skb, 0, cscov, 0); + return 0; } @@ -840,16 +823,17 @@ static int dccp_v4_rcv(struct sk_buff *skb) { const struct dccp_hdr *dh; struct sock *sk; + int min_cov; - /* Step 1: Check header basics: */ + /* Step 1: Check header basics */ if (dccp_invalid_packet(skb)) goto discard_it; - /* If the header checksum is incorrect, drop packet and return */ - if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr, - skb->nh.iph->daddr) < 0) { - LIMIT_NETDEBUG(KERN_WARNING "%s: incorrect header checksum\n", + /* Step 1: If header checksum is incorrect, drop packet and return */ + if (dccp_v4_csum_finish(skb, skb->nh.iph->saddr, skb->nh.iph->daddr)) { + LIMIT_NETDEBUG(KERN_WARNING + "%s: dropped packet with invalid checksum\n", __FUNCTION__); goto discard_it; } @@ -905,6 +889,21 @@ static int dccp_v4_rcv(struct sk_buff *skb) goto no_dccp_socket; } + /* + * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage + * o if MinCsCov = 0, only packets with CsCov = 0 are accepted + * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov + */ + min_cov = dccp_sk(sk)->dccps_pcrlen; + if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { + dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", + dh->dccph_cscov, min_cov); + /* FIXME: "Such packets SHOULD be reported using Data Dropped + * options (Section 11.7) with Drop Code 0, Protocol + * Constraints." */ + goto discard_and_relse; + } + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; nf_reset(skb); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 201801e1532d..193b946fd039 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -58,12 +58,22 @@ static void dccp_v6_hash(struct sock *sk) } } -static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, - struct in6_addr *saddr, - struct in6_addr *daddr, - unsigned long base) +/* add pseudo-header to DCCP checksum stored in skb->csum */ +static inline u16 dccp_v6_csum_finish(struct sk_buff *skb, + struct in6_addr *saddr, + struct in6_addr *daddr) { - return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); + return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum); +} + +static inline void dccp_v6_send_check(struct sock *sk, int unused_value, + struct sk_buff *skb) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + struct dccp_hdr *dh = dccp_hdr(skb); + + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr); } static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb) @@ -280,12 +290,9 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, if (skb != NULL) { struct dccp_hdr *dh = dccp_hdr(skb); - dh->dccph_checksum = dccp_v6_check(dh, skb->len, - &ireq6->loc_addr, - &ireq6->rmt_addr, - csum_partial((char *)dh, - skb->len, - skb->csum)); + dh->dccph_checksum = dccp_v6_csum_finish(skb, + &ireq6->loc_addr, + &ireq6->rmt_addr); ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); err = ip6_xmit(sk, skb, &fl, opt, 0); if (err == NET_XMIT_CN) @@ -305,18 +312,6 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req) kfree_skb(inet6_rsk(req)->pktopts); } -static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct dccp_hdr *dh = dccp_hdr(skb); - - dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr, - len, IPPROTO_DCCP, - csum_partial((char *)dh, - dh->dccph_doff << 2, - skb->csum)); -} - static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) { struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; @@ -360,12 +355,14 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); + dccp_csum_outgoing(skb); + dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr, + &rxskb->nh.ipv6h->daddr); + memset(&fl, 0, sizeof(fl)); ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr); ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr); - dh->dccph_checksum = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, - sizeof(*dh), IPPROTO_DCCP, - skb->csum); + fl.proto = IPPROTO_DCCP; fl.oif = inet6_iif(rxskb); fl.fl_ip_dport = dh->dccph_dport; @@ -825,12 +822,22 @@ static int dccp_v6_rcv(struct sk_buff **pskb) const struct dccp_hdr *dh; struct sk_buff *skb = *pskb; struct sock *sk; + int min_cov; - /* Step 1: Check header basics: */ + /* Step 1: Check header basics */ if (dccp_invalid_packet(skb)) goto discard_it; + /* Step 1: If header checksum is incorrect, drop packet and return. */ + if (dccp_v6_csum_finish(skb, &skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr)) { + LIMIT_NETDEBUG(KERN_WARNING + "%s: dropped packet with invalid checksum\n", + __FUNCTION__); + goto discard_it; + } + dh = dccp_hdr(skb); DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); @@ -869,6 +876,19 @@ static int dccp_v6_rcv(struct sk_buff **pskb) goto no_dccp_socket; } + /* + * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage + * o if MinCsCov = 0, only packets with CsCov = 0 are accepted + * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov + */ + min_cov = dccp_sk(sk)->dccps_pcrlen; + if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { + dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", + dh->dccph_cscov, min_cov); + /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */ + goto discard_and_relse; + } + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; diff --git a/net/dccp/output.c b/net/dccp/output.c index 51654975e8ea..992caedd7725 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -96,6 +96,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) dh->dccph_dport = inet->dport; dh->dccph_doff = (dccp_header_size + dcb->dccpd_opt_len) / 4; dh->dccph_ccval = dcb->dccpd_ccval; + dh->dccph_cscov = dp->dccps_pcslen; /* XXX For now we're using only 48 bits sequence numbers */ dh->dccph_x = 1; @@ -115,7 +116,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) break; } - icsk->icsk_af_ops->send_check(sk, skb->len, skb); + icsk->icsk_af_ops->send_check(sk, 0, skb); if (set_ack) dccp_event_ack_sent(sk); @@ -329,7 +330,6 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, skb_reserve(skb, sk->sk_prot->max_header); skb->dst = dst_clone(dst); - skb->csum = 0; dreq = dccp_rsk(req); DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; @@ -352,6 +352,8 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; + dccp_csum_outgoing(skb); + DCCP_INC_STATS(DCCP_MIB_OUTSEGS); return skb; } @@ -376,7 +378,6 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, skb_reserve(skb, sk->sk_prot->max_header); skb->dst = dst_clone(dst); - skb->csum = 0; dccp_inc_seqno(&dp->dccps_gss); @@ -401,7 +402,7 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr); dccp_hdr_reset(skb)->dccph_reset_code = code; - inet_csk(sk)->icsk_af_ops->send_check(sk, skb->len, skb); + inet_csk(sk)->icsk_af_ops->send_check(sk, 0, skb); DCCP_INC_STATS(DCCP_MIB_OUTSEGS); return skb; @@ -475,7 +476,6 @@ int dccp_connect(struct sock *sk) skb_reserve(skb, sk->sk_prot->max_header); DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; - skb->csum = 0; dccp_skb_entail(sk, skb); dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL)); @@ -507,7 +507,6 @@ void dccp_send_ack(struct sock *sk) /* Reserve space for headers */ skb_reserve(skb, sk->sk_prot->max_header); - skb->csum = 0; DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK; dccp_transmit_skb(sk, skb); } @@ -561,7 +560,6 @@ void dccp_send_sync(struct sock *sk, const u64 seq, /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, sk->sk_prot->max_header); - skb->csum = 0; DCCP_SKB_CB(skb)->dccpd_type = pkt_type; DCCP_SKB_CB(skb)->dccpd_seq = seq; @@ -587,7 +585,6 @@ void dccp_send_close(struct sock *sk, const int active) /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, sk->sk_prot->max_header); - skb->csum = 0; DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ? DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 047d170a363a..db54e557eff1 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -472,7 +472,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, case DCCP_SOCKOPT_PACKET_SIZE: dp->dccps_packet_size = val; break; - case DCCP_SOCKOPT_CHANGE_L: if (optlen != sizeof(struct dccp_so_feat)) err = -EINVAL; @@ -481,7 +480,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, (struct dccp_so_feat __user *) optval); break; - case DCCP_SOCKOPT_CHANGE_R: if (optlen != sizeof(struct dccp_so_feat)) err = -EINVAL; @@ -490,12 +488,26 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, (struct dccp_so_feat __user *) optval); break; - + case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ + if (val < 0 || val > 15) + err = -EINVAL; + else + dp->dccps_pcslen = val; + break; + case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */ + if (val < 0 || val > 15) + err = -EINVAL; + else { + dp->dccps_pcrlen = val; + /* FIXME: add feature negotiation, + * ChangeL(MinimumChecksumCoverage, val) */ + } + break; default: err = -ENOPROTOOPT; break; } - + release_sock(sk); return err; } @@ -575,6 +587,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, case DCCP_SOCKOPT_SERVICE: return dccp_getsockopt_service(sk, len, (__be32 __user *)optval, optlen); + case DCCP_SOCKOPT_SEND_CSCOV: + val = dp->dccps_pcslen; + break; + case DCCP_SOCKOPT_RECV_CSCOV: + val = dp->dccps_pcrlen; + break; case 128 ... 191: return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, len, (u32 __user *)optval, optlen); -- cgit v1.2.3-71-gd317 From 339bf98ffc6a8d8eb16fc532ac57ffbced2f8a68 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 10 Nov 2006 14:10:15 -0800 Subject: [NETLINK]: Do precise netlink message allocations where possible Account for the netlink message header size directly in nlmsg_new() instead of relying on the caller calculate it correctly. Replaces error handling of message construction functions when constructing notifications with bug traps since a failure implies a bug in calculating the size of the skb. Signed-off-by: Thomas Graf Acked-by: Paul Moore Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + include/net/fib_rules.h | 1 + include/net/netlink.h | 9 ++--- kernel/taskstats.c | 3 +- net/bridge/br_netlink.c | 21 ++++++++---- net/core/fib_rules.c | 24 +++++++++++--- net/core/neighbour.c | 17 +++++++--- net/core/rtnetlink.c | 39 ++++++++++++++-------- net/decnet/dn_rules.c | 6 ++++ net/decnet/dn_table.c | 34 ++++++++++++++++--- net/ipv4/devinet.c | 18 +++++++--- net/ipv4/fib_rules.c | 8 +++++ net/ipv4/fib_semantics.c | 36 ++++++++++++++++---- net/ipv6/addrconf.c | 70 ++++++++++++++++++--------------------- net/ipv6/fib6_rules.c | 7 ++++ net/ipv6/route.c | 23 +++++++++---- net/netlabel/netlabel_cipso_v4.c | 2 +- net/netlabel/netlabel_mgmt.c | 4 +-- net/netlabel/netlabel_unlabeled.c | 2 +- net/netlink/af_netlink.c | 13 ++++---- net/netlink/genetlink.c | 2 +- 21 files changed, 233 insertions(+), 107 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 66411622e06e..e61e1e138421 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -174,6 +174,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); */ #define NLMSG_GOODORDER 0 #define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER)) +#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) struct netlink_callback diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index e4ba781d289f..bc3c26494c3d 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -52,6 +52,7 @@ struct fib_rules_ops struct nlmsghdr *, struct fib_rule_hdr *); u32 (*default_pref)(void); + size_t (*nlmsg_payload)(struct fib_rule *); int nlgroup; struct nla_policy *policy; diff --git a/include/net/netlink.h b/include/net/netlink.h index ce5cba19c393..30021339157c 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -500,14 +500,15 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, /** * nlmsg_new - Allocate a new netlink message - * @size: maximum size of message + * @payload: size of the message payload * @flags: the type of memory to allocate. * - * Use NLMSG_GOODSIZE if size isn't know and you need a good default size. + * Use NLMSG_DEFAULT_SIZE if the size of the payload isn't known + * and a good default is needed. */ -static inline struct sk_buff *nlmsg_new(int size, gfp_t flags) +static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags) { - return alloc_skb(size, flags); + return alloc_skb(nlmsg_total_size(payload), flags); } /** diff --git a/kernel/taskstats.c b/kernel/taskstats.c index f45c5e70773c..4f3f0e48c845 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -77,8 +77,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp, /* * If new attributes are added, please revisit this allocation */ - size = nlmsg_total_size(genlmsg_total_size(size)); - skb = nlmsg_new(size, GFP_KERNEL); + skb = nlmsg_new(genlmsg_total_size(size), GFP_KERNEL); if (!skb) return -ENOMEM; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 8f661195d09d..15d6efbe7519 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -15,6 +15,18 @@ #include #include "br_private.h" +static inline size_t br_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ifinfomsg)) + + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ + + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ + + nla_total_size(4) /* IFLA_MASTER */ + + nla_total_size(4) /* IFLA_MTU */ + + nla_total_size(4) /* IFLA_LINK */ + + nla_total_size(1) /* IFLA_OPERSTATE */ + + nla_total_size(1); /* IFLA_PROTINFO */ +} + /* * Create one netlink message for one interface * Contains port and master info as well as carrier and bridge state. @@ -77,19 +89,16 @@ rtattr_failure: void br_ifinfo_notify(int event, struct net_bridge_port *port) { struct sk_buff *skb; - int payload = sizeof(struct ifinfomsg) + 128; int err = -ENOBUFS; pr_debug("bridge notify event=%d\n", event); - skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); + skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = br_fill_ifinfo(skb, port, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in br_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); errout: diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 4148e274a204..1df6cd4568d3 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -306,6 +306,22 @@ errout: return err; } +static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, + struct fib_rule *rule) +{ + size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr)) + + nla_total_size(IFNAMSIZ) /* FRA_IFNAME */ + + nla_total_size(4) /* FRA_PRIORITY */ + + nla_total_size(4) /* FRA_TABLE */ + + nla_total_size(4) /* FRA_FWMARK */ + + nla_total_size(4); /* FRA_FWMASK */ + + if (ops->nlmsg_payload) + payload += ops->nlmsg_payload(rule); + + return payload; +} + static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, u32 pid, u32 seq, int type, int flags, struct fib_rules_ops *ops) @@ -384,15 +400,13 @@ static void notify_rule_change(int event, struct fib_rule *rule, struct sk_buff *skb; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(fib_rule_nlmsg_size(ops, rule), GFP_KERNEL); if (skb == NULL) goto errout; err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in fib_rule_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL); errout: diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b4b478353b27..0e097ba14d73 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2410,20 +2410,27 @@ static struct file_operations neigh_stat_seq_fops = { #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_ARPD +static inline size_t neigh_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ndmsg)) + + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ + + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ + + nla_total_size(sizeof(struct nda_cacheinfo)) + + nla_total_size(4); /* NDA_PROBES */ +} + static void __neigh_notify(struct neighbour *n, int type, int flags) { struct sk_buff *skb; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = neigh_fill_info(skb, n, 0, 0, type, flags); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in neigh_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); errout: diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 02f3c7947898..50d6cb40c6e3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -273,6 +273,25 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, a->tx_compressed = b->tx_compressed; }; +static inline size_t if_nlmsg_size(int iwbuflen) +{ + return NLMSG_ALIGN(sizeof(struct ifinfomsg)) + + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ + + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */ + + nla_total_size(sizeof(struct rtnl_link_ifmap)) + + nla_total_size(sizeof(struct rtnl_link_stats)) + + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ + + nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */ + + nla_total_size(4) /* IFLA_TXQLEN */ + + nla_total_size(4) /* IFLA_WEIGHT */ + + nla_total_size(4) /* IFLA_MTU */ + + nla_total_size(4) /* IFLA_LINK */ + + nla_total_size(4) /* IFLA_MASTER */ + + nla_total_size(1) /* IFLA_OPERSTATE */ + + nla_total_size(1) /* IFLA_LINKMODE */ + + nla_total_size(iwbuflen); +} + static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, void *iwbuf, int iwbuflen, int type, u32 pid, u32 seq, u32 change, unsigned int flags) @@ -558,7 +577,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) struct sk_buff *nskb; char *iw_buf = NULL, *iw = NULL; int iw_buf_len = 0; - int err, payload; + int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) @@ -587,9 +606,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) } #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ - payload = NLMSG_ALIGN(sizeof(struct ifinfomsg) + - nla_total_size(iw_buf_len)); - nskb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); + nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL); if (nskb == NULL) { err = -ENOBUFS; goto errout; @@ -597,10 +614,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); - if (err <= 0) { - kfree_skb(nskb); - goto errout; - } + /* failure impilies BUG in if_nlmsg_size or wireless_rtnetlink_get */ + BUG_ON(err < 0); err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); errout: @@ -639,15 +654,13 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) struct sk_buff *skb; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(if_nlmsg_size(0), GFP_KERNEL); if (skb == NULL) goto errout; err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in if_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); errout: diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index e32d0c3d5a96..b7dfd04a9638 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -241,6 +241,12 @@ static u32 dn_fib_rule_default_pref(void) return 0; } +static size_t dn_fib_rule_nlmsg_payload(struct fib_rule *rule) +{ + return nla_total_size(2) /* dst */ + + nla_total_size(2); /* src */ +} + int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) { return fib_rules_dump(skb, cb, AF_DECnet); diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 317904bb5896..e74b744254ab 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -263,6 +263,32 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern return 0; } +static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi) +{ + size_t payload = NLMSG_ALIGN(struct rtmsg) + + nla_total_size(4) /* RTA_TABLE */ + + nla_total_size(2) /* RTA_DST */ + + nla_total_size(4); /* RTA_PRIORITY */ + + /* space for nested metrics */ + payload += nla_total_size((RTAX_MAX * nla_total_size(4))); + + if (fi->fib_nhs) { + /* Also handles the special case fib_nhs == 1 */ + + /* each nexthop is packed in an attribute */ + size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); + + /* may contain a gateway attribute */ + nhsize += nla_total_size(4); + + /* all nexthops are packed in a nested attribute */ + payload += nla_total_size(fi->fib_nhs * nhsize); + } + + return payload; +} + static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id, u8 type, u8 scope, void *dst, int dst_len, struct dn_fib_info *fi, unsigned int flags) @@ -335,17 +361,15 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id, u32 pid = req ? req->pid : 0; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(dn_fib_nlmsg_size(DN_FIB_INFO(f), GFP_KERNEL)); if (skb == NULL) goto errout; err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, f->fn_type, f->fn_scope, &f->fn_key, z, DN_FIB_INFO(f), 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in dn_fib_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); errout: diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 7602c79a389b..f38cbbae0ae3 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1120,6 +1120,16 @@ static struct notifier_block ip_netdev_notifier = { .notifier_call =inetdev_event, }; +static inline size_t inet_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + + nla_total_size(4) /* IFA_ADDRESS */ + + nla_total_size(4) /* IFA_LOCAL */ + + nla_total_size(4) /* IFA_BROADCAST */ + + nla_total_size(4) /* IFA_ANYCAST */ + + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ +} + static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 pid, u32 seq, int event, unsigned int flags) { @@ -1208,15 +1218,13 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, u32 seq = nlh ? nlh->nlmsg_seq : 0; int err = -ENOBUFS; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); if (skb == NULL) goto errout; err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); errout: diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index fd4a8cd4c06e..b837c33e0404 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -299,6 +299,13 @@ static u32 fib4_rule_default_pref(void) return 0; } +static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule) +{ + return nla_total_size(4) /* dst */ + + nla_total_size(4) /* src */ + + nla_total_size(4); /* flow */ +} + static struct fib_rules_ops fib4_rules_ops = { .family = AF_INET, .rule_size = sizeof(struct fib4_rule), @@ -308,6 +315,7 @@ static struct fib_rules_ops fib4_rules_ops = { .compare = fib4_rule_compare, .fill = fib4_rule_fill, .default_pref = fib4_rule_default_pref, + .nlmsg_payload = fib4_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV4_RULE, .policy = fib4_rule_policy, .rules_list = &fib4_rules, diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 884d176e0082..e63b8a98fb4d 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev) return -1; } +static inline size_t fib_nlmsg_size(struct fib_info *fi) +{ + size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg)) + + nla_total_size(4) /* RTA_TABLE */ + + nla_total_size(4) /* RTA_DST */ + + nla_total_size(4) /* RTA_PRIORITY */ + + nla_total_size(4); /* RTA_PREFSRC */ + + /* space for nested metrics */ + payload += nla_total_size((RTAX_MAX * nla_total_size(4))); + + if (fi->fib_nhs) { + /* Also handles the special case fib_nhs == 1 */ + + /* each nexthop is packed in an attribute */ + size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); + + /* may contain flow and gateway attribute */ + nhsize += 2 * nla_total_size(4); + + /* all nexthops are packed in a nested attribute */ + payload += nla_total_size(fi->fib_nhs * nhsize); + } + + return payload; +} + void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, u32 tb_id, struct nl_info *info) { struct sk_buff *skb; - int payload = sizeof(struct rtmsg) + 256; u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; int err = -ENOBUFS; - skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); + skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); if (skb == NULL) goto errout; err = fib_dump_info(skb, info->pid, seq, event, tb_id, fa->fa_type, fa->fa_scope, key, dst_len, fa->fa_tos, fa->fa_info, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in fib_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, info->nlh, GFP_KERNEL); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6a98f68348cb..967ea320a9ca 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3098,10 +3098,9 @@ static inline int rt_scope(int ifa_scope) static inline int inet6_ifaddr_msgsize(void) { - return nlmsg_total_size(sizeof(struct ifaddrmsg) + - nla_total_size(16) + - nla_total_size(sizeof(struct ifa_cacheinfo)) + - 128); + return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + + nla_total_size(16) /* IFA_ADDRESS */ + + nla_total_size(sizeof(struct ifa_cacheinfo)); } static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, @@ -3329,10 +3328,8 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWADDR, 0); - if (err < 0) { - kfree_skb(skb); - goto errout_ifa; - } + /* failure implies BUG in inet6_ifaddr_msgsize() */ + BUG_ON(err < 0); err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); errout_ifa: @@ -3351,10 +3348,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) goto errout; err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet6_ifaddr_msgsize() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); errout: @@ -3397,16 +3392,19 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; } -/* Maximum length of ifinfomsg attributes */ -#define INET6_IFINFO_RTA_SPACE \ - RTA_SPACE(IFNAMSIZ) /* IFNAME */ + \ - RTA_SPACE(MAX_ADDR_LEN) /* ADDRESS */ + \ - RTA_SPACE(sizeof(u32)) /* MTU */ + \ - RTA_SPACE(sizeof(int)) /* LINK */ + \ - RTA_SPACE(0) /* PROTINFO */ + \ - RTA_SPACE(sizeof(u32)) /* FLAGS */ + \ - RTA_SPACE(sizeof(struct ifla_cacheinfo)) /* CACHEINFO */ + \ - RTA_SPACE(sizeof(__s32[DEVCONF_MAX])) /* CONF */ +static inline size_t inet6_if_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ifinfomsg)) + + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ + + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ + + nla_total_size(4) /* IFLA_MTU */ + + nla_total_size(4) /* IFLA_LINK */ + + nla_total_size( /* IFLA_PROTINFO */ + nla_total_size(4) /* IFLA_INET6_FLAGS */ + + nla_total_size(sizeof(struct ifla_cacheinfo)) + + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ + ); +} static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, u32 pid, u32 seq, int event, unsigned int flags) @@ -3501,18 +3499,15 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) void inet6_ifinfo_notify(int event, struct inet6_dev *idev) { struct sk_buff *skb; - int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE; int err = -ENOBUFS; - skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); + skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet6_if_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); errout: @@ -3520,10 +3515,12 @@ errout: rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); } -/* Maximum length of prefix_cacheinfo attributes */ -#define INET6_PREFIX_RTA_SPACE \ - RTA_SPACE(sizeof(((struct prefix_info *)NULL)->prefix)) /* ADDRESS */ + \ - RTA_SPACE(sizeof(struct prefix_cacheinfo)) /* CACHEINFO */ +static inline size_t inet6_prefix_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct prefixmsg)) + + nla_total_size(sizeof(struct in6_addr)) + + nla_total_size(sizeof(struct prefix_cacheinfo)); +} static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, struct prefix_info *pinfo, u32 pid, u32 seq, @@ -3569,18 +3566,15 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo) { struct sk_buff *skb; - int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE; int err = -ENOBUFS; - skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); + skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in inet6_prefix_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); errout: diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 25804cb69cf0..d587dde5897e 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -232,6 +232,12 @@ static u32 fib6_rule_default_pref(void) return 0x3FFF; } +static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) +{ + return nla_total_size(16) /* dst */ + + nla_total_size(16); /* src */ +} + static struct fib_rules_ops fib6_rules_ops = { .family = AF_INET6, .rule_size = sizeof(struct fib6_rule), @@ -241,6 +247,7 @@ static struct fib_rules_ops fib6_rules_ops = { .compare = fib6_rule_compare, .fill = fib6_rule_fill, .default_pref = fib6_rule_default_pref, + .nlmsg_payload = fib6_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV6_RULE, .policy = fib6_rule_policy, .rules_list = &fib6_rules, diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0ad07c9087a7..a6472cb9054c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2006,6 +2006,20 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) return ip6_route_add(&cfg); } +static inline size_t rt6_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct rtmsg)) + + nla_total_size(16) /* RTA_SRC */ + + nla_total_size(16) /* RTA_DST */ + + nla_total_size(16) /* RTA_GATEWAY */ + + nla_total_size(16) /* RTA_PREFSRC */ + + nla_total_size(4) /* RTA_TABLE */ + + nla_total_size(4) /* RTA_IIF */ + + nla_total_size(4) /* RTA_OIF */ + + nla_total_size(4) /* RTA_PRIORITY */ + + nla_total_size(sizeof(struct rta_cacheinfo)); +} + static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, struct in6_addr *dst, struct in6_addr *src, int iif, int type, u32 pid, u32 seq, @@ -2200,7 +2214,6 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) struct sk_buff *skb; u32 pid = 0, seq = 0; struct nlmsghdr *nlh = NULL; - int payload = sizeof(struct rtmsg) + 256; int err = -ENOBUFS; if (info) { @@ -2210,15 +2223,13 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) seq = nlh->nlmsg_seq; } - skb = nlmsg_new(nlmsg_total_size(payload), gfp_any()); + skb = nlmsg_new(rt6_nlmsg_size(), gfp_any()); if (skb == NULL) goto errout; err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } + /* failure implies BUG in rt6_nlmsg_size() */ + BUG_ON(err < 0); err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any()); errout: diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index a6ce1d6d5c59..f1788bd290f8 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -452,7 +452,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) } list_start: - ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL); if (ans_skb == NULL) { ret_val = -ENOMEM; goto list_failure; diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 53c9079ad2c3..c529622ff0b7 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -356,7 +356,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) void *data; struct netlbl_dom_map *entry; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (ans_skb == NULL) return -ENOMEM; data = netlbl_netlink_hdr_put(ans_skb, @@ -492,7 +492,7 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) struct sk_buff *ans_skb = NULL; void *data; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (ans_skb == NULL) return -ENOMEM; data = netlbl_netlink_hdr_put(ans_skb, diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 1833ad233b39..219dccade4e1 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -138,7 +138,7 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info) struct sk_buff *ans_skb; void *data; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (ans_skb == NULL) goto list_failure; data = netlbl_netlink_hdr_put(ans_skb, diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d527c8977b1f..f61d81b3c61c 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1148,7 +1148,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, if (len > sk->sk_sndbuf - 32) goto out; err = -ENOBUFS; - skb = nlmsg_new(len, GFP_KERNEL); + skb = alloc_skb(len, GFP_KERNEL); if (skb==NULL) goto out; @@ -1435,14 +1435,13 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) struct sk_buff *skb; struct nlmsghdr *rep; struct nlmsgerr *errmsg; - int size; + size_t payload = sizeof(*errmsg); - if (err == 0) - size = nlmsg_total_size(sizeof(*errmsg)); - else - size = nlmsg_total_size(sizeof(*errmsg) + nlmsg_len(nlh)); + /* error messages get the original request appened */ + if (err) + payload += nlmsg_len(nlh); - skb = nlmsg_new(size, GFP_KERNEL); + skb = nlmsg_new(payload, GFP_KERNEL); if (!skb) { struct sock *sk; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 49bc2db7982b..70d60c818897 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -480,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, struct sk_buff *skb; int err; - skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (skb == NULL) return ERR_PTR(-ENOBUFS); -- cgit v1.2.3-71-gd317 From 2e2e9e92bd723244ea20fa488b1780111f2b05e1 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 13 Nov 2006 13:23:52 -0200 Subject: [DCCP]: Add sysctls to control retransmission behaviour This adds 3 sysctls which govern the retransmission behaviour of DCCP control packets (3way handshake, feature negotiation). It removes 4 FIXMEs from the code. The close resemblance of sysctl variables to their TCP analogues is emphasised not only by their name, but also by giving them the same initial values. This is useful since there is not much practical experience with DCCP yet. Furthermore, with regard to the previous patch, it is now possible to limit the number of keepalive-Responses by setting net.dccp.default.request_retries (also a bit like in TCP). Lastly, added documentation of all existing DCCP sysctls. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/dccp.txt | 41 +++++++++++++++++++++++++++++++++++++++ include/linux/sysctl.h | 3 +++ net/dccp/dccp.h | 11 +++++++++++ net/dccp/feat.h | 7 ------- net/dccp/proto.c | 1 + net/dccp/sysctl.c | 25 ++++++++++++++++++++++++ net/dccp/timer.c | 16 +++++++++------ 7 files changed, 91 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index a8142a81038a..c2328c862e98 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -63,6 +63,47 @@ DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it coverage value are also acceptable. The higher the number, the more restrictive this setting (see [RFC 4340, sec. 9.2.1]). +Sysctl variables +================ +Several DCCP default parameters can be managed by the following sysctls +(sysctl net.dccp.default or /proc/sys/net/dccp/default): + +request_retries + The number of active connection initiation retries (the number of + Requests minus one) before timing out. In addition, it also governs + the behaviour of the other, passive side: this variable also sets + the number of times DCCP repeats sending a Response when the initial + handshake does not progress from RESPOND to OPEN (i.e. when no Ack + is received after the initial Request). This value should be greater + than 0, suggested is less than 10. Analogue of tcp_syn_retries. + +retries1 + How often a DCCP Response is retransmitted until the listening DCCP + side considers its connecting peer dead. Analogue of tcp_retries1. + +retries2 + The number of times a general DCCP packet is retransmitted. This has + importance for retransmitted acknowledgments and feature negotiation, + data packets are never retransmitted. Analogue of tcp_retries2. + +send_ndp = 1 + Whether or not to send NDP count options (sec. 7.7.2). + +send_ackvec = 1 + Whether or not to send Ack Vector options (sec. 11.5). + +ack_ratio = 2 + The default Ack Ratio (sec. 11.3) to use. + +tx_ccid = 2 + Default CCID for the sender-receiver half-connection. + +rx_ccid = 2 + Default CCID for the receiver-sender half-connection. + +seq_window = 100 + The initial sequence window (sec. 7.5.2). + Notes ===== diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 0725441621d0..2e8c5ad82793 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -614,6 +614,9 @@ enum { NET_DCCP_DEFAULT_ACK_RATIO = 4, NET_DCCP_DEFAULT_SEND_ACKVEC = 5, NET_DCCP_DEFAULT_SEND_NDP = 6, + NET_DCCP_DEFAULT_REQ_RETRIES = 7, + NET_DCCP_DEFAULT_RETRIES1 = 8, + NET_DCCP_DEFAULT_RETRIES2 = 9, }; /* /proc/sys/net/ipx */ diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index d5c414bf7819..e7b96074a1b1 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -64,6 +64,17 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo); #define DCCP_XMIT_TIMEO 30000 /* Time/msecs for blocking transmit per packet */ +/* sysctl variables for DCCP */ +extern int sysctl_dccp_request_retries; +extern int sysctl_dccp_retries1; +extern int sysctl_dccp_retries2; +extern int dccp_feat_default_sequence_window; +extern int dccp_feat_default_rx_ccid; +extern int dccp_feat_default_tx_ccid; +extern int dccp_feat_default_ack_ratio; +extern int dccp_feat_default_send_ack_vector; +extern int dccp_feat_default_send_ndp_count; + /* is seq1 < seq2 ? */ static inline int before48(const u64 seq1, const u64 seq2) { diff --git a/net/dccp/feat.h b/net/dccp/feat.h index cee553d416ca..6048373c7186 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h @@ -26,11 +26,4 @@ extern void dccp_feat_clean(struct dccp_minisock *dmsk); extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); extern int dccp_feat_init(struct dccp_minisock *dmsk); -extern int dccp_feat_default_sequence_window; -extern int dccp_feat_default_rx_ccid; -extern int dccp_feat_default_tx_ccid; -extern int dccp_feat_default_ack_ratio; -extern int dccp_feat_default_send_ack_vector; -extern int dccp_feat_default_send_ndp_count; - #endif /* _DCCP_FEAT_H */ diff --git a/net/dccp/proto.c b/net/dccp/proto.c index db54e557eff1..9c9c08cffdaf 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -212,6 +212,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) dccp_init_xmit_timers(sk); icsk->icsk_rto = DCCP_TIMEOUT_INIT; + icsk->icsk_syn_retries = sysctl_dccp_request_retries; sk->sk_state = DCCP_CLOSED; sk->sk_write_space = dccp_write_space; icsk->icsk_sync_mss = dccp_sync_mss; diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 38bc157876f3..7b09f2179985 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -11,6 +11,7 @@ #include #include +#include "dccp.h" #include "feat.h" #ifndef CONFIG_SYSCTL @@ -66,6 +67,30 @@ static struct ctl_table dccp_default_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .ctl_name = NET_DCCP_DEFAULT_REQ_RETRIES, + .procname = "request_retries", + .data = &sysctl_dccp_request_retries, + .maxlen = sizeof(sysctl_dccp_request_retries), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .ctl_name = NET_DCCP_DEFAULT_RETRIES1, + .procname = "retries1", + .data = &sysctl_dccp_retries1, + .maxlen = sizeof(sysctl_dccp_retries1), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .ctl_name = NET_DCCP_DEFAULT_RETRIES2, + .procname = "retries2", + .data = &sysctl_dccp_retries2, + .maxlen = sizeof(sysctl_dccp_retries2), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { .ctl_name = 0, } }; diff --git a/net/dccp/timer.c b/net/dccp/timer.c index bda0af639ae4..7b3f16e29a97 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -15,6 +15,11 @@ #include "dccp.h" +/* sysctl variables governing numbers of retransmission attempts */ +int sysctl_dccp_request_retries __read_mostly = TCP_SYN_RETRIES; +int sysctl_dccp_retries1 __read_mostly = TCP_RETR1; +int sysctl_dccp_retries2 __read_mostly = TCP_RETR2; + static void dccp_write_timer(unsigned long data); static void dccp_keepalive_timer(unsigned long data); static void dccp_delack_timer(unsigned long data); @@ -44,11 +49,10 @@ static int dccp_write_timeout(struct sock *sk) if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) { if (icsk->icsk_retransmits != 0) dst_negative_advice(&sk->sk_dst_cache); - retry_until = icsk->icsk_syn_retries ? : - /* FIXME! */ 3 /* FIXME! sysctl_tcp_syn_retries */; + retry_until = icsk->icsk_syn_retries ? + : sysctl_dccp_request_retries; } else { - if (icsk->icsk_retransmits >= - /* FIXME! sysctl_tcp_retries1 */ 5 /* FIXME! */) { + if (icsk->icsk_retransmits >= sysctl_dccp_retries1) { /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black hole detection. :-( @@ -72,7 +76,7 @@ static int dccp_write_timeout(struct sock *sk) dst_negative_advice(&sk->sk_dst_cache); } - retry_until = /* FIXME! */ 15 /* FIXME! sysctl_tcp_retries2 */; + retry_until = sysctl_dccp_retries2; /* * FIXME: see tcp_write_timout and tcp_out_of_resources */ @@ -196,7 +200,7 @@ backoff: icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, DCCP_RTO_MAX); - if (icsk->icsk_retransmits > 3 /* FIXME: sysctl_dccp_retries1 */) + if (icsk->icsk_retransmits > sysctl_dccp_retries1) __sk_dst_reset(sk); out:; } -- cgit v1.2.3-71-gd317 From 90833aa4f496d69ca374af6acef7d1614c8693ff Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 13 Nov 2006 16:02:22 -0800 Subject: [NET]: The scheduled removal of the frame diverter. This patch contains the scheduled removal of the frame diverter. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- Documentation/feature-removal-schedule.txt | 15 - drivers/net/Space.c | 1 - include/linux/Kbuild | 1 - include/linux/divert.h | 132 ------- include/linux/netdevice.h | 6 - include/linux/sockios.h | 4 +- net/Kconfig | 27 -- net/core/Makefile | 1 - net/core/dev.c | 20 +- net/core/dv.c | 546 ----------------------------- net/core/sysctl_net_core.c | 14 - net/socket.c | 6 - 12 files changed, 6 insertions(+), 767 deletions(-) delete mode 100644 include/linux/divert.h delete mode 100644 net/core/dv.c (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index d52c4aaaf17f..b3949cd3d013 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -227,21 +227,6 @@ Who: Patrick McHardy --------------------------- -What: frame diverter -When: November 2006 -Why: The frame diverter is included in most distribution kernels, but is - broken. It does not correctly handle many things: - - IPV6 - - non-linear skb's - - network device RCU on removal - - input frames not correctly checked for protocol errors - It also adds allocation overhead even if not enabled. - It is not clear if anyone is still using it. -Who: Stephen Hemminger - ---------------------------- - - What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment When: October 2008 Why: The stacking of class devices makes these values misleading and diff --git a/drivers/net/Space.c b/drivers/net/Space.c index a67f5efc983f..602ed31a5dd9 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -33,7 +33,6 @@ #include #include #include -#include /* A unified ethernet device probe. This is the easiest way to have every ethernet adaptor have the name "eth[0123...]". diff --git a/include/linux/Kbuild b/include/linux/Kbuild index a1155a2beb32..d7e04689304c 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -193,7 +193,6 @@ unifdef-y += cuda.h unifdef-y += cyclades.h unifdef-y += dccp.h unifdef-y += dirent.h -unifdef-y += divert.h unifdef-y += dlm.h unifdef-y += elfcore.h unifdef-y += errno.h diff --git a/include/linux/divert.h b/include/linux/divert.h deleted file mode 100644 index 8fb4e9de6843..000000000000 --- a/include/linux/divert.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Frame Diversion, Benoit Locher - * - * Changes: - * 06/09/2000 BL: initial version - * - */ - -#ifndef _LINUX_DIVERT_H -#define _LINUX_DIVERT_H - -#include - -#define MAX_DIVERT_PORTS 8 /* Max number of ports to divert (tcp, udp) */ - -/* Divertable protocols */ -#define DIVERT_PROTO_NONE 0x0000 -#define DIVERT_PROTO_IP 0x0001 -#define DIVERT_PROTO_ICMP 0x0002 -#define DIVERT_PROTO_TCP 0x0004 -#define DIVERT_PROTO_UDP 0x0008 - -/* - * This is an Ethernet Frame Diverter option block - */ -struct divert_blk -{ - int divert; /* are we active */ - unsigned int protos; /* protocols */ - __u16 tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */ - __u16 tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */ - __u16 udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */ - __u16 udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */ -}; - -/* - * Diversion control block, for configuration with the userspace tool - * divert - */ - -typedef union _divert_cf_arg -{ - __s16 int16; - __u16 uint16; - __s32 int32; - __u32 uint32; - __s64 int64; - __u64 uint64; - void __user *ptr; -} divert_cf_arg; - - -struct divert_cf -{ - int cmd; /* Command */ - divert_cf_arg arg1, - arg2, - arg3; - int dev_index; /* device index (eth0=0, etc...) */ -}; - - -/* Diversion commands */ -#define DIVCMD_DIVERT 1 /* ENABLE/DISABLE diversion */ -#define DIVCMD_IP 2 /* ENABLE/DISABLE whold IP diversion */ -#define DIVCMD_TCP 3 /* ENABLE/DISABLE whold TCP diversion */ -#define DIVCMD_TCPDST 4 /* ADD/REMOVE TCP DST port for diversion */ -#define DIVCMD_TCPSRC 5 /* ADD/REMOVE TCP SRC port for diversion */ -#define DIVCMD_UDP 6 /* ENABLE/DISABLE whole UDP diversion */ -#define DIVCMD_UDPDST 7 /* ADD/REMOVE UDP DST port for diversion */ -#define DIVCMD_UDPSRC 8 /* ADD/REMOVE UDP SRC port for diversion */ -#define DIVCMD_ICMP 9 /* ENABLE/DISABLE whole ICMP diversion */ -#define DIVCMD_GETSTATUS 10 /* GET the status of the diverter */ -#define DIVCMD_RESET 11 /* Reset the diverter on the specified dev */ -#define DIVCMD_GETVERSION 12 /* Retrieve the diverter code version (char[32]) */ - -/* General syntax of the commands: - * - * DIVCMD_xxxxxx(arg1, arg2, arg3, dev_index) - * - * SIOCSIFDIVERT: - * DIVCMD_DIVERT(DIVARG1_ENABLE|DIVARG1_DISABLE, , ,ifindex) - * DIVCMD_IP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_TCP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_TCPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_TCPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_UDP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_UDPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_UDPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) - * DIVCMD_ICMP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) - * DIVCMD_RESET(, , , ifindex) - * - * SIOGIFDIVERT: - * DIVCMD_GETSTATUS(divert_blk, , , ifindex) - * DIVCMD_GETVERSION(string[3]) - */ - - -/* Possible values for arg1 */ -#define DIVARG1_ENABLE 0 /* ENABLE something */ -#define DIVARG1_DISABLE 1 /* DISABLE something */ -#define DIVARG1_ADD 2 /* ADD something */ -#define DIVARG1_REMOVE 3 /* REMOVE something */ - - -#ifdef __KERNEL__ - -/* diverter functions */ -#include - -#ifdef CONFIG_NET_DIVERT -#include - -int alloc_divert_blk(struct net_device *); -void free_divert_blk(struct net_device *); -int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg); -void divert_frame(struct sk_buff *skb); -static inline void handle_diverter(struct sk_buff *skb) -{ - /* if diversion is supported on device, then divert */ - if (skb->dev->divert && skb->dev->divert->divert) - divert_frame(skb); -} - -#else -# define alloc_divert_blk(dev) (0) -# define free_divert_blk(dev) do {} while (0) -# define divert_ioctl(cmd, arg) (-ENOPKG) -# define handle_diverter(skb) do {} while (0) -#endif -#endif -#endif /* _LINUX_DIVERT_H */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 83b8c4f1d69d..4e967b2e22cc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -38,7 +38,6 @@ #include #include -struct divert_blk; struct vlan_group; struct ethtool_ops; struct netpoll_info; @@ -517,11 +516,6 @@ struct net_device /* bridge stuff */ struct net_bridge_port *br_port; -#ifdef CONFIG_NET_DIVERT - /* this will get initialized at each interface type init routine */ - struct divert_blk *divert; -#endif /* CONFIG_NET_DIVERT */ - /* class/net/name entry */ struct class_device class_dev; /* space for optional statistics and wireless sysfs groups */ diff --git a/include/linux/sockios.h b/include/linux/sockios.h index e6b9d1d36ea2..abef7596655a 100644 --- a/include/linux/sockios.h +++ b/include/linux/sockios.h @@ -72,8 +72,8 @@ #define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ #define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ -#define SIOCGIFDIVERT 0x8944 /* Frame diversion support */ -#define SIOCSIFDIVERT 0x8945 /* Set frame diversion options */ +/* SIOCGIFDIVERT was: 0x8944 Frame diversion support */ +/* SIOCSIFDIVERT was: 0x8945 Set frame diversion options */ #define SIOCETHTOOL 0x8946 /* Ethtool interface */ diff --git a/net/Kconfig b/net/Kconfig index 67e39ad8b8b6..867f95032513 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -175,33 +175,6 @@ source "net/ipx/Kconfig" source "drivers/net/appletalk/Kconfig" source "net/x25/Kconfig" source "net/lapb/Kconfig" - -config NET_DIVERT - bool "Frame Diverter (EXPERIMENTAL)" - depends on EXPERIMENTAL && BROKEN - ---help--- - The Frame Diverter allows you to divert packets from the - network, that are not aimed at the interface receiving it (in - promisc. mode). Typically, a Linux box setup as an Ethernet bridge - with the Frames Diverter on, can do some *really* transparent www - caching using a Squid proxy for example. - - This is very useful when you don't want to change your router's - config (or if you simply don't have access to it). - - The other possible usages of diverting Ethernet Frames are - numberous: - - reroute smtp traffic to another interface - - traffic-shape certain network streams - - transparently proxy smtp connections - - etc... - - For more informations, please refer to: - - - - If unsure, say N. - source "net/econet/Kconfig" source "net/wanrouter/Kconfig" source "net/sched/Kconfig" diff --git a/net/core/Makefile b/net/core/Makefile index 119568077dab..73272d506e93 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -12,7 +12,6 @@ obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \ obj-$(CONFIG_XFRM) += flow.o obj-$(CONFIG_SYSFS) += net-sysfs.o -obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_WIRELESS_EXT) += wireless.o obj-$(CONFIG_NETPOLL) += netpoll.o diff --git a/net/core/dev.c b/net/core/dev.c index 411c2428d268..5bf13b132dd7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -98,7 +98,6 @@ #include #include #include -#include #include #include #include @@ -1827,8 +1826,6 @@ int netif_receive_skb(struct sk_buff *skb) ncls: #endif - handle_diverter(skb); - if (handle_bridge(&skb, &pt_prev, &ret, orig_dev)) goto out; @@ -2898,10 +2895,6 @@ int register_netdevice(struct net_device *dev) spin_lock_init(&dev->ingress_lock); #endif - ret = alloc_divert_blk(dev); - if (ret) - goto out; - dev->iflink = -1; /* Init, if this function is available */ @@ -2910,13 +2903,13 @@ int register_netdevice(struct net_device *dev) if (ret) { if (ret > 0) ret = -EIO; - goto out_err; + goto out; } } if (!dev_valid_name(dev->name)) { ret = -EINVAL; - goto out_err; + goto out; } dev->ifindex = dev_new_index(); @@ -2930,7 +2923,7 @@ int register_netdevice(struct net_device *dev) = hlist_entry(p, struct net_device, name_hlist); if (!strncmp(d->name, dev->name, IFNAMSIZ)) { ret = -EEXIST; - goto out_err; + goto out; } } @@ -2974,7 +2967,7 @@ int register_netdevice(struct net_device *dev) ret = netdev_register_sysfs(dev); if (ret) - goto out_err; + goto out; dev->reg_state = NETREG_REGISTERED; /* @@ -3001,9 +2994,6 @@ int register_netdevice(struct net_device *dev) out: return ret; -out_err: - free_divert_blk(dev); - goto out; } /** @@ -3320,8 +3310,6 @@ int unregister_netdevice(struct net_device *dev) /* Notifier chain MUST detach us from master device. */ BUG_TRAP(!dev->master); - free_divert_blk(dev); - /* Finish processing unregister after unlock */ net_set_todo(dev); diff --git a/net/core/dv.c b/net/core/dv.c deleted file mode 100644 index 29ee77f15932..000000000000 --- a/net/core/dv.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic frame diversion - * - * Authors: - * Benoit LOCHER: initial integration within the kernel with support for ethernet - * Dave Miller: improvement on the code (correctness, performance and source files) - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const char sysctl_divert_version[32]="0.46"; /* Current version */ - -static int __init dv_init(void) -{ - return 0; -} -module_init(dv_init); - -/* - * Allocate a divert_blk for a device. This must be an ethernet nic. - */ -int alloc_divert_blk(struct net_device *dev) -{ - int alloc_size = (sizeof(struct divert_blk) + 3) & ~3; - - dev->divert = NULL; - if (dev->type == ARPHRD_ETHER) { - dev->divert = kzalloc(alloc_size, GFP_KERNEL); - if (dev->divert == NULL) { - printk(KERN_INFO "divert: unable to allocate divert_blk for %s\n", - dev->name); - return -ENOMEM; - } - dev_hold(dev); - } - - return 0; -} - -/* - * Free a divert_blk allocated by the above function, if it was - * allocated on that device. - */ -void free_divert_blk(struct net_device *dev) -{ - if (dev->divert) { - kfree(dev->divert); - dev->divert=NULL; - dev_put(dev); - } -} - -/* - * Adds a tcp/udp (source or dest) port to an array - */ -static int add_port(u16 ports[], u16 port) -{ - int i; - - if (port == 0) - return -EINVAL; - - /* Storing directly in network format for performance, - * thanks Dave :) - */ - port = htons(port); - - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - if (ports[i] == port) - return -EALREADY; - } - - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - if (ports[i] == 0) { - ports[i] = port; - return 0; - } - } - - return -ENOBUFS; -} - -/* - * Removes a port from an array tcp/udp (source or dest) - */ -static int remove_port(u16 ports[], u16 port) -{ - int i; - - if (port == 0) - return -EINVAL; - - /* Storing directly in network format for performance, - * thanks Dave ! - */ - port = htons(port); - - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - if (ports[i] == port) { - ports[i] = 0; - return 0; - } - } - - return -EINVAL; -} - -/* Some basic sanity checks on the arguments passed to divert_ioctl() */ -static int check_args(struct divert_cf *div_cf, struct net_device **dev) -{ - char devname[32]; - int ret; - - if (dev == NULL) - return -EFAULT; - - /* GETVERSION: all other args are unused */ - if (div_cf->cmd == DIVCMD_GETVERSION) - return 0; - - /* Network device index should reasonably be between 0 and 1000 :) */ - if (div_cf->dev_index < 0 || div_cf->dev_index > 1000) - return -EINVAL; - - /* Let's try to find the ifname */ - sprintf(devname, "eth%d", div_cf->dev_index); - *dev = dev_get_by_name(devname); - - /* dev should NOT be null */ - if (*dev == NULL) - return -EINVAL; - - ret = 0; - - /* user issuing the ioctl must be a super one :) */ - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - goto out; - } - - /* Device must have a divert_blk member NOT null */ - if ((*dev)->divert == NULL) - ret = -EINVAL; -out: - dev_put(*dev); - return ret; -} - -/* - * control function of the diverter - */ -#if 0 -#define DVDBG(a) \ - printk(KERN_DEBUG "divert_ioctl() line %d %s\n", __LINE__, (a)) -#else -#define DVDBG(a) -#endif - -int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg) -{ - struct divert_cf div_cf; - struct divert_blk *div_blk; - struct net_device *dev; - int ret; - - switch (cmd) { - case SIOCGIFDIVERT: - DVDBG("SIOCGIFDIVERT, copy_from_user"); - if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf))) - return -EFAULT; - DVDBG("before check_args"); - ret = check_args(&div_cf, &dev); - if (ret) - return ret; - DVDBG("after checkargs"); - div_blk = dev->divert; - - DVDBG("befre switch()"); - switch (div_cf.cmd) { - case DIVCMD_GETSTATUS: - /* Now, just give the user the raw divert block - * for him to play with :) - */ - if (copy_to_user(div_cf.arg1.ptr, dev->divert, - sizeof(struct divert_blk))) - return -EFAULT; - break; - - case DIVCMD_GETVERSION: - DVDBG("GETVERSION: checking ptr"); - if (div_cf.arg1.ptr == NULL) - return -EINVAL; - DVDBG("GETVERSION: copying data to userland"); - if (copy_to_user(div_cf.arg1.ptr, - sysctl_divert_version, 32)) - return -EFAULT; - DVDBG("GETVERSION: data copied"); - break; - - default: - return -EINVAL; - } - - break; - - case SIOCSIFDIVERT: - if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf))) - return -EFAULT; - - ret = check_args(&div_cf, &dev); - if (ret) - return ret; - - div_blk = dev->divert; - - switch(div_cf.cmd) { - case DIVCMD_RESET: - div_blk->divert = 0; - div_blk->protos = DIVERT_PROTO_NONE; - memset(div_blk->tcp_dst, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - memset(div_blk->tcp_src, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - memset(div_blk->udp_dst, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - memset(div_blk->udp_src, 0, - MAX_DIVERT_PORTS * sizeof(u16)); - return 0; - - case DIVCMD_DIVERT: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->divert) - return -EALREADY; - div_blk->divert = 1; - break; - - case DIVARG1_DISABLE: - if (!div_blk->divert) - return -EALREADY; - div_blk->divert = 0; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_IP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_IP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_IP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_IP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_IP; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_TCP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_TCP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_TCP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_TCP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_TCP; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_TCPDST: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->tcp_dst, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->tcp_dst, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_TCPSRC: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->tcp_src, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->tcp_src, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_UDP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_UDP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_UDP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_UDP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_UDP; - break; - - default: - return -EINVAL; - } - - break; - - case DIVCMD_UDPDST: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->udp_dst, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->udp_dst, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_UDPSRC: - switch(div_cf.arg1.int32) { - case DIVARG1_ADD: - return add_port(div_blk->udp_src, - div_cf.arg2.uint16); - - case DIVARG1_REMOVE: - return remove_port(div_blk->udp_src, - div_cf.arg2.uint16); - - default: - return -EINVAL; - } - - break; - - case DIVCMD_ICMP: - switch(div_cf.arg1.int32) { - case DIVARG1_ENABLE: - if (div_blk->protos & DIVERT_PROTO_ICMP) - return -EALREADY; - div_blk->protos |= DIVERT_PROTO_ICMP; - break; - - case DIVARG1_DISABLE: - if (!(div_blk->protos & DIVERT_PROTO_ICMP)) - return -EALREADY; - div_blk->protos &= ~DIVERT_PROTO_ICMP; - break; - - default: - return -EINVAL; - } - - break; - - default: - return -EINVAL; - } - - break; - - default: - return -EINVAL; - } - - return 0; -} - - -/* - * Check if packet should have its dest mac address set to the box itself - * for diversion - */ - -#define ETH_DIVERT_FRAME(skb) \ - memcpy(eth_hdr(skb), skb->dev->dev_addr, ETH_ALEN); \ - skb->pkt_type=PACKET_HOST - -void divert_frame(struct sk_buff *skb) -{ - struct ethhdr *eth = eth_hdr(skb); - struct iphdr *iph; - struct tcphdr *tcph; - struct udphdr *udph; - struct divert_blk *divert = skb->dev->divert; - int i, src, dst; - unsigned char *skb_data_end = skb->data + skb->len; - - /* Packet is already aimed at us, return */ - if (!compare_ether_addr(eth->h_dest, skb->dev->dev_addr)) - return; - - /* proto is not IP, do nothing */ - if (eth->h_proto != htons(ETH_P_IP)) - return; - - /* Divert all IP frames ? */ - if (divert->protos & DIVERT_PROTO_IP) { - ETH_DIVERT_FRAME(skb); - return; - } - - /* Check for possible (maliciously) malformed IP frame (thanks Dave) */ - iph = (struct iphdr *) skb->data; - if (((iph->ihl<<2)+(unsigned char*)(iph)) >= skb_data_end) { - printk(KERN_INFO "divert: malformed IP packet !\n"); - return; - } - - switch (iph->protocol) { - /* Divert all ICMP frames ? */ - case IPPROTO_ICMP: - if (divert->protos & DIVERT_PROTO_ICMP) { - ETH_DIVERT_FRAME(skb); - return; - } - break; - - /* Divert all TCP frames ? */ - case IPPROTO_TCP: - if (divert->protos & DIVERT_PROTO_TCP) { - ETH_DIVERT_FRAME(skb); - return; - } - - /* Check for possible (maliciously) malformed IP - * frame (thanx Dave) - */ - tcph = (struct tcphdr *) - (((unsigned char *)iph) + (iph->ihl<<2)); - if (((unsigned char *)(tcph+1)) >= skb_data_end) { - printk(KERN_INFO "divert: malformed TCP packet !\n"); - return; - } - - /* Divert some tcp dst/src ports only ?*/ - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - dst = divert->tcp_dst[i]; - src = divert->tcp_src[i]; - if ((dst && dst == tcph->dest) || - (src && src == tcph->source)) { - ETH_DIVERT_FRAME(skb); - return; - } - } - break; - - /* Divert all UDP frames ? */ - case IPPROTO_UDP: - if (divert->protos & DIVERT_PROTO_UDP) { - ETH_DIVERT_FRAME(skb); - return; - } - - /* Check for possible (maliciously) malformed IP - * packet (thanks Dave) - */ - udph = (struct udphdr *) - (((unsigned char *)iph) + (iph->ihl<<2)); - if (((unsigned char *)(udph+1)) >= skb_data_end) { - printk(KERN_INFO - "divert: malformed UDP packet !\n"); - return; - } - - /* Divert some udp dst/src ports only ? */ - for (i = 0; i < MAX_DIVERT_PORTS; i++) { - dst = divert->udp_dst[i]; - src = divert->udp_src[i]; - if ((dst && dst == udph->dest) || - (src && src == udph->source)) { - ETH_DIVERT_FRAME(skb); - return; - } - } - break; - } -} diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 02534131d88e..1e75b1585460 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -21,10 +21,6 @@ extern __u32 sysctl_rmem_max; extern int sysctl_core_destroy_delay; -#ifdef CONFIG_NET_DIVERT -extern char sysctl_divert_version[]; -#endif /* CONFIG_NET_DIVERT */ - #ifdef CONFIG_XFRM extern u32 sysctl_xfrm_aevent_etime; extern u32 sysctl_xfrm_aevent_rseqth; @@ -105,16 +101,6 @@ ctl_table core_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, -#ifdef CONFIG_NET_DIVERT - { - .ctl_name = NET_CORE_DIVERT_VERSION, - .procname = "divert_version", - .data = (void *)sysctl_divert_version, - .maxlen = 32, - .mode = 0444, - .proc_handler = &proc_dostring - }, -#endif /* CONFIG_NET_DIVERT */ #ifdef CONFIG_XFRM { .ctl_name = NET_CORE_AEVENT_ETIME, diff --git a/net/socket.c b/net/socket.c index 6c9b9b326d76..e8db54702a69 100644 --- a/net/socket.c +++ b/net/socket.c @@ -77,7 +77,6 @@ #include #include #include -#include #include #include #include @@ -852,11 +851,6 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = vlan_ioctl_hook(argp); mutex_unlock(&vlan_ioctl_mutex); break; - case SIOCGIFDIVERT: - case SIOCSIFDIVERT: - /* Convert this to call through a hook */ - err = divert_ioctl(cmd, argp); - break; case SIOCADDDLCI: case SIOCDELDLCI: err = -ENOPKG; -- cgit v1.2.3-71-gd317 From b9df3cb8cf9a96e63dfdcd3056a9cbc71f2459e7 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 14 Nov 2006 11:21:36 -0200 Subject: [TCP/DCCP]: Introduce net_xmit_eval Throughout the TCP/DCCP (and tunnelling) code, it often happens that the return code of a transmit function needs to be tested against NET_XMIT_CN which is a value that does not indicate a strict error condition. This patch uses a macro for these recurring situations which is consistent with the already existing macro net_xmit_errno, saving on duplicated code. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/netdevice.h | 4 ++++ include/net/ipip.h | 2 +- net/dccp/ipv4.c | 5 ++--- net/dccp/ipv6.c | 3 +-- net/dccp/output.c | 14 ++------------ net/ipv4/tcp_ipv4.c | 3 +-- net/ipv4/tcp_output.c | 8 +------- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/tcp_ipv6.c | 3 +-- 9 files changed, 14 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4e967b2e22cc..caa3c2593719 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -66,6 +66,10 @@ struct netpoll_info; #define NET_RX_CN_HIGH 4 /* The storm is here */ #define NET_RX_BAD 5 /* packet dropped due to kernel error */ +/* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It + * indicates that the device will soon be dropping packets, or already drops + * some packets of the same priority; prompting us to send less aggressively. */ +#define net_xmit_eval(e) ((e) == NET_XMIT_CN? 0 : (e)) #define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) #endif diff --git a/include/net/ipip.h b/include/net/ipip.h index f490c3cbe377..84058858eea7 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -35,7 +35,7 @@ struct ip_tunnel ip_send_check(iph); \ \ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output);\ - if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) { \ + if (net_xmit_eval(err) == 0) { \ stats->tx_bytes += pkt_len; \ stats->tx_packets++; \ } else { \ diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index bc400b2ba25e..61c09014dade 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -501,8 +501,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } out: @@ -571,7 +570,7 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) rxskb->nh.iph->saddr, NULL); bh_unlock_sock(dccp_v4_ctl_socket->sk); - if (err == NET_XMIT_CN || err == 0) { + if (net_xmit_eval(err) == 0) { DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 8d6ddb6389a7..2165b1740c7c 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -294,8 +294,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, &ireq6->rmt_addr); ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); err = ip6_xmit(sk, skb, &fl, opt, 0); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } done: diff --git a/net/dccp/output.c b/net/dccp/output.c index 0994b13f0f15..ef22f3cc791a 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -125,16 +125,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = icsk->icsk_af_ops->queue_xmit(skb, sk, 0); - if (err <= 0) - return err; - - /* NET_XMIT_CN is special. It does not guarantee, - * that this packet is lost. It tells that device - * is about to start to drop packets or already - * drops some packets of the same priority and - * invokes us to send less aggressively. - */ - return err == NET_XMIT_CN ? 0 : err; + return net_xmit_eval(err); } return -ENOBUFS; } @@ -426,8 +417,7 @@ int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) if (skb != NULL) { memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, sk, 0); - if (err == NET_XMIT_CN) - err = 0; + return net_xmit_eval(err); } } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 2eb58844403c..0ad0904bf56c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -662,8 +662,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } out: diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f63e99aac2d5..6a8581ab9a23 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -484,13 +484,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, tcp_enter_cwr(sk); - /* NET_XMIT_CN is special. It does not guarantee, - * that this packet is lost. It tells that device - * is about to start to drop packets or already - * drops some packets of the same priority and - * invokes us to send less aggressively. - */ - return err == NET_XMIT_CN ? 0 : err; + return net_xmit_eval(err); #undef SYSCTL_FLAG_TSTAMPS #undef SYSCTL_FLAG_WSCALE diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 4919f9294e2a..80a11909159d 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -748,7 +748,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); - if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) { + if (net_xmit_eval(err) == 0) { stats->tx_bytes += pkt_len; stats->tx_packets++; } else { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9a8e690fdf7c..9a88395a7629 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -502,8 +502,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); err = ip6_xmit(sk, skb, &fl, opt, 0); - if (err == NET_XMIT_CN) - err = 0; + err = net_xmit_eval(err); } done: -- cgit v1.2.3-71-gd317 From c02fdc0e81e9c735d8d895af1e201b235df326d8 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 14 Nov 2006 12:48:10 -0200 Subject: [DCCP]: Make feature negotiation more readable This patch replaces cryptic feature negotiation messages of type Oct 31 15:42:20 kernel: dccp_feat_change: feat change type=32 feat=1 Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=34 feat=1 Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=32 feat=5 into ones of type: Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(CCID (1), 3) Nov 2 13:54:45 kernel: dccp_feat_change: ChangeR(CCID (1), 3) Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(Ack Ratio (5), 2) Also, * completed the feature number list wrt RFC 4340 sec. 6.4 * annotating which ones have been implemented so far * implemented rudimentary sanity checking in feat.c (FIXMEs) * some minor fixes Commiter note: uninlined dccp_feat_name and dccp_feat_typename, for consistency with dccp_{state,packet}_name, that, BTW, should be compiled only if CONFIG_IP_DCCP_DEBUG is selected, leaving this to another cset tho. Also shortened dccp_feat_negotiation_debug to dccp_feat_debug. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 25 ++++++----- net/dccp/feat.c | 116 +++++++++++++++++++++++++++++++++++++++------------ net/dccp/feat.h | 41 +++++++++++++++++- net/dccp/options.c | 4 +- 4 files changed, 145 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 0502dfa7f32c..696319ee2d5b 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -175,18 +175,21 @@ enum { DCCPC_CCID3 = 3, }; -/* DCCP features */ -enum { - DCCPF_RESERVED = 0, - DCCPF_CCID = 1, - DCCPF_SEQUENCE_WINDOW = 3, - DCCPF_ACK_RATIO = 5, - DCCPF_SEND_ACK_VECTOR = 6, - DCCPF_SEND_NDP_COUNT = 7, +/* DCCP features (RFC 4340 section 6.4) */ + enum { + DCCPF_RESERVED = 0, + DCCPF_CCID = 1, + DCCPF_SHORT_SEQNOS = 2, /* XXX: not yet implemented */ + DCCPF_SEQUENCE_WINDOW = 3, + DCCPF_ECN_INCAPABLE = 4, /* XXX: not yet implemented */ + DCCPF_ACK_RATIO = 5, + DCCPF_SEND_ACK_VECTOR = 6, + DCCPF_SEND_NDP_COUNT = 7, DCCPF_MIN_CSUM_COVER = 8, - /* 10-127 reserved */ - DCCPF_MIN_CCID_SPECIFIC = 128, - DCCPF_MAX_CCID_SPECIFIC = 255, + DCCPF_DATA_CHECKSUM = 9, /* XXX: not yet implemented */ + /* 10-127 reserved */ + DCCPF_MIN_CCID_SPECIFIC = 128, + DCCPF_MAX_CCID_SPECIFIC = 255, }; /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */ diff --git a/net/dccp/feat.c b/net/dccp/feat.c index a1b0682ee77c..12cde2f2f13b 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -12,7 +12,6 @@ #include -#include "dccp.h" #include "ccid.h" #include "feat.h" @@ -23,9 +22,17 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, { struct dccp_opt_pend *opt; - dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); + dccp_feat_debug(type, feature, *val); - /* XXX sanity check feat change request */ + if (!dccp_feat_is_valid_type(type)) { + pr_info("option type %d invalid in negotiation\n", type); + return 1; + } + if (!dccp_feat_is_valid_length(type, feature, len)) { + pr_info("invalid length %d\n", len); + return 1; + } + /* XXX add further sanity checks */ /* check if that feature is already being negotiated */ list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { @@ -95,14 +102,14 @@ static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) /* XXX taking only u8 vals */ static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) { - dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val); + dccp_feat_debug(type, feat, val); switch (feat) { case DCCPF_CCID: return dccp_feat_update_ccid(sk, type, val); default: - dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n", - type, feat, val); + dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", + dccp_feat_typename(type), feat); break; } return 0; @@ -265,10 +272,10 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) u8 *copy; int rc; - /* NN features must be change L */ - if (type == DCCPO_CHANGE_R) { - dccp_pr_debug("received CHANGE_R %d for NN feat %d\n", - type, feature); + /* NN features must be Change L (sec. 6.3.2) */ + if (type != DCCPO_CHANGE_L) { + dccp_pr_debug("received %s for NN feature %d\n", + dccp_feat_typename(type), feature); return -EFAULT; } @@ -299,7 +306,8 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) return rc; } - dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy); + dccp_feat_debug(type, feature, *copy); + list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); return 0; @@ -318,14 +326,19 @@ static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, return; } - opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R : - DCCPO_CONFIRM_L; + switch (type) { + case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break; + case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break; + default: pr_info("invalid type %d\n", type); return; + + } opt->dccpop_feat = feature; opt->dccpop_val = NULL; opt->dccpop_len = 0; /* change feature */ - dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type); + dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); + list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); } @@ -359,7 +372,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) { int rc; - dccp_pr_debug("got feat change type=%d feat=%d\n", type, feature); + dccp_feat_debug(type, feature, *val); /* figure out if it's SP or NN feature */ switch (feature) { @@ -375,6 +388,8 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) /* XXX implement other features */ default: + dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", + dccp_feat_typename(type), feature); rc = -EFAULT; break; } @@ -403,20 +418,27 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, u8 t; struct dccp_opt_pend *opt; struct dccp_minisock *dmsk = dccp_msk(sk); - int rc = 1; + int found = 0; int all_confirmed = 1; - dccp_pr_debug("got feat confirm type=%d feat=%d\n", type, feature); - - /* XXX sanity check type & feat */ + dccp_feat_debug(type, feature, *val); /* locate our change request */ - t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L; + switch (type) { + case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; + case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; + default: pr_info("invalid type %d\n", type); + return 1; + + } + /* XXX sanity check feature value */ list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { if (!opt->dccpop_conf && opt->dccpop_type == t && opt->dccpop_feat == feature) { - /* we found it */ + found = 1; + dccp_pr_debug("feature %d found\n", opt->dccpop_feat); + /* XXX do sanity check */ opt->dccpop_conf = 1; @@ -425,9 +447,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *val); - dccp_pr_debug("feat %d type %d confirmed %d\n", - feature, type, *val); - rc = 0; + /* XXX check the return value of dccp_feat_update */ break; } @@ -446,9 +466,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); } - if (rc) - dccp_pr_debug("feat %d type %d never requested\n", - feature, type); + if (!found) + dccp_pr_debug("%s(%d, ...) never requested\n", + dccp_feat_typename(type), feature); return 0; } @@ -583,3 +603,45 @@ out: } EXPORT_SYMBOL_GPL(dccp_feat_init); + +#ifdef CONFIG_IP_DCCP_DEBUG +const char *dccp_feat_typename(const u8 type) +{ + switch(type) { + case DCCPO_CHANGE_L: return("ChangeL"); + case DCCPO_CONFIRM_L: return("ConfirmL"); + case DCCPO_CHANGE_R: return("ChangeR"); + case DCCPO_CONFIRM_R: return("ConfirmR"); + /* the following case must not appear in feature negotation */ + default: dccp_pr_debug("unknown type %d [BUG!]\n", type); + } + return NULL; +} + +EXPORT_SYMBOL_GPL(dccp_feat_typename); + +const char *dccp_feat_name(const u8 feat) +{ + static const char *feature_names[] = { + [DCCPF_RESERVED] = "Reserved", + [DCCPF_CCID] = "CCID", + [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", + [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", + [DCCPF_ECN_INCAPABLE] = "ECN Incapable", + [DCCPF_ACK_RATIO] = "Ack Ratio", + [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", + [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", + [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", + [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", + }; + if (feat >= DCCPF_MIN_CCID_SPECIFIC) + return "CCID-specific"; + + if (dccp_feat_is_reserved(feat)) + return feature_names[DCCPF_RESERVED]; + + return feature_names[feat]; +} + +EXPORT_SYMBOL_GPL(dccp_feat_name); +#endif /* CONFIG_IP_DCCP_DEBUG */ diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 6048373c7186..2c373ad7edcf 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h @@ -12,9 +12,46 @@ */ #include +#include "dccp.h" -struct sock; -struct dccp_minisock; +static inline int dccp_feat_is_valid_length(u8 type, u8 feature, u8 len) +{ + /* sec. 6.1: Confirm has at least length 3, + * sec. 6.2: Change has at least length 4 */ + if (len < 3) + return 1; + if (len < 4 && (type == DCCPO_CHANGE_L || type == DCCPO_CHANGE_R)) + return 1; + /* XXX: add per-feature length validation (sec. 6.6.8) */ + return 0; +} + +static inline int dccp_feat_is_reserved(const u8 feat) +{ + return (feat > DCCPF_DATA_CHECKSUM && + feat < DCCPF_MIN_CCID_SPECIFIC) || + feat == DCCPF_RESERVED; +} + +/* feature negotiation knows only these four option types (RFC 4340, sec. 6) */ +static inline int dccp_feat_is_valid_type(const u8 optnum) +{ + return optnum >= DCCPO_CHANGE_L && optnum <= DCCPO_CONFIRM_R; + +} + +#ifdef CONFIG_IP_DCCP_DEBUG +extern const char *dccp_feat_typename(const u8 type); +extern const char *dccp_feat_name(const u8 feat); + +static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val) +{ + dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type), + dccp_feat_name(feat), feat, val); +} +#else +#define dccp_feat_debug(type, feat, val) +#endif /* CONFIG_IP_DCCP_DEBUG */ extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, u8 *val, u8 len, gfp_t gfp); diff --git a/net/dccp/options.c b/net/dccp/options.c index 121e794fe454..2d0ef27f4ab9 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -465,8 +465,10 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, if (len) memcpy(to, val, len); - dccp_pr_debug("option %d feat %d len %d\n", type, feat, len); + dccp_pr_debug("%s(%s (%d), ...), length %d\n", + dccp_feat_typename(type), + dccp_feat_name(feat), feat, len); return 0; } -- cgit v1.2.3-71-gd317 From 09dbc3895e3242346bd434dae743c456fd28fc6a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 14 Nov 2006 12:57:34 -0200 Subject: [DCCP]: Miscellaneous code tidy-ups This patch does not change code; it performs some trivial clean/tidy-ups: * removal of a `debug_prefix' string in favour of the already existing dccp_role(sk) * add documentation of structures and constants * separated out the cases for invalid packets (step 1 of the packet validation) * removing duplicate statements * combining declaration & initialisation Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 18 +++++++++++++++++- net/dccp/ackvec.c | 27 ++++++--------------------- net/dccp/ipv4.c | 39 +++++++++++++++++++-------------------- net/dccp/ipv6.c | 6 ++---- net/dccp/options.c | 18 +++++++----------- net/dccp/output.c | 1 + net/dccp/proto.c | 8 ++------ 7 files changed, 54 insertions(+), 63 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 696319ee2d5b..d308f1228b61 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -209,6 +209,7 @@ struct dccp_so_feat { #define DCCP_SOCKOPT_CCID_RX_INFO 128 #define DCCP_SOCKOPT_CCID_TX_INFO 192 +/* maximum number of services provided on the same listening port */ #define DCCP_SERVICE_LIST_MAX_LEN 32 #ifdef __KERNEL__ @@ -355,6 +356,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) * @dccpms_ccid - Congestion Control Id (CCID) (section 10) * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5) * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2) + * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3) + * @dccpms_pending - List of features being negotiated + * @dccpms_conf - */ struct dccp_minisock { __u64 dccpms_sequence_window; @@ -452,14 +456,26 @@ struct dccp_ackvec; * @dccps_gss - greatest sequence number sent * @dccps_gsr - greatest valid sequence number received * @dccps_gar - greatest valid ack number received on a non-Sync; initialized to %dccps_iss + * @dccps_service - first (passive sock) or unique (active sock) service code + * @dccps_service_list - second .. last service code on passive socket * @dccps_timestamp_time - time of latest TIMESTAMP option * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option * @dccps_packet_size - Set thru setsockopt - * @dccps_role - Role of this sock, one of %dccp_role + * @dccps_l_ack_ratio - + * @dccps_r_ack_ratio - * @dccps_pcslen - sender partial checksum coverage (via sockopt) * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) * @dccps_ndp_count - number of Non Data Packets since last data packet + * @dccps_mss_cache - + * @dccps_minisock - * @dccps_hc_rx_ackvec - rx half connection ack vector + * @dccps_hc_rx_ccid - + * @dccps_hc_tx_ccid - + * @dccps_options_received - + * @dccps_epoch - + * @dccps_role - Role of this sock, one of %dccp_role + * @dccps_hc_rx_insert_options - + * @dccps_hc_tx_insert_options - * @dccps_xmit_timer - timer for when CCID is not ready to send */ struct dccp_sock { diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index f8208874ac7d..0c54b89a4e9b 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -67,10 +67,6 @@ static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); -#ifdef CONFIG_IP_DCCP_DEBUG - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT tx: " : "server tx: "; -#endif struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; int len = av->dccpav_vec_len + 2; struct timeval now; @@ -129,9 +125,9 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) dccp_ackvec_insert_avr(av, avr); - dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " + dccp_pr_debug("%s ACK Vector 0, len=%d, ack_seqno=%llu, " "ack_ackno=%llu\n", - debug_prefix, avr->dccpavr_sent_len, + dccp_role(sk), avr->dccpavr_sent_len, (unsigned long long)avr->dccpavr_ack_seqno, (unsigned long long)avr->dccpavr_ack_ackno); return 0; @@ -380,14 +376,9 @@ void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, */ list_for_each_entry_reverse(avr, &av->dccpav_records, dccpavr_node) { if (ackno == avr->dccpavr_ack_seqno) { -#ifdef CONFIG_IP_DCCP_DEBUG - struct dccp_sock *dp = dccp_sk(sk); - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx ack: " : "server rx ack: "; -#endif - dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " + dccp_pr_debug("%s ACK packet 0, len=%d, ack_seqno=%llu, " "ack_ackno=%llu, ACKED!\n", - debug_prefix, 1, + dccp_role(sk), 1, (unsigned long long)avr->dccpavr_ack_seqno, (unsigned long long)avr->dccpavr_ack_ackno); dccp_ackvec_throw_record(av, avr); @@ -437,16 +428,10 @@ found: if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) { const u8 state = *vector & DCCP_ACKVEC_STATE_MASK; if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { -#ifdef CONFIG_IP_DCCP_DEBUG - struct dccp_sock *dp = dccp_sk(sk); - const char *debug_prefix = - dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx ack: " : "server rx ack: "; -#endif - dccp_pr_debug("%sACK vector 0, len=%d, " + dccp_pr_debug("%s ACK vector 0, len=%d, " "ack_seqno=%llu, ack_ackno=%llu, " "ACKED!\n", - debug_prefix, len, + dccp_role(sk), len, (unsigned long long) avr->dccpavr_ack_seqno, (unsigned long long) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 61c09014dade..34d6d197c3b2 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -518,7 +518,7 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) sizeof(struct dccp_hdr_reset); struct sk_buff *skb; struct dst_entry *dst; - u64 seqno; + u64 seqno = 0; /* Never send a reset in response to a reset. */ if (rxdh->dccph_type == DCCP_PKT_RESET) @@ -552,13 +552,11 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) DCCP_SKB_CB(rxskb)->dccpd_reset_code; /* See "8.3.1. Abnormal Termination" in RFC 4340 */ - seqno = 0; if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); dccp_hdr_set_seq(dh, seqno); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), - DCCP_SKB_CB(rxskb)->dccpd_seq); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); dccp_csum_outgoing(skb); dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr, @@ -734,6 +732,11 @@ discard: EXPORT_SYMBOL_GPL(dccp_v4_do_rcv); +/** + * dccp_invalid_packet - check for malformed packets + * Implements RFC 4340, 8.5: Step 1: Check header basics + * Packets that fail these checks are ignored and do not receive Resets. + */ int dccp_invalid_packet(struct sk_buff *skb) { const struct dccp_hdr *dh; @@ -742,6 +745,7 @@ int dccp_invalid_packet(struct sk_buff *skb) if (skb->pkt_type != PACKET_HOST) return 1; + /* If the packet is shorter than 12 bytes, drop packet and return */ if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: pskb_may_pull failed\n"); return 1; @@ -749,42 +753,37 @@ int dccp_invalid_packet(struct sk_buff *skb) dh = dccp_hdr(skb); - /* If the packet type is not understood, drop packet and return */ + /* If P.type is not understood, drop packet and return */ if (dh->dccph_type >= DCCP_PKT_INVALID) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: invalid packet type\n"); return 1; } /* - * If P.Data Offset is too small for packet type, or too large for - * packet, drop packet and return + * If P.Data Offset is too small for packet type, drop packet and return */ if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) " - "too small 1\n", - dh->dccph_doff); + "too small\n", dh->dccph_doff); return 1; } - + /* + * If P.Data Offset is too too large for packet, drop packet and return + */ if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) " - "too small 2\n", - dh->dccph_doff); + "too large\n", dh->dccph_doff); return 1; } - dh = dccp_hdr(skb); - /* * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet * has short sequence numbers), drop packet and return */ - if (dh->dccph_x == 0 && - dh->dccph_type != DCCP_PKT_DATA && - dh->dccph_type != DCCP_PKT_ACK && - dh->dccph_type != DCCP_PKT_DATAACK) { - LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data, Ack " - "nor DataAck and P.X == 0\n", + if (dh->dccph_type >= DCCP_PKT_DATA && + dh->dccph_type <= DCCP_PKT_DATAACK && dh->dccph_x == 0) { + LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data||Ack||" + "DataAck, while P.X == 0\n", dccp_packet_name(dh->dccph_type)); return 1; } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 2165b1740c7c..fc326173c215 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -318,7 +318,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) sizeof(struct dccp_hdr_reset); struct sk_buff *skb; struct flowi fl; - u64 seqno; + u64 seqno = 0; if (rxdh->dccph_type == DCCP_PKT_RESET) return; @@ -345,13 +345,11 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) DCCP_SKB_CB(rxskb)->dccpd_reset_code; /* See "8.3.1. Abnormal Termination" in RFC 4340 */ - seqno = 0; if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); dccp_hdr_set_seq(dh, seqno); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), - DCCP_SKB_CB(rxskb)->dccpd_seq); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); dccp_csum_outgoing(skb); dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr, diff --git a/net/dccp/options.c b/net/dccp/options.c index 2d0ef27f4ab9..7e50678e2471 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -60,10 +60,6 @@ static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) int dccp_parse_options(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); -#ifdef CONFIG_IP_DCCP_DEBUG - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx opt: " : "server rx opt: "; -#endif const struct dccp_hdr *dh = dccp_hdr(skb); const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); @@ -119,7 +115,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) goto out_invalid_option; opt_recv->dccpor_ndp = dccp_decode_value_var(value, len); - dccp_pr_debug("%sNDP count=%d\n", debug_prefix, + dccp_pr_debug("%s rx opt: NDP count=%d\n", dccp_role(sk), opt_recv->dccpor_ndp); break; case DCCPO_CHANGE_L: @@ -165,8 +161,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; dccp_timestamp(sk, &dp->dccps_timestamp_time); - dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n", - debug_prefix, opt_recv->dccpor_timestamp, + dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n", + dccp_role(sk), opt_recv->dccpor_timestamp, (unsigned long long) DCCP_SKB_CB(skb)->dccpd_ack_seq); break; @@ -176,8 +172,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value); - dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", - debug_prefix, + dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, " + "ackno=%llu, ", dccp_role(sk), opt_recv->dccpor_timestamp_echo, len + 2, (unsigned long long) @@ -211,8 +207,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) if (elapsed_time > opt_recv->dccpor_elapsed_time) opt_recv->dccpor_elapsed_time = elapsed_time; - dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix, - elapsed_time); + dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n", + dccp_role(sk), elapsed_time); break; /* * From RFC 4340, sec. 10.3: diff --git a/net/dccp/output.c b/net/dccp/output.c index ef22f3cc791a..c34eada7f025 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -333,6 +333,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, return NULL; } + /* Build and checksum header */ dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_sport = inet_sk(sk)->sport; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 9c9c08cffdaf..0225bdacd3b1 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -452,9 +452,8 @@ out_free_val: static int do_dccp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - struct dccp_sock *dp; - int err; - int val; + struct dccp_sock *dp = dccp_sk(sk); + int val, err = 0; if (optlen < sizeof(int)) return -EINVAL; @@ -466,9 +465,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, return dccp_setsockopt_service(sk, val, optval, optlen); lock_sock(sk); - dp = dccp_sk(sk); - err = 0; - switch (optname) { case DCCP_SOCKOPT_PACKET_SIZE: dp->dccps_packet_size = val; -- cgit v1.2.3-71-gd317 From 93ec2c723e3f8a216dde2899aeb85c648672bc6b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:50 -0700 Subject: netpoll info leak After looking harder, Steve noticed that the netpoll beast leaked a little every time it shutdown for a nap. Not a big leak, but a nuisance kind of thing. He took out his refcount duct tape and patched the leak. It was overkill since there was already other locking in that area, but it looked clean and wouldn't attract fleas. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 1 + net/core/netpoll.c | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 1efe60c5c00c..39845fc975f9 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -25,6 +25,7 @@ struct netpoll { }; struct netpoll_info { + atomic_t refcnt; spinlock_t poll_lock; int poll_owner; int tries; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 4de62f1f4134..c66df2f45d26 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -658,8 +658,11 @@ int netpoll_setup(struct netpoll *np) npinfo->tries = MAX_RETRIES; spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); - } else + atomic_set(&npinfo->refcnt, 1); + } else { npinfo = ndev->npinfo; + atomic_inc(&npinfo->refcnt); + } if (!ndev->poll_controller) { printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", @@ -766,12 +769,22 @@ void netpoll_cleanup(struct netpoll *np) if (np->dev) { npinfo = np->dev->npinfo; - if (npinfo && npinfo->rx_np == np) { - spin_lock_irqsave(&npinfo->rx_lock, flags); - npinfo->rx_np = NULL; - npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; - spin_unlock_irqrestore(&npinfo->rx_lock, flags); + if (npinfo) { + if (npinfo->rx_np == np) { + spin_lock_irqsave(&npinfo->rx_lock, flags); + npinfo->rx_np = NULL; + npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; + spin_unlock_irqrestore(&npinfo->rx_lock, flags); + } + + np->dev->npinfo = NULL; + if (atomic_dec_and_test(&npinfo->refcnt)) { + skb_queue_purge(&npinfo->arp_tx); + + kfree(npinfo); + } } + dev_put(np->dev); } -- cgit v1.2.3-71-gd317 From b6cd27ed33886a5ffaf0925a6d98e13e18e8a1af Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:51 -0700 Subject: netpoll per device txq When the netpoll beast got really busy, it tended to clog things, so it stored them for later. But the beast was putting all it's skb's in one basket. This was bad because maybe some pipes were clogged and others were not. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 2 ++ net/core/netpoll.c | 50 +++++++++++++++---------------------------------- 2 files changed, 17 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 39845fc975f9..93a8b7664423 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -33,6 +33,8 @@ struct netpoll_info { spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ struct sk_buff_head arp_tx; /* list of arp requests to reply to */ + struct sk_buff_head txq; + struct work_struct tx_work; }; void netpoll_poll(struct netpoll *np); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index c66df2f45d26..ac4e8b8f57d1 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -38,10 +38,6 @@ static struct sk_buff_head skb_pool; -static DEFINE_SPINLOCK(queue_lock); -static int queue_depth; -static struct sk_buff *queue_head, *queue_tail; - static atomic_t trapped; #define NETPOLL_RX_ENABLED 1 @@ -56,46 +52,25 @@ static void arp_reply(struct sk_buff *skb); static void queue_process(void *p) { - unsigned long flags; + struct netpoll_info *npinfo = p; struct sk_buff *skb; - while (queue_head) { - spin_lock_irqsave(&queue_lock, flags); - - skb = queue_head; - queue_head = skb->next; - if (skb == queue_tail) - queue_head = NULL; - - queue_depth--; - - spin_unlock_irqrestore(&queue_lock, flags); - + while ((skb = skb_dequeue(&npinfo->txq))) dev_queue_xmit(skb); - } -} -static DECLARE_WORK(send_queue, queue_process, NULL); +} void netpoll_queue(struct sk_buff *skb) { - unsigned long flags; + struct net_device *dev = skb->dev; + struct netpoll_info *npinfo = dev->npinfo; - if (queue_depth == MAX_QUEUE_DEPTH) { - __kfree_skb(skb); - return; + if (!npinfo) + kfree_skb(skb); + else { + skb_queue_tail(&npinfo->txq, skb); + schedule_work(&npinfo->tx_work); } - - spin_lock_irqsave(&queue_lock, flags); - if (!queue_head) - queue_head = skb; - else - queue_tail->next = skb; - queue_tail = skb; - queue_depth++; - spin_unlock_irqrestore(&queue_lock, flags); - - schedule_work(&send_queue); } static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, @@ -658,6 +633,9 @@ int netpoll_setup(struct netpoll *np) npinfo->tries = MAX_RETRIES; spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); + skb_queue_head_init(&npinfo->txq); + INIT_WORK(&npinfo->tx_work, queue_process, npinfo); + atomic_set(&npinfo->refcnt, 1); } else { npinfo = ndev->npinfo; @@ -780,6 +758,8 @@ void netpoll_cleanup(struct netpoll *np) np->dev->npinfo = NULL; if (atomic_dec_and_test(&npinfo->refcnt)) { skb_queue_purge(&npinfo->arp_tx); + skb_queue_purge(&npinfo->txq); + flush_scheduled_work(); kfree(npinfo); } -- cgit v1.2.3-71-gd317 From 2bdfe0baeca0e2750037b8fba71905c00ac3c515 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:54 -0700 Subject: netpoll retry cleanup The netpoll beast was still not happy. If the beast got clogged pipes, it tended to stare blankly off in space for a long time. The problem couldn't be completely fixed because the beast talked with irq's disabled. But it could be made less painful and shorter. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 1 - net/core/netpoll.c | 71 +++++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 93a8b7664423..c65d12ec7bb0 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -28,7 +28,6 @@ struct netpoll_info { atomic_t refcnt; spinlock_t poll_lock; int poll_owner; - int tries; int rx_flags; spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 93cb828f3aaf..6b34c394672f 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -34,12 +34,12 @@ #define MAX_UDP_CHUNK 1460 #define MAX_SKBS 32 #define MAX_QUEUE_DEPTH (MAX_SKBS / 2) -#define MAX_RETRIES 20000 static struct sk_buff_head skb_pool; static atomic_t trapped; +#define USEC_PER_POLL 50 #define NETPOLL_RX_ENABLED 1 #define NETPOLL_RX_DROP 2 @@ -72,6 +72,7 @@ static void queue_process(void *p) schedule_delayed_work(&npinfo->tx_work, HZ/10); return; } + netif_tx_unlock_bh(dev); } } @@ -244,50 +245,44 @@ repeat: static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) { - int status; - struct netpoll_info *npinfo; + int status = NETDEV_TX_BUSY; + unsigned long tries; + struct net_device *dev = np->dev; + struct netpoll_info *npinfo = np->dev->npinfo; + + if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) { + __kfree_skb(skb); + return; + } + + /* don't get messages out of order, and no recursion */ + if ( !(np->drop == netpoll_queue && skb_queue_len(&npinfo->txq)) + && npinfo->poll_owner != smp_processor_id() + && netif_tx_trylock(dev)) { + + /* try until next clock tick */ + for(tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) { + if (!netif_queue_stopped(dev)) + status = dev->hard_start_xmit(skb, dev); + + if (status == NETDEV_TX_OK) + break; - if (!np || !np->dev || !netif_running(np->dev)) { - __kfree_skb(skb); - return; - } + /* tickle device maybe there is some cleanup */ + netpoll_poll(np); - npinfo = np->dev->npinfo; + udelay(USEC_PER_POLL); + } + netif_tx_unlock(dev); + } - /* avoid recursion */ - if (npinfo->poll_owner == smp_processor_id() || - np->dev->xmit_lock_owner == smp_processor_id()) { + if (status != NETDEV_TX_OK) { + /* requeue for later */ if (np->drop) np->drop(skb); else __kfree_skb(skb); - return; } - - do { - npinfo->tries--; - netif_tx_lock(np->dev); - - /* - * network drivers do not expect to be called if the queue is - * stopped. - */ - status = NETDEV_TX_BUSY; - if (!netif_queue_stopped(np->dev)) - status = np->dev->hard_start_xmit(skb, np->dev); - - netif_tx_unlock(np->dev); - - /* success */ - if(!status) { - npinfo->tries = MAX_RETRIES; /* reset */ - return; - } - - /* transmit busy */ - netpoll_poll(np); - udelay(50); - } while (npinfo->tries > 0); } void netpoll_send_udp(struct netpoll *np, const char *msg, int len) @@ -649,7 +644,7 @@ int netpoll_setup(struct netpoll *np) npinfo->rx_np = NULL; spin_lock_init(&npinfo->poll_lock); npinfo->poll_owner = -1; - npinfo->tries = MAX_RETRIES; + spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); skb_queue_head_init(&npinfo->txq); -- cgit v1.2.3-71-gd317 From 5de4a473bda49554e4e9bd93b78f43c49a7ea69c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:55 -0700 Subject: netpoll queue cleanup The beast had a long and not very happy history. At one point, a friend (netdump) had asked that he open up a little. Well, the friend was long gone now, and the beast had this dangling piece hanging (netpoll_queue). It wasn't hard to stitch the netpoll_queue back in where it belonged and make everything tidy. Signed-off-by: Stephen Hemminger --- drivers/net/netconsole.c | 1 - include/linux/netpoll.h | 4 ++-- net/core/netpoll.c | 23 +++-------------------- 3 files changed, 5 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e6e8a9797b6d..69233f6aa05c 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -60,7 +60,6 @@ static struct netpoll np = { .local_port = 6665, .remote_port = 6666, .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - .drop = netpoll_queue, }; static int configured = 0; diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index c65d12ec7bb0..b7eb008c43de 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -18,7 +18,7 @@ struct netpoll { struct net_device *dev; char dev_name[16], *name; void (*rx_hook)(struct netpoll *, int, char *, int); - void (*drop)(struct sk_buff *skb); + u32 local_ip, remote_ip; u16 local_port, remote_port; unsigned char local_mac[6], remote_mac[6]; @@ -44,7 +44,7 @@ int netpoll_trap(void); void netpoll_set_trap(int trap); void netpoll_cleanup(struct netpoll *np); int __netpoll_rx(struct sk_buff *skb); -void netpoll_queue(struct sk_buff *skb); + #ifdef CONFIG_NETPOLL static inline int netpoll_rx(struct sk_buff *skb) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 6b34c394672f..0d1de3c47a01 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -77,19 +77,6 @@ static void queue_process(void *p) } } -void netpoll_queue(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct netpoll_info *npinfo = dev->npinfo; - - if (!npinfo) - kfree_skb(skb); - else { - skb_queue_tail(&npinfo->txq, skb); - schedule_work(&npinfo->tx_work); - } -} - static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, unsigned short ulen, u32 saddr, u32 daddr) { @@ -256,7 +243,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) } /* don't get messages out of order, and no recursion */ - if ( !(np->drop == netpoll_queue && skb_queue_len(&npinfo->txq)) + if ( skb_queue_len(&npinfo->txq) == 0 && npinfo->poll_owner != smp_processor_id() && netif_tx_trylock(dev)) { @@ -277,11 +264,8 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) } if (status != NETDEV_TX_OK) { - /* requeue for later */ - if (np->drop) - np->drop(skb); - else - __kfree_skb(skb); + skb_queue_tail(&npinfo->txq, skb); + schedule_work(&npinfo->tx_work); } } @@ -809,4 +793,3 @@ EXPORT_SYMBOL(netpoll_setup); EXPORT_SYMBOL(netpoll_cleanup); EXPORT_SYMBOL(netpoll_send_udp); EXPORT_SYMBOL(netpoll_poll); -EXPORT_SYMBOL(netpoll_queue); -- cgit v1.2.3-71-gd317 From bf6bce71eae386dbc37f93af7e5ad173450d9945 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Oct 2006 15:46:56 -0700 Subject: netpoll header cleanup As Steve left netpoll beast, hopefully not to return soon. He noticed that the header was messy. He straightened it up and polished it a little, then waved goodbye. Signed-off-by: Stephen Hemminger --- include/linux/netpoll.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index b7eb008c43de..2cc9867b1626 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -12,16 +12,15 @@ #include #include -struct netpoll; - struct netpoll { struct net_device *dev; - char dev_name[16], *name; + char dev_name[IFNAMSIZ]; + const char *name; void (*rx_hook)(struct netpoll *, int, char *, int); u32 local_ip, remote_ip; u16 local_port, remote_port; - unsigned char local_mac[6], remote_mac[6]; + u8 local_mac[ETH_ALEN], remote_mac[ETH_ALEN]; }; struct netpoll_info { -- cgit v1.2.3-71-gd317 From cfb6eeb4c860592edd123fdea908d23c6ad1c7dc Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 14 Nov 2006 19:07:45 -0800 Subject: [TCP]: MD5 Signature Option (RFC2385) support. Based on implementation by Rick Payne. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- CREDITS | 3 + include/linux/tcp.h | 35 ++- include/net/request_sock.h | 3 +- include/net/tcp.h | 143 ++++++++++ include/net/timewait_sock.h | 3 + net/dccp/ipv4.c | 6 +- net/dccp/ipv6.c | 6 +- net/dccp/minisocks.c | 2 +- net/ipv4/Kconfig | 16 ++ net/ipv4/tcp.c | 137 +++++++++ net/ipv4/tcp_input.c | 8 + net/ipv4/tcp_ipv4.c | 673 ++++++++++++++++++++++++++++++++++++++++++-- net/ipv4/tcp_minisocks.c | 64 ++++- net/ipv4/tcp_output.c | 111 +++++++- net/ipv6/tcp_ipv6.c | 568 +++++++++++++++++++++++++++++++++++-- 15 files changed, 1714 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/CREDITS b/CREDITS index ccd4f9f4dd71..d0880082c19b 100644 --- a/CREDITS +++ b/CREDITS @@ -2598,6 +2598,9 @@ S: Ucitelska 1576 S: Prague 8 S: 182 00 Czech Republic +N: Rick Payne +D: RFC2385 Support for TCP + N: Barak A. Pearlmutter E: bap@cs.unm.edu W: http://www.cs.unm.edu/~bap/ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 2d36f6db3706..0aecfc955591 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -19,6 +19,7 @@ #include #include +#include struct tcphdr { __be16 source; @@ -94,6 +95,7 @@ enum { #define TCP_INFO 11 /* Information about this connection. */ #define TCP_QUICKACK 12 /* Block/reenable quick acks */ #define TCP_CONGESTION 13 /* Congestion control algorithm */ +#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */ #define TCPI_OPT_TIMESTAMPS 1 #define TCPI_OPT_SACK 2 @@ -157,6 +159,17 @@ struct tcp_info __u32 tcpi_total_retrans; }; +/* for TCP_MD5SIG socket option */ +#define TCP_MD5SIG_MAXKEYLEN 80 + +struct tcp_md5sig { + struct __kernel_sockaddr_storage tcpm_addr; /* address associated */ + __u16 __tcpm_pad1; /* zero */ + __u16 tcpm_keylen; /* key length */ + __u32 __tcpm_pad2; /* zero */ + __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ +}; + #ifdef __KERNEL__ #include @@ -197,9 +210,13 @@ struct tcp_options_received { }; struct tcp_request_sock { - struct inet_request_sock req; - __u32 rcv_isn; - __u32 snt_isn; + struct inet_request_sock req; +#ifdef CONFIG_TCP_MD5SIG + /* Only used by TCP MD5 Signature so far. */ + struct tcp_request_sock_ops *af_specific; +#endif + __u32 rcv_isn; + __u32 snt_isn; }; static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) @@ -363,6 +380,14 @@ struct tcp_sock { __u32 probe_seq_start; __u32 probe_seq_end; } mtu_probe; + +#ifdef CONFIG_TCP_MD5SIG +/* TCP AF-Specific parts; only used by MD5 Signature support so far */ + struct tcp_sock_af_ops *af_specific; + +/* TCP MD5 Signagure Option information */ + struct tcp_md5sig_info *md5sig_info; +#endif }; static inline struct tcp_sock *tcp_sk(const struct sock *sk) @@ -377,6 +402,10 @@ struct tcp_timewait_sock { __u32 tw_rcv_wnd; __u32 tw_ts_recent; long tw_ts_recent_stamp; +#ifdef CONFIG_TCP_MD5SIG + __u16 tw_md5_keylen; + __u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; +#endif }; static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index b5b023e79e5f..e37baaf2080b 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -35,7 +35,8 @@ struct request_sock_ops { struct dst_entry *dst); void (*send_ack)(struct sk_buff *skb, struct request_sock *req); - void (*send_reset)(struct sk_buff *skb); + void (*send_reset)(struct sock *sk, + struct sk_buff *skb); void (*destructor)(struct request_sock *req); }; diff --git a/include/net/tcp.h b/include/net/tcp.h index e1a5d29d0a1f..363960872de0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -161,6 +162,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOPT_SACK_PERM 4 /* SACK Permitted */ #define TCPOPT_SACK 5 /* SACK Block */ #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ +#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ /* * TCP option lengths @@ -170,6 +172,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_WINDOW 3 #define TCPOLEN_SACK_PERM 2 #define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_MD5SIG 18 /* But this is what stacks really send out. */ #define TCPOLEN_TSTAMP_ALIGNED 12 @@ -178,6 +181,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_SACK_BASE 2 #define TCPOLEN_SACK_BASE_ALIGNED 4 #define TCPOLEN_SACK_PERBLOCK 8 +#define TCPOLEN_MD5SIG_ALIGNED 20 /* Flags in tp->nonagle */ #define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ @@ -299,6 +303,8 @@ extern void tcp_cleanup_rbuf(struct sock *sk, int copied); extern int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); +extern void tcp_twsk_destructor(struct sock *sk); + static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { @@ -1064,6 +1070,114 @@ static inline void clear_all_retrans_hints(struct tcp_sock *tp){ tp->fastpath_skb_hint = NULL; } +/* MD5 Signature */ +struct crypto_hash; + +/* - key database */ +struct tcp_md5sig_key { + u8 *key; + u8 keylen; +}; + +struct tcp4_md5sig_key { + u8 *key; + u16 keylen; + __be32 addr; +}; + +struct tcp6_md5sig_key { + u8 *key; + u16 keylen; +#if 0 + u32 scope_id; /* XXX */ +#endif + struct in6_addr addr; +}; + +/* - sock block */ +struct tcp_md5sig_info { + struct tcp4_md5sig_key *keys4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct tcp6_md5sig_key *keys6; + u32 entries6; + u32 alloced6; +#endif + u32 entries4; + u32 alloced4; +}; + +/* - pseudo header */ +struct tcp4_pseudohdr { + __be32 saddr; + __be32 daddr; + __u8 pad; + __u8 protocol; + __be16 len; +}; + +struct tcp6_pseudohdr { + struct in6_addr saddr; + struct in6_addr daddr; + __be32 len; + __be32 protocol; /* including padding */ +}; + +union tcp_md5sum_block { + struct tcp4_pseudohdr ip4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct tcp6_pseudohdr ip6; +#endif +}; + +/* - pool: digest algorithm, hash description and scratch buffer */ +struct tcp_md5sig_pool { + struct hash_desc md5_desc; + union tcp_md5sum_block md5_blk; +}; + +#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ + +/* - functions */ +extern int tcp_v4_calc_md5_hash(char *md5_hash, + struct tcp_md5sig_key *key, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, + int protocol, int tcplen); +extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, + struct sock *addr_sk); + +extern int tcp_v4_md5_do_add(struct sock *sk, + __be32 addr, + u8 *newkey, + u8 newkeylen); + +extern int tcp_v4_md5_do_del(struct sock *sk, + u32 addr); + +extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void); +extern void tcp_free_md5sig_pool(void); + +extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); +extern void __tcp_put_md5sig_pool(void); + +static inline +struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) +{ + int cpu = get_cpu(); + struct tcp_md5sig_pool *ret = __tcp_get_md5sig_pool(cpu); + if (!ret) + put_cpu(); + return ret; +} + +static inline void tcp_put_md5sig_pool(void) +{ + __tcp_put_md5sig_pool(); + put_cpu(); +} + /* /proc */ enum tcp_seq_states { TCP_SEQ_STATE_LISTENING, @@ -1103,6 +1217,35 @@ extern int tcp4_proc_init(void); extern void tcp4_proc_exit(void); #endif +/* TCP af-specific functions */ +struct tcp_sock_af_ops { +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk, + struct sock *addr_sk); + int (*calc_md5_hash) (char *location, + struct tcp_md5sig_key *md5, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, + int protocol, int len); + int (*md5_add) (struct sock *sk, + struct sock *addr_sk, + u8 *newkey, + u8 len); + int (*md5_parse) (struct sock *sk, + char __user *optval, + int optlen); +#endif +}; + +struct tcp_request_sock_ops { +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk, + struct request_sock *req); +#endif +}; + extern void tcp_v4_init(struct net_proto_family *ops); extern void tcp_init(void); diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h index be293d795e38..d7a306ea560d 100644 --- a/include/net/timewait_sock.h +++ b/include/net/timewait_sock.h @@ -31,6 +31,9 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) static inline void twsk_destructor(struct sock *sk) { + BUG_ON(sk == NULL); + BUG_ON(sk->sk_prot == NULL); + BUG_ON(sk->sk_prot->twsk_prot == NULL); if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) sk->sk_prot->twsk_prot->twsk_destructor(sk); } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 34d6d197c3b2..35985334daee 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -509,7 +509,7 @@ out: return err; } -static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) +static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) { int err; struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; @@ -724,7 +724,7 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; reset: - dccp_v4_ctl_send_reset(skb); + dccp_v4_ctl_send_reset(sk, skb); discard: kfree_skb(skb); return 0; @@ -913,7 +913,7 @@ no_dccp_socket: if (dh->dccph_type != DCCP_PKT_RESET) { DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; - dccp_v4_ctl_send_reset(skb); + dccp_v4_ctl_send_reset(sk, skb); } discard_it: diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index fc326173c215..e0a0607862ef 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -310,7 +310,7 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req) kfree_skb(inet6_rsk(req)->pktopts); } -static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) +static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) { struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + @@ -805,7 +805,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; reset: - dccp_v6_ctl_send_reset(skb); + dccp_v6_ctl_send_reset(sk, skb); discard: if (opt_skb != NULL) __kfree_skb(opt_skb); @@ -902,7 +902,7 @@ no_dccp_socket: if (dh->dccph_type != DCCP_PKT_RESET) { DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; - dccp_v6_ctl_send_reset(skb); + dccp_v6_ctl_send_reset(sk, skb); } discard_it: diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 0c49733f5be1..3975048d8094 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -246,7 +246,7 @@ listen_overflow: DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; drop: if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET) - req->rsk_ops->send_reset(skb); + req->rsk_ops->send_reset(sk, skb); inet_csk_reqsk_queue_drop(sk, req, prev); goto out; diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index bc298bcc344e..39e0cb763588 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -618,5 +618,21 @@ config DEFAULT_TCP_CONG default "reno" if DEFAULT_RENO default "cubic" +config TCP_MD5SIG + bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)" + depends on EXPERIMENTAL + select CRYPTO + select CRYPTO_MD5 + ---help--- + RFC2385 specifices a method of giving MD5 protection to TCP sessions. + Its main (only?) use is to protect BGP sessions between core routers + on the Internet. + + If unsure, say N. + +config TCP_MD5SIG_DEBUG + bool "TCP: MD5 Signature Option debugging" + depends on TCP_MD5SIG + source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c05e8edaf544..dadef867a3bb 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -258,6 +258,7 @@ #include #include #include +#include #include #include @@ -1942,6 +1943,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level, } break; +#ifdef CONFIG_TCP_MD5SIG + case TCP_MD5SIG: + /* Read the IP->Key mappings from userspace */ + err = tp->af_specific->md5_parse(sk, optval, optlen); + break; +#endif + default: err = -ENOPROTOOPT; break; @@ -2231,6 +2239,135 @@ out: } EXPORT_SYMBOL(tcp_tso_segment); +#ifdef CONFIG_TCP_MD5SIG +static unsigned long tcp_md5sig_users; +static struct tcp_md5sig_pool **tcp_md5sig_pool; +static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); + +static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) +{ + int cpu; + for_each_possible_cpu(cpu) { + struct tcp_md5sig_pool *p = *per_cpu_ptr(pool, cpu); + if (p) { + if (p->md5_desc.tfm) + crypto_free_hash(p->md5_desc.tfm); + kfree(p); + p = NULL; + } + } + free_percpu(pool); +} + +void tcp_free_md5sig_pool(void) +{ + struct tcp_md5sig_pool **pool = NULL; + + spin_lock(&tcp_md5sig_pool_lock); + if (--tcp_md5sig_users == 0) { + pool = tcp_md5sig_pool; + tcp_md5sig_pool = NULL; + } + spin_unlock(&tcp_md5sig_pool_lock); + if (pool) + __tcp_free_md5sig_pool(pool); +} + +EXPORT_SYMBOL(tcp_free_md5sig_pool); + +struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) +{ + int cpu; + struct tcp_md5sig_pool **pool; + + pool = alloc_percpu(struct tcp_md5sig_pool *); + if (!pool) + return NULL; + + for_each_possible_cpu(cpu) { + struct tcp_md5sig_pool *p; + struct crypto_hash *hash; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto out_free; + *per_cpu_ptr(pool, cpu) = p; + + hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); + if (!hash || IS_ERR(hash)) + goto out_free; + + p->md5_desc.tfm = hash; + } + return pool; +out_free: + __tcp_free_md5sig_pool(pool); + return NULL; +} + +struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void) +{ + struct tcp_md5sig_pool **pool; + int alloc = 0; + +retry: + spin_lock(&tcp_md5sig_pool_lock); + pool = tcp_md5sig_pool; + if (tcp_md5sig_users++ == 0) { + alloc = 1; + spin_unlock(&tcp_md5sig_pool_lock); + } else if (!pool) { + tcp_md5sig_users--; + spin_unlock(&tcp_md5sig_pool_lock); + cpu_relax(); + goto retry; + } else + spin_unlock(&tcp_md5sig_pool_lock); + + if (alloc) { + /* we cannot hold spinlock here because this may sleep. */ + struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(); + spin_lock(&tcp_md5sig_pool_lock); + if (!p) { + tcp_md5sig_users--; + spin_unlock(&tcp_md5sig_pool_lock); + return NULL; + } + pool = tcp_md5sig_pool; + if (pool) { + /* oops, it has already been assigned. */ + spin_unlock(&tcp_md5sig_pool_lock); + __tcp_free_md5sig_pool(p); + } else { + tcp_md5sig_pool = pool = p; + spin_unlock(&tcp_md5sig_pool_lock); + } + } + return pool; +} + +EXPORT_SYMBOL(tcp_alloc_md5sig_pool); + +struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu) +{ + struct tcp_md5sig_pool **p; + spin_lock(&tcp_md5sig_pool_lock); + p = tcp_md5sig_pool; + if (p) + tcp_md5sig_users++; + spin_unlock(&tcp_md5sig_pool_lock); + return (p ? *per_cpu_ptr(p, cpu) : NULL); +} + +EXPORT_SYMBOL(__tcp_get_md5sig_pool); + +void __tcp_put_md5sig_pool(void) { + __tcp_free_md5sig_pool(tcp_md5sig_pool); +} + +EXPORT_SYMBOL(__tcp_put_md5sig_pool); +#endif + extern void __skb_cb_too_small_for_tcp(int, int); extern struct tcp_congestion_ops tcp_reno; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4a8c96cdec7d..6ab3423674bb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2677,6 +2677,14 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, opt_rx->sack_ok) { TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; } +#ifdef CONFIG_TCP_MD5SIG + case TCPOPT_MD5SIG: + /* + * The MD5 Hash has already been + * checked (see tcp_v{4,6}_do_rcv()). + */ + break; +#endif }; ptr+=opsize-2; length-=opsize; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ad0904bf56c..8c8e8112f98d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -78,6 +78,9 @@ #include #include +#include +#include + int sysctl_tcp_tw_reuse __read_mostly; int sysctl_tcp_low_latency __read_mostly; @@ -89,6 +92,13 @@ static struct socket *tcp_socket; void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); +#ifdef CONFIG_TCP_MD5SIG +static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr); +static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + __be32 saddr, __be32 daddr, struct tcphdr *th, + int protocol, int tcplen); +#endif + struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), .lhash_users = ATOMIC_INIT(0), @@ -526,11 +536,19 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) * Exception: precedence violation. We do not implement it in any case. */ -static void tcp_v4_send_reset(struct sk_buff *skb) +static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) { struct tcphdr *th = skb->h.th; - struct tcphdr rth; + struct { + struct tcphdr th; +#ifdef CONFIG_TCP_MD5SIG + u32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; +#endif + } rep; struct ip_reply_arg arg; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif /* Never send a reset in response to a reset. */ if (th->rst) @@ -540,29 +558,50 @@ static void tcp_v4_send_reset(struct sk_buff *skb) return; /* Swap the send and the receive. */ - memset(&rth, 0, sizeof(struct tcphdr)); - rth.dest = th->source; - rth.source = th->dest; - rth.doff = sizeof(struct tcphdr) / 4; - rth.rst = 1; + memset(&rep, 0, sizeof(rep)); + rep.th.dest = th->source; + rep.th.source = th->dest; + rep.th.doff = sizeof(struct tcphdr) / 4; + rep.th.rst = 1; if (th->ack) { - rth.seq = th->ack_seq; + rep.th.seq = th->ack_seq; } else { - rth.ack = 1; - rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + - skb->len - (th->doff << 2)); + rep.th.ack = 1; + rep.th.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + + skb->len - (th->doff << 2)); } memset(&arg, 0, sizeof arg); - arg.iov[0].iov_base = (unsigned char *)&rth; - arg.iov[0].iov_len = sizeof rth; + arg.iov[0].iov_base = (unsigned char *)&rep; + arg.iov[0].iov_len = sizeof(rep.th); + +#ifdef CONFIG_TCP_MD5SIG + key = sk ? tcp_v4_md5_do_lookup(sk, skb->nh.iph->daddr) : NULL; + if (key) { + rep.opt[0] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + /* Update length and the length the header thinks exists */ + arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; + rep.th.doff = arg.iov[0].iov_len / 4; + + tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], + key, + skb->nh.iph->daddr, + skb->nh.iph->saddr, + &rep.th, IPPROTO_TCP, + arg.iov[0].iov_len); + } +#endif + arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, skb->nh.iph->saddr, /*XXX*/ sizeof(struct tcphdr), IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; - ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth); + ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); @@ -572,15 +611,24 @@ static void tcp_v4_send_reset(struct sk_buff *skb) outside socket context is ugly, certainly. What can I do? */ -static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, +static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, + struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) { struct tcphdr *th = skb->h.th; struct { struct tcphdr th; - u32 tsopt[TCPOLEN_TSTAMP_ALIGNED >> 2]; + u32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) +#ifdef CONFIG_TCP_MD5SIG + + (TCPOLEN_MD5SIG_ALIGNED >> 2) +#endif + ]; } rep; struct ip_reply_arg arg; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; + struct tcp_md5sig_key tw_key; +#endif memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof arg); @@ -588,12 +636,12 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, arg.iov[0].iov_base = (unsigned char *)&rep; arg.iov[0].iov_len = sizeof(rep.th); if (ts) { - rep.tsopt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - rep.tsopt[1] = htonl(tcp_time_stamp); - rep.tsopt[2] = htonl(ts); - arg.iov[0].iov_len = sizeof(rep); + rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | + TCPOLEN_TIMESTAMP); + rep.opt[1] = htonl(tcp_time_stamp); + rep.opt[2] = htonl(ts); + arg.iov[0].iov_len = TCPOLEN_TSTAMP_ALIGNED; } /* Swap the send and the receive. */ @@ -605,6 +653,44 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, rep.th.ack = 1; rep.th.window = htons(win); +#ifdef CONFIG_TCP_MD5SIG + /* + * The SKB holds an imcoming packet, but may not have a valid ->sk + * pointer. This is especially the case when we're dealing with a + * TIME_WAIT ack, because the sk structure is long gone, and only + * the tcp_timewait_sock remains. So the md5 key is stashed in that + * structure, and we use it in preference. I believe that (twsk || + * skb->sk) holds true, but we program defensively. + */ + if (!twsk && skb->sk) { + key = tcp_v4_md5_do_lookup(skb->sk, skb->nh.iph->daddr); + } else if (twsk && twsk->tw_md5_keylen) { + tw_key.key = twsk->tw_md5_key; + tw_key.keylen = twsk->tw_md5_keylen; + key = &tw_key; + } else { + key = NULL; + } + + if (key) { + int offset = (ts) ? 3 : 0; + + rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; + rep.th.doff = arg.iov[0].iov_len/4; + + tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], + key, + skb->nh.iph->daddr, + skb->nh.iph->saddr, + &rep.th, IPPROTO_TCP, + arg.iov[0].iov_len); + } +#endif + arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, skb->nh.iph->saddr, /*XXX*/ arg.iov[0].iov_len, IPPROTO_TCP, 0); @@ -618,9 +704,9 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) { struct inet_timewait_sock *tw = inet_twsk(sk); - const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent); inet_twsk_put(tw); @@ -628,7 +714,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, + tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, + tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); } @@ -714,6 +801,461 @@ static struct ip_options *tcp_v4_save_options(struct sock *sk, return dopt; } +#ifdef CONFIG_TCP_MD5SIG +/* + * RFC2385 MD5 checksumming requires a mapping of + * IP address->MD5 Key. + * We need to maintain these in the sk structure. + */ + +/* Find the Key structure for an address. */ +static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + if (!tp->md5sig_info || !tp->md5sig_info->entries4) + return NULL; + for (i = 0; i < tp->md5sig_info->entries4; i++) { + if (tp->md5sig_info->keys4[i].addr == addr) + return (struct tcp_md5sig_key *)&tp->md5sig_info->keys4[i]; + } + return NULL; +} + +struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, + struct sock *addr_sk) +{ + return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->daddr); +} + +EXPORT_SYMBOL(tcp_v4_md5_lookup); + +struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, + struct request_sock *req) +{ + return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); +} + +/* This can be called on a newly created socket, from other files */ +int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, + u8 *newkey, u8 newkeylen) +{ + /* Add Key to the list */ + struct tcp4_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + struct tcp4_md5sig_key *keys; + + key = (struct tcp4_md5sig_key *) tcp_v4_md5_do_lookup(sk, addr); + if (key) { + /* Pre-existing entry - just update that one. */ + kfree (key->key); + key->key = newkey; + key->keylen = newkeylen; + } else { + if (!tp->md5sig_info) { + tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); + if (!tp->md5sig_info) { + kfree(newkey); + return -ENOMEM; + } + } + if (tcp_alloc_md5sig_pool() == NULL) { + kfree(newkey); + return -ENOMEM; + } + if (tp->md5sig_info->alloced4 == tp->md5sig_info->entries4) { + keys = kmalloc((sizeof(struct tcp4_md5sig_key) * + (tp->md5sig_info->entries4 + 1)), GFP_ATOMIC); + if (!keys) { + kfree(newkey); + tcp_free_md5sig_pool(); + return -ENOMEM; + } + + if (tp->md5sig_info->entries4) + memcpy(keys, tp->md5sig_info->keys4, + (sizeof (struct tcp4_md5sig_key) * + tp->md5sig_info->entries4)); + + /* Free old key list, and reference new one */ + if (tp->md5sig_info->keys4) + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = keys; + tp->md5sig_info->alloced4++; + } + tp->md5sig_info->entries4++; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].addr = addr; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].key = newkey; + tp->md5sig_info->keys4[tp->md5sig_info->entries4 - 1].keylen = newkeylen; + } + return 0; +} + +EXPORT_SYMBOL(tcp_v4_md5_do_add); + +static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, + u8 *newkey, u8 newkeylen) +{ + return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->daddr, + newkey, newkeylen); +} + +int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + for (i = 0; i < tp->md5sig_info->entries4; i++) { + if (tp->md5sig_info->keys4[i].addr == addr) { + /* Free the key */ + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4--; + + if (tp->md5sig_info->entries4 == 0) { + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + } else { + /* Need to do some manipulation */ + if (tp->md5sig_info->entries4 != i) + memcpy(&tp->md5sig_info->keys4[i], + &tp->md5sig_info->keys4[i+1], + (tp->md5sig_info->entries4 - i) + * sizeof (struct tcp4_md5sig_key)); + } + tcp_free_md5sig_pool(); + return 0; + } + } + return -ENOENT; +} + +EXPORT_SYMBOL(tcp_v4_md5_do_del); + +static void tcp_v4_clear_md5_list (struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + /* Free each key, then the set of key keys, + * the crypto element, and then decrement our + * hold on the last resort crypto. + */ + if (tp->md5sig_info->entries4) { + int i; + for (i = 0; i < tp->md5sig_info->entries4; i++) + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4 = 0; + tcp_free_md5sig_pool(); + } + if (tp->md5sig_info->keys4) { + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + tp->md5sig_info->alloced4 = 0; + } +} + +static int tcp_v4_parse_md5_keys (struct sock *sk, char __user *optval, + int optlen) +{ + struct tcp_md5sig cmd; + struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; + u8 *newkey; + + if (optlen < sizeof(cmd)) + return -EINVAL; + + if (copy_from_user (&cmd, optval, sizeof(cmd))) + return -EFAULT; + + if (sin->sin_family != AF_INET) + return -EINVAL; + + if (!cmd.tcpm_key || !cmd.tcpm_keylen) { + if (!tcp_sk(sk)->md5sig_info) + return -ENOENT; + return tcp_v4_md5_do_del(sk, sin->sin_addr.s_addr); + } + + if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) + return -EINVAL; + + if (!tcp_sk(sk)->md5sig_info) { + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_md5sig_info *p; + + p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); + if (!p) + return -EINVAL; + + tp->md5sig_info = p; + + } + + newkey = kmalloc(cmd.tcpm_keylen, GFP_KERNEL); + if (!newkey) + return -ENOMEM; + memcpy(newkey, cmd.tcpm_key, cmd.tcpm_keylen); + return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, + newkey, cmd.tcpm_keylen); +} + +static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + __be32 saddr, __be32 daddr, + struct tcphdr *th, int protocol, + int tcplen) +{ + struct scatterlist sg[4]; + __u16 data_len; + int block = 0; +#ifdef CONFIG_TCP_MD5SIG_DEBUG + int i; +#endif + __u16 old_checksum; + struct tcp_md5sig_pool *hp; + struct tcp4_pseudohdr *bp; + struct hash_desc *desc; + int err; + unsigned int nbytes = 0; + + /* + * Okay, so RFC2385 is turned on for this connection, + * so we need to generate the MD5 hash for the packet now. + */ + + hp = tcp_get_md5sig_pool(); + if (!hp) + goto clear_hash_noput; + + bp = &hp->md5_blk.ip4; + desc = &hp->md5_desc; + + /* + * 1. the TCP pseudo-header (in the order: source IP address, + * destination IP address, zero-padded protocol number, and + * segment length) + */ + bp->saddr = saddr; + bp->daddr = daddr; + bp->pad = 0; + bp->protocol = protocol; + bp->len = htons(tcplen); + sg_set_buf(&sg[block++], bp, sizeof(*bp)); + nbytes += sizeof(*bp); + +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk("Calcuating hash for: "); + for (i = 0; i < sizeof (*bp); i++) + printk ("%02x ", (unsigned int)((unsigned char *)bp)[i]); + printk(" "); +#endif + + /* 2. the TCP header, excluding options, and assuming a + * checksum of zero/ + */ + old_checksum = th->check; + th->check = 0; + sg_set_buf(&sg[block++], th, sizeof(struct tcphdr)); + nbytes += sizeof(struct tcphdr); +#ifdef CONFIG_TCP_MD5SIG_DEBUG + for (i = 0; i < sizeof (struct tcphdr); i++) + printk (" %02x", (unsigned int)((unsigned char *)th)[i]); +#endif + /* 3. the TCP segment data (if any) */ + data_len = tcplen - (th->doff << 2); + if (data_len > 0) { + unsigned char *data = (unsigned char *)th + (th->doff << 2); + sg_set_buf(&sg[block++], data, data_len); + nbytes += data_len; + } + + /* 4. an independently-specified key or password, known to both + * TCPs and presumably connection-specific + */ + sg_set_buf(&sg[block++], key->key, key->keylen); + nbytes += key->keylen; + +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk (" and password: "); + for (i = 0; i < key->keylen; i++) + printk ("%02x ", (unsigned int)key->key[i]); +#endif + + /* Now store the Hash into the packet */ + err = crypto_hash_init(desc); + if (err) + goto clear_hash; + err = crypto_hash_update(desc, sg, nbytes); + if (err) + goto clear_hash; + err = crypto_hash_final(desc, md5_hash); + if (err) + goto clear_hash; + + /* Reset header, and free up the crypto */ + tcp_put_md5sig_pool(); + th->check = old_checksum; + +out: +#ifdef CONFIG_TCP_MD5SIG_DEBUG + printk(" result:"); + for (i = 0; i < 16; i++) + printk (" %02x", (unsigned int)(((u8*)md5_hash)[i])); + printk("\n"); +#endif + return 0; +clear_hash: + tcp_put_md5sig_pool(); +clear_hash_noput: + memset(md5_hash, 0, 16); + goto out; +} + +int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, int protocol, + int tcplen) +{ + __be32 saddr, daddr; + + if (sk) { + saddr = inet_sk(sk)->saddr; + daddr = inet_sk(sk)->daddr; + } else { + struct rtable *rt = (struct rtable *)dst; + BUG_ON(!rt); + saddr = rt->rt_src; + daddr = rt->rt_dst; + } + return tcp_v4_do_calc_md5_hash(md5_hash, key, + saddr, daddr, + th, protocol, tcplen); +} + +EXPORT_SYMBOL(tcp_v4_calc_md5_hash); + +static int tcp_v4_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) +{ + /* + * This gets called for each TCP segment that arrives + * so we want to be efficient. + * We have 3 drop cases: + * o No MD5 hash and one expected. + * o MD5 hash and we're not expecting one. + * o MD5 hash and its wrong. + */ + __u8 *hash_location = NULL; + struct tcp_md5sig_key *hash_expected; + struct iphdr *iph = skb->nh.iph; + struct tcphdr *th = skb->h.th; + int length = (th->doff << 2) - sizeof (struct tcphdr); + int genhash; + unsigned char *ptr; + unsigned char newhash[16]; + + hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); + + /* + * If the TCP option length is less than the TCP_MD5SIG + * option length, then we can shortcut + */ + if (length < TCPOLEN_MD5SIG) { + if (hash_expected) + return 1; + else + return 0; + } + + /* Okay, we can't shortcut - we have to grub through the options */ + ptr = (unsigned char *)(th + 1); + while (length > 0) { + int opcode = *ptr++; + int opsize; + + switch (opcode) { + case TCPOPT_EOL: + goto done_opts; + case TCPOPT_NOP: + length--; + continue; + default: + opsize = *ptr++; + if (opsize < 2) + goto done_opts; + if (opsize > length) + goto done_opts; + + if (opcode == TCPOPT_MD5SIG) { + hash_location = ptr; + goto done_opts; + } + } + ptr += opsize-2; + length -= opsize; + } +done_opts: + /* We've parsed the options - do we have a hash? */ + if (!hash_expected && !hash_location) + return 0; + + if (hash_expected && !hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest)); + } + return 1; + } + + if (!hash_expected && hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest)); + } + return 1; + } + + /* Okay, so this is hash_expected and hash_location - + * so we need to calculate the checksum. + */ + genhash = tcp_v4_do_calc_md5_hash(newhash, + hash_expected, + iph->saddr, iph->daddr, + th, sk->sk_protocol, + skb->len); + + if (genhash || memcmp(hash_location, newhash, 16) != 0) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash failed for " + "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)%s\n", + NIPQUAD (iph->saddr), ntohs(th->source), + NIPQUAD (iph->daddr), ntohs(th->dest), + genhash ? " tcp_v4_calc_md5_hash failed" : ""); +#ifdef CONFIG_TCP_MD5SIG_DEBUG + do { + int i; + printk("Received: "); + for (i = 0; i < 16; i++) + printk("%02x ", 0xff & (int)hash_location[i]); + printk("\n"); + printk("Calculated: "); + for (i = 0; i < 16; i++) + printk("%02x ", 0xff & (int)newhash[i]); + printk("\n"); + } while(0); +#endif + } + return 1; + } + return 0; +} + +#endif + struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), @@ -723,9 +1265,16 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .send_reset = tcp_v4_send_reset, }; +struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_reqsk_md5_lookup, +#endif +}; + static struct timewait_sock_ops tcp_timewait_sock_ops = { .twsk_obj_size = sizeof(struct tcp_timewait_sock), .twsk_unique = tcp_twsk_unique, + .twsk_destructor= tcp_twsk_destructor, }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -773,6 +1322,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (!req) goto drop; +#ifdef CONFIG_TCP_MD5SIG + tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; +#endif + tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = 536; tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; @@ -891,6 +1444,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct inet_sock *newinet; struct tcp_sock *newtp; struct sock *newsk; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif if (sk_acceptq_is_full(sk)) goto exit_overflow; @@ -925,6 +1481,24 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->advmss = dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(newsk); +#ifdef CONFIG_TCP_MD5SIG + /* Copy over the MD5 key from the original socket */ + if ((key = tcp_v4_md5_do_lookup(sk, newinet->daddr)) != NULL) { + /* + * We're using one, so create a matching key + * on the newsk structure. If we fail to get + * memory, then we end up not copying the key + * across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + memcpy(newkey, key->key, key->keylen); + tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, + newkey, key->keylen); + } + } +#endif + __inet_hash(&tcp_hashinfo, newsk, 0); __inet_inherit_port(&tcp_hashinfo, sk, newsk); @@ -1000,10 +1574,24 @@ static int tcp_v4_checksum_init(struct sk_buff *skb) */ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { + struct sock *rsk; +#ifdef CONFIG_TCP_MD5SIG + /* + * We really want to reject the packet as early as possible + * if: + * o We're expecting an MD5'd packet and this is no MD5 tcp option + * o There is an MD5 option and we're not expecting one + */ + if (tcp_v4_inbound_md5_hash (sk, skb)) + goto discard; +#endif + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ TCP_CHECK_TIMER(sk); - if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) + if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) { + rsk = sk; goto reset; + } TCP_CHECK_TIMER(sk); return 0; } @@ -1017,20 +1605,24 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) goto discard; if (nsk != sk) { - if (tcp_child_process(sk, nsk, skb)) + if (tcp_child_process(sk, nsk, skb)) { + rsk = nsk; goto reset; + } return 0; } } TCP_CHECK_TIMER(sk); - if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) + if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) { + rsk = sk; goto reset; + } TCP_CHECK_TIMER(sk); return 0; reset: - tcp_v4_send_reset(skb); + tcp_v4_send_reset(rsk, skb); discard: kfree_skb(skb); /* Be careful here. If this function gets more complicated and @@ -1139,7 +1731,7 @@ no_tcp_socket: bad_packet: TCP_INC_STATS_BH(TCP_MIB_INERRS); } else { - tcp_v4_send_reset(skb); + tcp_v4_send_reset(NULL, skb); } discard_it: @@ -1262,6 +1854,15 @@ struct inet_connection_sock_af_ops ipv4_specific = { #endif }; +struct tcp_sock_af_ops tcp_sock_ipv4_specific = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_md5_lookup, + .calc_md5_hash = tcp_v4_calc_md5_hash, + .md5_add = tcp_v4_md5_add_func, + .md5_parse = tcp_v4_parse_md5_keys, +#endif +}; + /* NOTE: A lot of things set to zero explicitly by call to * sk_alloc() so need not be done here. */ @@ -1301,6 +1902,9 @@ static int tcp_v4_init_sock(struct sock *sk) icsk->icsk_af_ops = &ipv4_specific; icsk->icsk_sync_mss = tcp_sync_mss; +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv4_specific; +#endif sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; @@ -1324,6 +1928,15 @@ int tcp_v4_destroy_sock(struct sock *sk) /* Cleans up our, hopefully empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); +#ifdef CONFIG_TCP_MD5SIG + /* Clean up the MD5 key list, if any */ + if (tp->md5sig_info) { + tcp_v4_clear_md5_list(sk); + kfree(tp->md5sig_info); + tp->md5sig_info = NULL; + } +#endif + #ifdef CONFIG_NET_DMA /* Cleans up our sk_async_wait_queue */ __skb_queue_purge(&sk->sk_async_wait_queue); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 0163d9826907..ac55d8892cf1 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -306,6 +306,28 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tw->tw_ipv6only = np->ipv6only; } #endif + +#ifdef CONFIG_TCP_MD5SIG + /* + * The timewait bucket does not have the key DB from the + * sock structure. We just make a quick copy of the + * md5 key being used (if indeed we are using one) + * so the timewait ack generating code has the key. + */ + do { + struct tcp_md5sig_key *key; + memset(tcptw->tw_md5_key, 0, sizeof(tcptw->tw_md5_key)); + tcptw->tw_md5_keylen = 0; + key = tp->af_specific->md5_lookup(sk, sk); + if (key != NULL) { + memcpy(&tcptw->tw_md5_key, key->key, key->keylen); + tcptw->tw_md5_keylen = key->keylen; + if (tcp_alloc_md5sig_pool() == NULL) + BUG(); + } + } while(0); +#endif + /* Linkage updates. */ __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); @@ -337,6 +359,17 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tcp_done(sk); } +void tcp_twsk_destructor(struct sock *sk) +{ + struct tcp_timewait_sock *twsk = tcp_twsk(sk); +#ifdef CONFIG_TCP_MD5SIG + if (twsk->tw_md5_keylen) + tcp_put_md5sig_pool(); +#endif +} + +EXPORT_SYMBOL_GPL(tcp_twsk_destructor); + /* This is not only more efficient than what we used to do, it eliminates * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM * @@ -435,6 +468,11 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->rx_opt.ts_recent_stamp = 0; newtp->tcp_header_len = sizeof(struct tcphdr); } +#ifdef CONFIG_TCP_MD5SIG + newtp->md5sig_info = NULL; /*XXX*/ + if (newtp->af_specific->md5_lookup(sk, newsk)) + newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; +#endif if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len) newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; newtp->rx_opt.mss_clamp = req->mss; @@ -617,6 +655,30 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, req, NULL); if (child == NULL) goto listen_overflow; +#ifdef CONFIG_TCP_MD5SIG + else { + /* Copy over the MD5 key from the original socket */ + struct tcp_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + key = tp->af_specific->md5_lookup(sk, child); + if (key != NULL) { + /* + * We're using one, so create a matching key on the + * newsk structure. If we fail to get memory then we + * end up not copying the key across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + if (!tcp_alloc_md5sig_pool()) + BUG(); + memcpy(newkey, key->key, key->keylen); + tp->af_specific->md5_add(child, child, + newkey, + key->keylen); + } + } + } +#endif inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_removed(sk, req); @@ -633,7 +695,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, embryonic_reset: NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS); if (!(flg & TCP_FLAG_RST)) - req->rsk_ops->send_reset(skb); + req->rsk_ops->send_reset(sk, skb); inet_csk_reqsk_queue_drop(sk, req, prev); return NULL; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 6a8581ab9a23..32c1a972fa31 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -270,7 +270,7 @@ static u16 tcp_select_window(struct sock *sk) } static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, - __u32 tstamp) + __u32 tstamp, __u8 **md5_hash) { if (tp->rx_opt.tstamp_ok) { *ptr++ = htonl((TCPOPT_NOP << 24) | @@ -298,16 +298,29 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, tp->rx_opt.eff_sacks--; } } +#ifdef CONFIG_TCP_MD5SIG + if (md5_hash) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + *md5_hash = (__u8 *)ptr; + } +#endif } /* Construct a tcp options header for a SYN or SYN_ACK packet. * If this is every changed make sure to change the definition of * MAX_SYN_SIZE to match the new maximum number of options that you * can generate. + * + * Note - that with the RFC2385 TCP option, we make room for the + * 16 byte MD5 hash. This will be filled in later, so the pointer for the + * location to be filled is passed back up. */ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, int offer_wscale, int wscale, __u32 tstamp, - __u32 ts_recent) + __u32 ts_recent, __u8 **md5_hash) { /* We always get an MSS option. * The option bytes which will be seen in normal data @@ -346,6 +359,20 @@ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale)); +#ifdef CONFIG_TCP_MD5SIG + /* + * If MD5 is enabled, then we set the option, and include the size + * (always 18). The actual MD5 hash is added just before the + * packet is sent. + */ + if (md5_hash) { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + *md5_hash = (__u8 *) ptr; + } +#endif } /* This routine actually transmits TCP packets queued in by @@ -366,6 +393,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, struct tcp_sock *tp; struct tcp_skb_cb *tcb; int tcp_header_size; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *md5; + __u8 *md5_hash_location; +#endif struct tcphdr *th; int sysctl_flags; int err; @@ -424,6 +455,16 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, if (tcp_packets_in_flight(tp) == 0) tcp_ca_event(sk, CA_EVENT_TX_START); +#ifdef CONFIG_TCP_MD5SIG + /* + * Are we doing MD5 on this segment? If so - make + * room for it. + */ + md5 = tp->af_specific->md5_lookup(sk, sk); + if (md5) + tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; +#endif + th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; @@ -460,13 +501,34 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, (sysctl_flags & SYSCTL_FLAG_WSCALE), tp->rx_opt.rcv_wscale, tcb->when, - tp->rx_opt.ts_recent); + tp->rx_opt.ts_recent, + +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL); } else { tcp_build_and_update_options((__be32 *)(th + 1), - tp, tcb->when); + tp, tcb->when, +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL); TCP_ECN_send(sk, tp, skb, tcp_header_size); } +#ifdef CONFIG_TCP_MD5SIG + /* Calculate the MD5 hash, as we have all we need now */ + if (md5) { + tp->af_specific->calc_md5_hash(md5_hash_location, + md5, + sk, NULL, NULL, + skb->h.th, + sk->sk_protocol, + skb->len); + } +#endif + icsk->icsk_af_ops->send_check(sk, skb->len, skb); if (likely(tcb->flags & TCPCB_FLAG_ACK)) @@ -840,6 +902,11 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); +#ifdef CONFIG_TCP_MD5SIG + if (tp->af_specific->md5_lookup(sk, sk)) + mss_now -= TCPOLEN_MD5SIG_ALIGNED; +#endif + xmit_size_goal = mss_now; if (doing_tso) { @@ -2033,6 +2100,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct tcphdr *th; int tcp_header_size; struct sk_buff *skb; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *md5; + __u8 *md5_hash_location; +#endif skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); if (skb == NULL) @@ -2048,6 +2119,13 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + /* SACK_PERM is in the place of NOP NOP of TS */ ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); + +#ifdef CONFIG_TCP_MD5SIG + /* Are we doing MD5 on this segment? If so - make room for it */ + md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); + if (md5) + tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; +#endif skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); memset(th, 0, sizeof(struct tcphdr)); @@ -2085,11 +2163,29 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, TCP_SKB_CB(skb)->when, - req->ts_recent); + req->ts_recent, + ( +#ifdef CONFIG_TCP_MD5SIG + md5 ? &md5_hash_location : +#endif + NULL) + ); skb->csum = 0; th->doff = (tcp_header_size >> 2); TCP_INC_STATS(TCP_MIB_OUTSEGS); + +#ifdef CONFIG_TCP_MD5SIG + /* Okay, we have all we need - do the md5 hash if needed */ + if (md5) { + tp->af_specific->calc_md5_hash(md5_hash_location, + md5, + NULL, dst, req, + skb->h.th, sk->sk_protocol, + skb->len); + } +#endif + return skb; } @@ -2108,6 +2204,11 @@ static void tcp_connect_init(struct sock *sk) tp->tcp_header_len = sizeof(struct tcphdr) + (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); +#ifdef CONFIG_TCP_MD5SIG + if (tp->af_specific->md5_lookup(sk, sk) != NULL) + tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; +#endif + /* If user gave his TCP_MAXSEG, record it to clamp */ if (tp->rx_opt.user_mss) tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9a88395a7629..663d1d238014 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -66,10 +66,13 @@ #include #include +#include +#include + /* Socket used for sending RSTs and ACKs */ static struct socket *tcp6_socket; -static void tcp_v6_send_reset(struct sk_buff *skb); +static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb); @@ -78,6 +81,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); static struct inet_connection_sock_af_ops ipv6_mapped; static struct inet_connection_sock_af_ops ipv6_specific; +static struct tcp_sock_af_ops tcp_sock_ipv6_specific; +static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; static int tcp_v6_get_port(struct sock *sk, unsigned short snum) { @@ -208,6 +213,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, icsk->icsk_af_ops = &ipv6_mapped; sk->sk_backlog_rcv = tcp_v4_do_rcv; +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_mapped_specific; +#endif err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); @@ -215,6 +223,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, icsk->icsk_ext_hdr_len = exthdrlen; icsk->icsk_af_ops = &ipv6_specific; sk->sk_backlog_rcv = tcp_v6_do_rcv; +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +#endif goto failure; } else { ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF), @@ -518,6 +529,396 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req) kfree_skb(inet6_rsk(req)->pktopts); } +#ifdef CONFIG_TCP_MD5SIG +static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, + struct in6_addr *addr) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + BUG_ON(tp == NULL); + + if (!tp->md5sig_info || !tp->md5sig_info->entries6) + return NULL; + + for (i = 0; i < tp->md5sig_info->entries6; i++) { + if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, addr) == 0) + return (struct tcp_md5sig_key *)&tp->md5sig_info->keys6[i]; + } + return NULL; +} + +static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, + struct sock *addr_sk) +{ + return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr); +} + +static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, + struct request_sock *req) +{ + return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); +} + +static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, + char *newkey, u8 newkeylen) +{ + /* Add key to the list */ + struct tcp6_md5sig_key *key; + struct tcp_sock *tp = tcp_sk(sk); + struct tcp6_md5sig_key *keys; + + key = (struct tcp6_md5sig_key*) tcp_v6_md5_do_lookup(sk, peer); + if (key) { + /* modify existing entry - just update that one */ + kfree(key->key); + key->key = newkey; + key->keylen = newkeylen; + } else { + /* reallocate new list if current one is full. */ + if (!tp->md5sig_info) { + tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); + if (!tp->md5sig_info) { + kfree(newkey); + return -ENOMEM; + } + } + tcp_alloc_md5sig_pool(); + if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) { + keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) * + (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC); + + if (!keys) { + tcp_free_md5sig_pool(); + kfree(newkey); + return -ENOMEM; + } + + if (tp->md5sig_info->entries6) + memmove(keys, tp->md5sig_info->keys6, + (sizeof (tp->md5sig_info->keys6[0]) * + tp->md5sig_info->entries6)); + + kfree(tp->md5sig_info->keys6); + tp->md5sig_info->keys6 = keys; + tp->md5sig_info->alloced6++; + } + + ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr, + peer); + tp->md5sig_info->keys6[tp->md5sig_info->entries6].key = newkey; + tp->md5sig_info->keys6[tp->md5sig_info->entries6].keylen = newkeylen; + + tp->md5sig_info->entries6++; + } + return 0; +} + +static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk, + u8 *newkey, __u8 newkeylen) +{ + return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr, + newkey, newkeylen); +} + +static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + for (i = 0; i < tp->md5sig_info->entries6; i++) { + if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, peer) == 0) { + /* Free the key */ + kfree(tp->md5sig_info->keys6[i].key); + tp->md5sig_info->entries6--; + + if (tp->md5sig_info->entries6 == 0) { + kfree(tp->md5sig_info->keys6); + tp->md5sig_info->keys6 = NULL; + + tcp_free_md5sig_pool(); + + return 0; + } else { + /* shrink the database */ + if (tp->md5sig_info->entries6 != i) + memmove(&tp->md5sig_info->keys6[i], + &tp->md5sig_info->keys6[i+1], + (tp->md5sig_info->entries6 - i) + * sizeof (tp->md5sig_info->keys6[0])); + } + } + } + return -ENOENT; +} + +static void tcp_v6_clear_md5_list (struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + int i; + + if (tp->md5sig_info->entries6) { + for (i = 0; i < tp->md5sig_info->entries6; i++) + kfree(tp->md5sig_info->keys6[i].key); + tp->md5sig_info->entries6 = 0; + tcp_free_md5sig_pool(); + } + + kfree(tp->md5sig_info->keys6); + tp->md5sig_info->keys6 = NULL; + tp->md5sig_info->alloced6 = 0; + + if (tp->md5sig_info->entries4) { + for (i = 0; i < tp->md5sig_info->entries4; i++) + kfree(tp->md5sig_info->keys4[i].key); + tp->md5sig_info->entries4 = 0; + tcp_free_md5sig_pool(); + } + + kfree(tp->md5sig_info->keys4); + tp->md5sig_info->keys4 = NULL; + tp->md5sig_info->alloced4 = 0; +} + +static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, + int optlen) +{ + struct tcp_md5sig cmd; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; + u8 *newkey; + + if (optlen < sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, optval, sizeof(cmd))) + return -EFAULT; + + if (sin6->sin6_family != AF_INET6) + return -EINVAL; + + if (!cmd.tcpm_keylen) { + if (!tcp_sk(sk)->md5sig_info) + return -ENOENT; + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) + return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]); + return tcp_v6_md5_do_del(sk, &sin6->sin6_addr); + } + + if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) + return -EINVAL; + + if (!tcp_sk(sk)->md5sig_info) { + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_md5sig_info *p; + + p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); + if (!p) + return -ENOMEM; + + tp->md5sig_info = p; + } + + newkey = kmalloc(cmd.tcpm_keylen, GFP_KERNEL); + if (!newkey) + return -ENOMEM; + memcpy(newkey, cmd.tcpm_key, cmd.tcpm_keylen); + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) { + return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3], + newkey, cmd.tcpm_keylen); + } + return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); +} + +static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + struct in6_addr *saddr, + struct in6_addr *daddr, + struct tcphdr *th, int protocol, + int tcplen) +{ + struct scatterlist sg[4]; + __u16 data_len; + int block = 0; + __u16 cksum; + struct tcp_md5sig_pool *hp; + struct tcp6_pseudohdr *bp; + struct hash_desc *desc; + int err; + unsigned int nbytes = 0; + + hp = tcp_get_md5sig_pool(); + if (!hp) { + printk(KERN_WARNING "%s(): hash pool not found...\n", __FUNCTION__); + goto clear_hash_noput; + } + bp = &hp->md5_blk.ip6; + desc = &hp->md5_desc; + + /* 1. TCP pseudo-header (RFC2460) */ + ipv6_addr_copy(&bp->saddr, saddr); + ipv6_addr_copy(&bp->daddr, daddr); + bp->len = htonl(tcplen); + bp->protocol = htonl(protocol); + + sg_set_buf(&sg[block++], bp, sizeof(*bp)); + nbytes += sizeof(*bp); + + /* 2. TCP header, excluding options */ + cksum = th->check; + th->check = 0; + sg_set_buf(&sg[block++], th, sizeof(*th)); + nbytes += sizeof(*th); + + /* 3. TCP segment data (if any) */ + data_len = tcplen - (th->doff << 2); + if (data_len > 0) { + u8 *data = (u8 *)th + (th->doff << 2); + sg_set_buf(&sg[block++], data, data_len); + nbytes += data_len; + } + + /* 4. shared key */ + sg_set_buf(&sg[block++], key->key, key->keylen); + nbytes += key->keylen; + + /* Now store the hash into the packet */ + err = crypto_hash_init(desc); + if (err) { + printk(KERN_WARNING "%s(): hash_init failed\n", __FUNCTION__); + goto clear_hash; + } + err = crypto_hash_update(desc, sg, nbytes); + if (err) { + printk(KERN_WARNING "%s(): hash_update failed\n", __FUNCTION__); + goto clear_hash; + } + err = crypto_hash_final(desc, md5_hash); + if (err) { + printk(KERN_WARNING "%s(): hash_final failed\n", __FUNCTION__); + goto clear_hash; + } + + /* Reset header, and free up the crypto */ + tcp_put_md5sig_pool(); + th->check = cksum; +out: + return 0; +clear_hash: + tcp_put_md5sig_pool(); +clear_hash_noput: + memset(md5_hash, 0, 16); + goto out; +} + +static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, + struct dst_entry *dst, + struct request_sock *req, + struct tcphdr *th, int protocol, + int tcplen) +{ + struct in6_addr *saddr, *daddr; + + if (sk) { + saddr = &inet6_sk(sk)->saddr; + daddr = &inet6_sk(sk)->daddr; + } else { + saddr = &inet6_rsk(req)->loc_addr; + daddr = &inet6_rsk(req)->rmt_addr; + } + return tcp_v6_do_calc_md5_hash(md5_hash, key, + saddr, daddr, + th, protocol, tcplen); +} + +static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) +{ + __u8 *hash_location = NULL; + struct tcp_md5sig_key *hash_expected; + struct ipv6hdr *ip6h = skb->nh.ipv6h; + struct tcphdr *th = skb->h.th; + int length = (th->doff << 2) - sizeof (*th); + int genhash; + u8 *ptr; + u8 newhash[16]; + + hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); + + /* If the TCP option is too short, we can short cut */ + if (length < TCPOLEN_MD5SIG) + return hash_expected ? 1 : 0; + + /* parse options */ + ptr = (u8*)(th + 1); + while (length > 0) { + int opcode = *ptr++; + int opsize; + + switch(opcode) { + case TCPOPT_EOL: + goto done_opts; + case TCPOPT_NOP: + length--; + continue; + default: + opsize = *ptr++; + if (opsize < 2 || opsize > length) + goto done_opts; + if (opcode == TCPOPT_MD5SIG) { + hash_location = ptr; + goto done_opts; + } + } + ptr += opsize - 2; + length -= opsize; + } + +done_opts: + /* do we have a hash as expected? */ + if (!hash_expected) { + if (!hash_location) + return 0; + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash NOT expected but found " + "(" NIP6_FMT ", %u)->" + "(" NIP6_FMT ", %u)\n", + NIP6(ip6h->saddr), ntohs(th->source), + NIP6(ip6h->daddr), ntohs(th->dest)); + } + return 1; + } + + if (!hash_location) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash expected but NOT found " + "(" NIP6_FMT ", %u)->" + "(" NIP6_FMT ", %u)\n", + NIP6(ip6h->saddr), ntohs(th->source), + NIP6(ip6h->daddr), ntohs(th->dest)); + } + return 1; + } + + /* check the signature */ + genhash = tcp_v6_do_calc_md5_hash(newhash, + hash_expected, + &ip6h->saddr, &ip6h->daddr, + th, sk->sk_protocol, + skb->len); + if (genhash || memcmp(hash_location, newhash, 16) != 0) { + if (net_ratelimit()) { + printk(KERN_INFO "MD5 Hash %s for " + "(" NIP6_FMT ", %u)->" + "(" NIP6_FMT ", %u)\n", + genhash ? "failed" : "mismatch", + NIP6(ip6h->saddr), ntohs(th->source), + NIP6(ip6h->daddr), ntohs(th->dest)); + } + return 1; + } + return 0; +} +#endif + static struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), @@ -527,9 +928,16 @@ static struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .send_reset = tcp_v6_send_reset }; +struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v6_reqsk_md5_lookup, +#endif +}; + static struct timewait_sock_ops tcp6_timewait_sock_ops = { .twsk_obj_size = sizeof(struct tcp6_timewait_sock), .twsk_unique = tcp_twsk_unique, + .twsk_destructor= tcp_twsk_destructor, }; static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) @@ -566,11 +974,15 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) return 0; } -static void tcp_v6_send_reset(struct sk_buff *skb) +static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) { struct tcphdr *th = skb->h.th, *t1; struct sk_buff *buff; struct flowi fl; + int tot_len = sizeof(*th); +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif if (th->rst) return; @@ -578,25 +990,35 @@ static void tcp_v6_send_reset(struct sk_buff *skb) if (!ipv6_unicast_destination(skb)) return; +#ifdef CONFIG_TCP_MD5SIG + if (sk) + key = tcp_v6_md5_do_lookup(sk, &skb->nh.ipv6h->daddr); + else + key = NULL; + + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; +#endif + /* * We need to grab some memory, and put together an RST, * and then put it into the queue to be sent. */ - buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr), + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); if (buff == NULL) return; - skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr)); + skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); - t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr)); + t1 = (struct tcphdr *) skb_push(buff, tot_len); /* Swap the send and the receive. */ memset(t1, 0, sizeof(*t1)); t1->dest = th->source; t1->source = th->dest; - t1->doff = sizeof(*t1)/4; + t1->doff = tot_len / 4; t1->rst = 1; if(th->ack) { @@ -607,6 +1029,22 @@ static void tcp_v6_send_reset(struct sk_buff *skb) + skb->len - (th->doff<<2)); } +#ifdef CONFIG_TCP_MD5SIG + if (key) { + u32 *opt = (u32*)(t1 + 1); + opt[0] = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + tcp_v6_do_calc_md5_hash((__u8*)&opt[1], + key, + &skb->nh.ipv6h->daddr, + &skb->nh.ipv6h->saddr, + t1, IPPROTO_TCP, + tot_len); + } +#endif + buff->csum = csum_partial((char *)t1, sizeof(*t1), 0); memset(&fl, 0, sizeof(fl)); @@ -637,15 +1075,37 @@ static void tcp_v6_send_reset(struct sk_buff *skb) kfree_skb(buff); } -static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) +static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, + struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) { struct tcphdr *th = skb->h.th, *t1; struct sk_buff *buff; struct flowi fl; int tot_len = sizeof(struct tcphdr); + u32 *topt; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; + struct tcp_md5sig_key tw_key; +#endif + +#ifdef CONFIG_TCP_MD5SIG + if (!tw && skb->sk) { + key = tcp_v6_md5_do_lookup(skb->sk, &skb->nh.ipv6h->daddr); + } else if (tw && tw->tw_md5_keylen) { + tw_key.key = tw->tw_md5_key; + tw_key.keylen = tw->tw_md5_keylen; + key = &tw_key; + } else { + key = NULL; + } +#endif if (ts) tot_len += TCPOLEN_TSTAMP_ALIGNED; +#ifdef CONFIG_TCP_MD5SIG + if (key) + tot_len += TCPOLEN_MD5SIG_ALIGNED; +#endif buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); @@ -665,15 +1125,29 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 t1->ack_seq = htonl(ack); t1->ack = 1; t1->window = htons(win); + + topt = (u32*)(t1 + 1); if (ts) { - u32 *ptr = (u32*)(t1 + 1); - *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); - *ptr++ = htonl(tcp_time_stamp); - *ptr = htonl(ts); + *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); + *topt++ = htonl(tcp_time_stamp); + *topt = htonl(ts); } +#ifdef CONFIG_TCP_MD5SIG + if (key) { + *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); + tcp_v6_do_calc_md5_hash((__u8 *)topt, + key, + &skb->nh.ipv6h->daddr, + &skb->nh.ipv6h->saddr, + t1, IPPROTO_TCP, + tot_len); + } +#endif + buff->csum = csum_partial((char *)t1, tot_len, 0); memset(&fl, 0, sizeof(fl)); @@ -704,9 +1178,9 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) { struct inet_timewait_sock *tw = inet_twsk(sk); - const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_ts_recent); @@ -715,7 +1189,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); + tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); } @@ -786,6 +1260,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (req == NULL) goto drop; +#ifdef CONFIG_TCP_MD5SIG + tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops; +#endif + tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); tmp_opt.user_mss = tp->rx_opt.user_mss; @@ -844,6 +1322,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct tcp_sock *newtp; struct sock *newsk; struct ipv6_txoptions *opt; +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; +#endif if (skb->protocol == htons(ETH_P_IP)) { /* @@ -874,6 +1355,10 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; newsk->sk_backlog_rcv = tcp_v4_do_rcv; +#ifdef CONFIG_TCP_MD5SIG + newtp->af_specific = &tcp_sock_ipv6_mapped_specific; +#endif + newnp->pktoptions = NULL; newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); @@ -1008,6 +1493,23 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; +#ifdef CONFIG_TCP_MD5SIG + /* Copy over the MD5 key from the original socket */ + if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) { + /* We're using one, so create a matching key + * on the newsk structure. If we fail to get + * memory, then we end up not copying the key + * across. Shucks. + */ + char *newkey = kmalloc(key->keylen, GFP_ATOMIC); + if (newkey) { + memcpy(newkey, key->key, key->keylen); + tcp_v6_md5_do_add(newsk, &inet6_sk(sk)->daddr, + newkey, key->keylen); + } + } +#endif + __inet6_hash(&tcp_hashinfo, newsk); inet_inherit_port(&tcp_hashinfo, sk, newsk); @@ -1067,6 +1569,11 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_do_rcv(sk, skb); +#ifdef CONFIG_TCP_MD5SIG + if (tcp_v6_inbound_md5_hash (sk, skb)) + goto discard; +#endif + if (sk_filter(sk, skb)) goto discard; @@ -1132,7 +1639,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; reset: - tcp_v6_send_reset(skb); + tcp_v6_send_reset(sk, skb); discard: if (opt_skb) __kfree_skb(opt_skb); @@ -1257,7 +1764,7 @@ no_tcp_socket: bad_packet: TCP_INC_STATS_BH(TCP_MIB_INERRS); } else { - tcp_v6_send_reset(skb); + tcp_v6_send_reset(NULL, skb); } discard_it: @@ -1336,6 +1843,15 @@ static struct inet_connection_sock_af_ops ipv6_specific = { #endif }; +static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v6_md5_lookup, + .calc_md5_hash = tcp_v6_calc_md5_hash, + .md5_add = tcp_v6_md5_add_func, + .md5_parse = tcp_v6_parse_md5_keys, +#endif +}; + /* * TCP over IPv4 via INET6 API */ @@ -1358,6 +1874,15 @@ static struct inet_connection_sock_af_ops ipv6_mapped = { #endif }; +static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { +#ifdef CONFIG_TCP_MD5SIG + .md5_lookup = tcp_v4_md5_lookup, + .calc_md5_hash = tcp_v4_calc_md5_hash, + .md5_add = tcp_v6_md5_add_func, + .md5_parse = tcp_v6_parse_md5_keys, +#endif +}; + /* NOTE: A lot of things set to zero explicitly by call to * sk_alloc() so need not be done here. */ @@ -1397,6 +1922,10 @@ static int tcp_v6_init_sock(struct sock *sk) sk->sk_write_space = sk_stream_write_space; sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); +#ifdef CONFIG_TCP_MD5SIG + tp->af_specific = &tcp_sock_ipv6_specific; +#endif + sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; @@ -1407,6 +1936,11 @@ static int tcp_v6_init_sock(struct sock *sk) static int tcp_v6_destroy_sock(struct sock *sk) { +#ifdef CONFIG_TCP_MD5SIG + /* Clean up the MD5 key list */ + if (tcp_sk(sk)->md5sig_info) + tcp_v6_clear_md5_list(sk); +#endif tcp_v4_destroy_sock(sk); return inet6_destroy_sock(sk); } -- cgit v1.2.3-71-gd317 From 6051e2f4fb68fc8e5343db58fa680ece376f405c Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 14 Nov 2006 19:54:19 -0800 Subject: [IPv6] prefix: Convert RTM_NEWPREFIX notifications to use the new netlink api RTM_GETPREFIX is completely unused and is thus removed. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 -- net/core/rtnetlink.c | 1 - net/ipv6/addrconf.c | 30 ++++++++++++++---------------- security/selinux/nlmsgtab.c | 1 - 4 files changed, 14 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 3a18addaed4c..33b3d0ab3a91 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -81,8 +81,6 @@ enum { RTM_NEWPREFIX = 52, #define RTM_NEWPREFIX RTM_NEWPREFIX - RTM_GETPREFIX = 54, -#define RTM_GETPREFIX RTM_GETPREFIX RTM_GETMULTICAST = 58, #define RTM_GETMULTICAST RTM_GETMULTICAST diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 50d6cb40c6e3..0cb4d9e53a07 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -108,7 +108,6 @@ static const int rtm_min[RTM_NR_FAMILIES] = [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)), [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)), [RTM_FAM(RTM_NEWACTION)] = NLMSG_LENGTH(sizeof(struct tcamsg)), - [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 46cd941d296f..052f99eaf2ac 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3518,16 +3518,18 @@ static inline size_t inet6_prefix_nlmsg_size(void) } static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, - struct prefix_info *pinfo, u32 pid, u32 seq, - int event, unsigned int flags) + struct prefix_info *pinfo, u32 pid, u32 seq, + int event, unsigned int flags) { - struct prefixmsg *pmsg; - struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + struct prefixmsg *pmsg; + struct nlmsghdr *nlh; struct prefix_cacheinfo ci; - nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*pmsg), flags); - pmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*pmsg), flags); + if (nlh == NULL) + return -ENOBUFS; + + pmsg = nlmsg_data(nlh); pmsg->prefix_family = AF_INET6; pmsg->prefix_pad1 = 0; pmsg->prefix_pad2 = 0; @@ -3535,26 +3537,22 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, pmsg->prefix_len = pinfo->prefix_len; pmsg->prefix_type = pinfo->type; pmsg->prefix_pad3 = 0; - pmsg->prefix_flags = 0; if (pinfo->onlink) pmsg->prefix_flags |= IF_PREFIX_ONLINK; if (pinfo->autoconf) pmsg->prefix_flags |= IF_PREFIX_AUTOCONF; - RTA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix); + NLA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix); ci.preferred_time = ntohl(pinfo->prefered); ci.valid_time = ntohl(pinfo->valid); - RTA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci); + NLA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci); - nlh->nlmsg_len = skb->tail - b; - return skb->len; + return nlmsg_end(skb, nlh); -nlmsg_failure: -rtattr_failure: - skb_trim(skb, b - skb->data); - return -1; +nla_put_failure: + return nlmsg_cancel(skb, nlh); } static void inet6_prefix_notify(int event, struct inet6_dev *idev, diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index b8f4d25cf335..ccfe8755735e 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -60,7 +60,6 @@ static struct nlmsg_perm nlmsg_route_perms[] = { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, -- cgit v1.2.3-71-gd317 From ba4e58eca8aa9473b44fdfd312f26c4a2e7798b3 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 27 Nov 2006 11:10:57 -0800 Subject: [NET]: Supporting UDP-Lite (RFC 3828) in Linux This is a revision of the previously submitted patch, which alters the way files are organized and compiled in the following manner: * UDP and UDP-Lite now use separate object files * source file dependencies resolved via header files net/ipv{4,6}/udp_impl.h * order of inclusion files in udp.c/udplite.c adapted accordingly [NET/IPv4]: Support for the UDP-Lite protocol (RFC 3828) This patch adds support for UDP-Lite to the IPv4 stack, provided as an extension to the existing UDPv4 code: * generic routines are all located in net/ipv4/udp.c * UDP-Lite specific routines are in net/ipv4/udplite.c * MIB/statistics support in /proc/net/snmp and /proc/net/udplite * shared API with extensions for partial checksum coverage [NET/IPv6]: Extension for UDP-Lite over IPv6 It extends the existing UDPv6 code base with support for UDP-Lite in the same manner as per UDPv4. In particular, * UDPv6 generic and shared code is in net/ipv6/udp.c * UDP-Litev6 specific extensions are in net/ipv6/udplite.c * MIB/statistics support in /proc/net/snmp6 and /proc/net/udplite6 * support for IPV6_ADDRFORM * aligned the coding style of protocol initialisation with af_inet6.c * made the error handling in udpv6_queue_rcv_skb consistent; to return `-1' on error on all error cases * consolidation of shared code [NET]: UDP-Lite Documentation and basic XFRM/Netfilter support The UDP-Lite patch further provides * API documentation for UDP-Lite * basic xfrm support * basic netfilter support for IPv4 and IPv6 (LOG target) Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- Documentation/networking/udplite.txt | 281 +++++++++++++++++++ include/linux/in.h | 1 + include/linux/socket.h | 1 + include/linux/udp.h | 12 + include/net/ipv6.h | 12 +- include/net/transp_v6.h | 2 + include/net/udp.h | 91 +++++- include/net/udplite.h | 149 ++++++++++ include/net/xfrm.h | 2 + net/ipv4/Makefile | 3 +- net/ipv4/af_inet.c | 8 +- net/ipv4/netfilter/ipt_LOG.c | 11 +- net/ipv4/proc.c | 13 + net/ipv4/udp.c | 518 ++++++++++++++++++++--------------- net/ipv4/udp_impl.h | 38 +++ net/ipv4/udplite.c | 119 ++++++++ net/ipv4/xfrm4_policy.c | 1 + net/ipv6/Makefile | 4 +- net/ipv6/af_inet6.c | 21 +- net/ipv6/ipv6_sockglue.c | 11 +- net/ipv6/netfilter/ip6t_LOG.c | 10 +- net/ipv6/proc.c | 11 + net/ipv6/udp.c | 361 +++++++++++++----------- net/ipv6/udp_impl.h | 34 +++ net/ipv6/udplite.c | 105 +++++++ net/ipv6/xfrm6_policy.c | 1 + net/netfilter/xt_multiport.c | 5 +- net/netfilter/xt_tcpudp.c | 20 +- 28 files changed, 1442 insertions(+), 403 deletions(-) create mode 100644 Documentation/networking/udplite.txt create mode 100644 include/net/udplite.h create mode 100644 net/ipv4/udp_impl.h create mode 100644 net/ipv4/udplite.c create mode 100644 net/ipv6/udp_impl.h create mode 100644 net/ipv6/udplite.c (limited to 'include/linux') diff --git a/Documentation/networking/udplite.txt b/Documentation/networking/udplite.txt new file mode 100644 index 000000000000..dd6f46b83dab --- /dev/null +++ b/Documentation/networking/udplite.txt @@ -0,0 +1,281 @@ + =========================================================================== + The UDP-Lite protocol (RFC 3828) + =========================================================================== + + + UDP-Lite is a Standards-Track IETF transport protocol whose characteristic + is a variable-length checksum. This has advantages for transport of multimedia + (video, VoIP) over wireless networks, as partly damaged packets can still be + fed into the codec instead of being discarded due to a failed checksum test. + + This file briefly describes the existing kernel support and the socket API. + For in-depth information, you can consult: + + o The UDP-Lite Homepage: http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/ + Fom here you can also download some example application source code. + + o The UDP-Lite HOWTO on + http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/UDP-Lite-HOWTO.txt + + o The Wireshark UDP-Lite WiKi (with capture files): + http://wiki.wireshark.org/Lightweight_User_Datagram_Protocol + + o The Protocol Spec, RFC 3828, http://www.ietf.org/rfc/rfc3828.txt + + + I) APPLICATIONS + + Several applications have been ported successfully to UDP-Lite. Ethereal + (now called wireshark) has UDP-Litev4/v6 support by default. The tarball on + + http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/udplite_linux.tar.gz + + has source code for several v4/v6 client-server and network testing examples. + + Porting applications to UDP-Lite is straightforward: only socket level and + IPPROTO need to be changed; senders additionally set the checksum coverage + length (default = header length = 8). Details are in the next section. + + + II) PROGRAMMING API + + UDP-Lite provides a connectionless, unreliable datagram service and hence + uses the same socket type as UDP. In fact, porting from UDP to UDP-Lite is + very easy: simply add `IPPROTO_UDPLITE' as the last argument of the socket(2) + call so that the statement looks like: + + s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE); + + or, respectively, + + s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE); + + With just the above change you are able to run UDP-Lite services or connect + to UDP-Lite servers. The kernel will assume that you are not interested in + using partial checksum coverage and so emulate UDP mode (full coverage). + + To make use of the partial checksum coverage facilities requires setting a + single socket option, which takes an integer specifying the coverage length: + + * Sender checksum coverage: UDPLITE_SEND_CSCOV + + For example, + + int val = 20; + setsockopt(s, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, sizeof(int)); + + sets the checksum coverage length to 20 bytes (12b data + 8b header). + Of each packet only the first 20 bytes (plus the pseudo-header) will be + checksummed. This is useful for RTP applications which have a 12-byte + base header. + + + * Receiver checksum coverage: UDPLITE_RECV_CSCOV + + This option is the receiver-side analogue. It is truly optional, i.e. not + required to enable traffic with partial checksum coverage. Its function is + that of a traffic filter: when enabled, it instructs the kernel to drop + all packets which have a coverage _less_ than this value. For example, if + RTP and UDP headers are to be protected, a receiver can enforce that only + packets with a minimum coverage of 20 are admitted: + + int min = 20; + setsockopt(s, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &min, sizeof(int)); + + The calls to getsockopt(2) are analogous. Being an extension and not a stand- + alone protocol, all socket options known from UDP can be used in exactly the + same manner as before, e.g. UDP_CORK or UDP_ENCAP. + + A detailed discussion of UDP-Lite checksum coverage options is in section IV. + + + III) HEADER FILES + + The socket API requires support through header files in /usr/include: + + * /usr/include/netinet/in.h + to define IPPROTO_UDPLITE + + * /usr/include/netinet/udplite.h + for UDP-Lite header fields and protocol constants + + For testing purposes, the following can serve as a `mini' header file: + + #define IPPROTO_UDPLITE 136 + #define SOL_UDPLITE 136 + #define UDPLITE_SEND_CSCOV 10 + #define UDPLITE_RECV_CSCOV 11 + + Ready-made header files for various distros are in the UDP-Lite tarball. + + + IV) KERNEL BEHAVIOUR WITH REGARD TO THE VARIOUS SOCKET OPTIONS + + To enable debugging messages, the log level need to be set to 8, as most + messages use the KERN_DEBUG level (7). + + 1) Sender Socket Options + + If the sender specifies a value of 0 as coverage length, the module + assumes full coverage, transmits a packet with coverage length of 0 + and according checksum. If the sender specifies a coverage < 8 and + different from 0, the kernel assumes 8 as default value. Finally, + if the specified coverage length exceeds the packet length, the packet + length is used instead as coverage length. + + 2) Receiver Socket Options + + The receiver specifies the minimum value of the coverage length it + is willing to accept. A value of 0 here indicates that the receiver + always wants the whole of the packet covered. In this case, all + partially covered packets are dropped and an error is logged. + + It is not possible to specify illegal values (<0 and <8); in these + cases the default of 8 is assumed. + + All packets arriving with a coverage value less than the specified + threshold are discarded, these events are also logged. + + 3) Disabling the Checksum Computation + + On both sender and receiver, checksumming will always be performed + and can not be disabled using SO_NO_CHECK. Thus + + setsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, ... ); + + will always will be ignored, while the value of + + getsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, &value, ...); + + is meaningless (as in TCP). Packets with a zero checksum field are + illegal (cf. RFC 3828, sec. 3.1) will be silently discarded. + + 4) Fragmentation + + The checksum computation respects both buffersize and MTU. The size + of UDP-Lite packets is determined by the size of the send buffer. The + minimum size of the send buffer is 2048 (defined as SOCK_MIN_SNDBUF + in include/net/sock.h), the default value is configurable as + net.core.wmem_default or via setting the SO_SNDBUF socket(7) + option. The maximum upper bound for the send buffer is determined + by net.core.wmem_max. + + Given a payload size larger than the send buffer size, UDP-Lite will + split the payload into several individual packets, filling up the + send buffer size in each case. + + The precise value also depends on the interface MTU. The interface MTU, + in turn, may trigger IP fragmentation. In this case, the generated + UDP-Lite packet is split into several IP packets, of which only the + first one contains the L4 header. + + The send buffer size has implications on the checksum coverage length. + Consider the following example: + + Payload: 1536 bytes Send Buffer: 1024 bytes + MTU: 1500 bytes Coverage Length: 856 bytes + + UDP-Lite will ship the 1536 bytes in two separate packets: + + Packet 1: 1024 payload + 8 byte header + 20 byte IP header = 1052 bytes + Packet 2: 512 payload + 8 byte header + 20 byte IP header = 540 bytes + + The coverage packet covers the UDP-Lite header and 848 bytes of the + payload in the first packet, the second packet is fully covered. Note + that for the second packet, the coverage length exceeds the packet + length. The kernel always re-adjusts the coverage length to the packet + length in such cases. + + As an example of what happens when one UDP-Lite packet is split into + several tiny fragments, consider the following example. + + Payload: 1024 bytes Send buffer size: 1024 bytes + MTU: 300 bytes Coverage length: 575 bytes + + +-+-----------+--------------+--------------+--------------+ + |8| 272 | 280 | 280 | 280 | + +-+-----------+--------------+--------------+--------------+ + 280 560 840 1032 + ^ + *****checksum coverage************* + + The UDP-Lite module generates one 1032 byte packet (1024 + 8 byte + header). According to the interface MTU, these are split into 4 IP + packets (280 byte IP payload + 20 byte IP header). The kernel module + sums the contents of the entire first two packets, plus 15 bytes of + the last packet before releasing the fragments to the IP module. + + To see the analogous case for IPv6 fragmentation, consider a link + MTU of 1280 bytes and a write buffer of 3356 bytes. If the checksum + coverage is less than 1232 bytes (MTU minus IPv6/fragment header + lengths), only the first fragment needs to be considered. When using + larger checksum coverage lengths, each eligible fragment needs to be + checksummed. Suppose we have a checksum coverage of 3062. The buffer + of 3356 bytes will be split into the following fragments: + + Fragment 1: 1280 bytes carrying 1232 bytes of UDP-Lite data + Fragment 2: 1280 bytes carrying 1232 bytes of UDP-Lite data + Fragment 3: 948 bytes carrying 900 bytes of UDP-Lite data + + The first two fragments have to be checksummed in full, of the last + fragment only 598 (= 3062 - 2*1232) bytes are checksummed. + + While it is important that such cases are dealt with correctly, they + are (annoyingly) rare: UDP-Lite is designed for optimising multimedia + performance over wireless (or generally noisy) links and thus smaller + coverage lenghts are likely to be expected. + + + V) UDP-LITE RUNTIME STATISTICS AND THEIR MEANING + + Exceptional and error conditions are logged to syslog at the KERN_DEBUG + level. Live statistics about UDP-Lite are available in /proc/net/snmp + and can (with newer versions of netstat) be viewed using + + netstat -svu + + This displays UDP-Lite statistics variables, whose meaning is as follows. + + InDatagrams: Total number of received datagrams. + + NoPorts: Number of packets received to an unknown port. + These cases are counted separately (not as InErrors). + + InErrors: Number of erroneous UDP-Lite packets. Errors include: + * internal socket queue receive errors + * packet too short (less than 8 bytes or stated + coverage length exceeds received length) + * xfrm4_policy_check() returned with error + * application has specified larger min. coverage + length than that of incoming packet + * checksum coverage violated + * bad checksum + + OutDatagrams: Total number of sent datagrams. + + These statistics derive from the UDP MIB (RFC 2013). + + + VI) IPTABLES + + There is packet match support for UDP-Lite as well as support for the LOG target. + If you copy and paste the following line into /etc/protcols, + + udplite 136 UDP-Lite # UDP-Lite [RFC 3828] + + then + iptables -A INPUT -p udplite -j LOG + + will produce logging output to syslog. Dropping and rejecting packets also works. + + + VII) MAINTAINER ADDRESS + + The UDP-Lite patch was developed at + University of Aberdeen + Electronics Research Group + Department of Engineering + Fraser Noble Building + Aberdeen AB24 3UE; UK + The current maintainer is Gerrit Renker, . Initial + code was developed by William Stanislaus, . diff --git a/include/linux/in.h b/include/linux/in.h index 2619859f6e1b..1912e7c0bc26 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -45,6 +45,7 @@ enum { IPPROTO_COMP = 108, /* Compression Header protocol */ IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ + IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX diff --git a/include/linux/socket.h b/include/linux/socket.h index 361409094649..592b66679823 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -264,6 +264,7 @@ struct ucred { #define SOL_IPV6 41 #define SOL_ICMPV6 58 #define SOL_SCTP 132 +#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */ #define SOL_RAW 255 #define SOL_IPX 256 #define SOL_AX25 257 diff --git a/include/linux/udp.h b/include/linux/udp.h index 014b41d1e308..564f3b050105 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -38,6 +38,7 @@ struct udphdr { #include #include +#define UDP_HTABLE_SIZE 128 struct udp_sock { /* inet_sock has to be the first member */ @@ -50,12 +51,23 @@ struct udp_sock { * when the socket is uncorked. */ __u16 len; /* total length of pending frames */ + /* + * Fields specific to UDP-Lite. + */ + __u16 pcslen; + __u16 pcrlen; +/* indicator bits used by pcflag: */ +#define UDPLITE_BIT 0x1 /* set by udplite proto init function */ +#define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ +#define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ + __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ }; static inline struct udp_sock *udp_sk(const struct sock *sk) { return (struct udp_sock *)sk; } +#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 3c266ad99a02..9390649bbfec 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -158,9 +158,13 @@ DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset); \ }) DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); -#define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field) -#define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field) -#define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field) +DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); +#define UDP6_INC_STATS_BH(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field); \ + else SNMP_INC_STATS_BH(udp_stats_in6, field); } while(0) +#define UDP6_INC_STATS_USER(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \ + else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0) int snmp6_register_dev(struct inet6_dev *idev); int snmp6_unregister_dev(struct inet6_dev *idev); @@ -604,6 +608,8 @@ extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); extern int udp6_proc_init(void); extern void udp6_proc_exit(void); +extern int udplite6_proc_init(void); +extern void udplite6_proc_exit(void); extern int ipv6_misc_proc_init(void); extern void ipv6_misc_proc_exit(void); diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 61f724c1036f..409da3a9a455 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -11,6 +11,7 @@ extern struct proto rawv6_prot; extern struct proto udpv6_prot; +extern struct proto udplitev6_prot; extern struct proto tcpv6_prot; struct flowi; @@ -24,6 +25,7 @@ extern void ipv6_destopt_init(void); /* transport protocols */ extern void rawv6_init(void); extern void udpv6_init(void); +extern void udplitev6_init(void); extern void tcpv6_init(void); extern int udpv6_connect(struct sock *sk, diff --git a/include/net/udp.h b/include/net/udp.h index db0c05f67546..4f0626735ed3 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -26,9 +26,28 @@ #include #include #include +#include +#include #include -#define UDP_HTABLE_SIZE 128 +/** + * struct udp_skb_cb - UDP(-Lite) private variables + * + * @header: private variables used by IPv4/IPv6 + * @cscov: checksum coverage length (UDP-Lite only) + * @partial_cov: if set indicates partial csum coverage + */ +struct udp_skb_cb { + union { + struct inet_skb_parm h4; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + struct inet6_skb_parm h6; +#endif + } header; + __u16 cscov; + __u8 partial_cov; +}; +#define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) extern struct hlist_head udp_hash[UDP_HTABLE_SIZE]; extern rwlock_t udp_hash_lock; @@ -47,6 +66,62 @@ extern struct proto udp_prot; struct sk_buff; +/* + * Generic checksumming routines for UDP(-Lite) v4 and v6 + */ +static inline u16 __udp_lib_checksum_complete(struct sk_buff *skb) +{ + if (! UDP_SKB_CB(skb)->partial_cov) + return __skb_checksum_complete(skb); + return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov, + skb->csum)); +} + +static __inline__ int udp_lib_checksum_complete(struct sk_buff *skb) +{ + return skb->ip_summed != CHECKSUM_UNNECESSARY && + __udp_lib_checksum_complete(skb); +} + +/** + * udp_csum_outgoing - compute UDPv4/v6 checksum over fragments + * @sk: socket we are writing to + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static inline u32 udp_csum_outgoing(struct sock *sk, struct sk_buff *skb) +{ + u32 csum = csum_partial(skb->h.raw, sizeof(struct udphdr), 0); + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + return csum; +} + +/* hash routines shared between UDPv4/6 and UDP-Litev4/6 */ +static inline void udp_lib_hash(struct sock *sk) +{ + BUG(); +} + +static inline void udp_lib_unhash(struct sock *sk) +{ + write_lock_bh(&udp_hash_lock); + if (sk_del_node_init(sk)) { + inet_sk(sk)->num = 0; + sock_prot_dec_use(sk->sk_prot); + } + write_unlock_bh(&udp_hash_lock); +} + +static inline void udp_lib_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + + +/* net/ipv4/udp.c */ extern int udp_get_port(struct sock *sk, unsigned short snum, int (*saddr_cmp)(const struct sock *, const struct sock *)); extern void udp_err(struct sk_buff *, u32); @@ -61,21 +136,29 @@ extern unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait); DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); -#define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field) -#define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field) -#define UDP_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_statistics, field) +/* + * SNMP statistics for UDP and UDP-Lite + */ +#define UDP_INC_STATS_USER(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_USER(udplite_statistics, field); \ + else SNMP_INC_STATS_USER(udp_statistics, field); } while(0) +#define UDP_INC_STATS_BH(field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_BH(udplite_statistics, field); \ + else SNMP_INC_STATS_BH(udp_statistics, field); } while(0) /* /proc */ struct udp_seq_afinfo { struct module *owner; char *name; sa_family_t family; + struct hlist_head *hashtable; int (*seq_show) (struct seq_file *m, void *v); struct file_operations *seq_fops; }; struct udp_iter_state { sa_family_t family; + struct hlist_head *hashtable; int bucket; struct seq_operations seq_ops; }; diff --git a/include/net/udplite.h b/include/net/udplite.h new file mode 100644 index 000000000000..1473b3e49044 --- /dev/null +++ b/include/net/udplite.h @@ -0,0 +1,149 @@ +/* + * Definitions for the UDP-Lite (RFC 3828) code. + */ +#ifndef _UDPLITE_H +#define _UDPLITE_H + +/* UDP-Lite socket options */ +#define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ +#define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ + +extern struct proto udplite_prot; +extern struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; + +/* UDP-Lite does not have a standardized MIB yet, so we inherit from UDP */ +DECLARE_SNMP_STAT(struct udp_mib, udplite_statistics); + +/* + * Checksum computation is all in software, hence simpler getfrag. + */ +static __inline__ int udplite_getfrag(void *from, char *to, int offset, + int len, int odd, struct sk_buff *skb) +{ + return memcpy_fromiovecend(to, (struct iovec *) from, offset, len); +} + +/* Designate sk as UDP-Lite socket */ +static inline int udplite_sk_init(struct sock *sk) +{ + udp_sk(sk)->pcflag = UDPLITE_BIT; + return 0; +} + +/* + * Checksumming routines + */ +static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) +{ + u16 cscov; + + /* In UDPv4 a zero checksum means that the transmitter generated no + * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets + * with a zero checksum field are illegal. */ + if (uh->check == 0) { + LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: zeroed checksum field\n"); + return 1; + } + + UDP_SKB_CB(skb)->partial_cov = 0; + cscov = ntohs(uh->len); + + if (cscov == 0) /* Indicates that full coverage is required. */ + cscov = skb->len; + else if (cscov < 8 || cscov > skb->len) { + /* + * Coverage length violates RFC 3828: log and discard silently. + */ + LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: bad csum coverage %d/%d\n", + cscov, skb->len); + return 1; + + } else if (cscov < skb->len) + UDP_SKB_CB(skb)->partial_cov = 1; + + UDP_SKB_CB(skb)->cscov = cscov; + + /* + * There is no known NIC manufacturer supporting UDP-Lite yet, + * hence ip_summed is always (re-)set to CHECKSUM_NONE. + */ + skb->ip_summed = CHECKSUM_NONE; + + return 0; +} + +static __inline__ int udplite4_csum_init(struct sk_buff *skb, struct udphdr *uh) +{ + int rc = udplite_checksum_init(skb, uh); + + if (!rc) + skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, + skb->nh.iph->daddr, + skb->len, IPPROTO_UDPLITE, 0); + return rc; +} + +static __inline__ int udplite6_csum_init(struct sk_buff *skb, struct udphdr *uh) +{ + int rc = udplite_checksum_init(skb, uh); + + if (!rc) + skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, + skb->len, IPPROTO_UDPLITE, 0); + return rc; +} + +static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) +{ + int cscov = up->len; + + /* + * Sender has set `partial coverage' option on UDP-Lite socket + */ + if (up->pcflag & UDPLITE_SEND_CC) { + if (up->pcslen < up->len) { + /* up->pcslen == 0 means that full coverage is required, + * partial coverage only if 0 < up->pcslen < up->len */ + if (0 < up->pcslen) { + cscov = up->pcslen; + } + uh->len = htons(up->pcslen); + } + /* + * NOTE: Causes for the error case `up->pcslen > up->len': + * (i) Application error (will not be penalized). + * (ii) Payload too big for send buffer: data is split + * into several packets, each with its own header. + * In this case (e.g. last segment), coverage may + * exceed packet length. + * Since packets with coverage length > packet length are + * illegal, we fall back to the defaults here. + */ + } + return cscov; +} + +static inline u32 udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) +{ + u32 csum = 0; + int off, len, cscov = udplite_sender_cscov(udp_sk(sk), skb->h.uh); + + skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ + + skb_queue_walk(&sk->sk_write_queue, skb) { + off = skb->h.raw - skb->data; + len = skb->len - off; + + csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum); + + if ((cscov -= len) <= 0) + break; + } + return csum; +} + +extern void udplite4_register(void); +extern int udplite_get_port(struct sock *sk, unsigned short snum, + int (*scmp)(const struct sock *, const struct sock *)); +#endif /* _UDPLITE_H */ diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 81c91e8a328f..3878a88ff618 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -468,6 +468,7 @@ __be16 xfrm_flowi_sport(struct flowi *fl) switch(fl->proto) { case IPPROTO_TCP: case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_SCTP: port = fl->fl_ip_sport; break; @@ -493,6 +494,7 @@ __be16 xfrm_flowi_dport(struct flowi *fl) switch(fl->proto) { case IPPROTO_TCP: case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_SCTP: port = fl->fl_ip_dport; break; diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 15645c51520c..7a068626feea 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,8 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ + datagram.o raw.o udp.o udplite.o \ + arp.o icmp.o devinet.o af_inet.o igmp.o \ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4a81d54a7569..8db39f7e3bf0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -104,6 +104,7 @@ #include #include #include +#include #include #include #include @@ -1223,10 +1224,13 @@ static int __init init_ipv4_mibs(void) tcp_statistics[1] = alloc_percpu(struct tcp_mib); udp_statistics[0] = alloc_percpu(struct udp_mib); udp_statistics[1] = alloc_percpu(struct udp_mib); + udplite_statistics[0] = alloc_percpu(struct udp_mib); + udplite_statistics[1] = alloc_percpu(struct udp_mib); if (! (net_statistics[0] && net_statistics[1] && ip_statistics[0] && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] - && udp_statistics[0] && udp_statistics[1])) + && udp_statistics[0] && udp_statistics[1] + && udplite_statistics[0] && udplite_statistics[1] ) ) return -ENOMEM; (void) tcp_mib_init(); @@ -1313,6 +1317,8 @@ static int __init inet_init(void) /* Setup TCP slab cache for open requests. */ tcp_init(); + /* Add UDP-Lite (RFC 3828) */ + udplite4_register(); /* * Set the ICMP layer up diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 7dc820df8bc5..46eee64a11f6 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -171,11 +171,15 @@ static void dump_packet(const struct nf_loginfo *info, } break; } - case IPPROTO_UDP: { + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { struct udphdr _udph, *uh; - /* Max length: 10 "PROTO=UDP " */ - printk("PROTO=UDP "); + if (ih->protocol == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + printk("PROTO=UDP " ); + else /* Max length: 14 "PROTO=UDPLITE " */ + printk("PROTO=UDPLITE "); if (ntohs(ih->frag_off) & IP_OFFSET) break; @@ -341,6 +345,7 @@ static void dump_packet(const struct nf_loginfo *info, /* IP: 40+46+6+11+127 = 230 */ /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ /* UDP: 10+max(25,20) = 35 */ + /* UDPLITE: 14+max(25,20) = 39 */ /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ /* ESP: 10+max(25)+15 = 50 */ /* AH: 9+max(25)+15 = 49 */ diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 9c6cbe3d9fb8..cd873da54cbe 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); + seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot)); seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues, atomic_read(&ip_frag_mem)); @@ -304,6 +306,17 @@ static int snmp_seq_show(struct seq_file *seq, void *v) fold_field((void **) udp_statistics, snmp4_udp_list[i].entry)); + /* the UDP and UDP-Lite MIBs are the same */ + seq_puts(seq, "\nUdpLite:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %s", snmp4_udp_list[i].name); + + seq_puts(seq, "\nUdpLite:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %lu", + fold_field((void **) udplite_statistics, + snmp4_udp_list[i].entry) ); + seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9e1bd374875e..98ba75096175 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -92,22 +92,16 @@ #include #include #include -#include #include -#include -#include #include -#include #include #include #include -#include -#include #include #include -#include #include #include +#include "udp_impl.h" /* * Snmp MIB for the UDP layer @@ -120,26 +114,30 @@ DEFINE_RWLOCK(udp_hash_lock); static int udp_port_rover; -static inline int udp_lport_inuse(u16 num) +static inline int __udp_lib_lport_inuse(__be16 num, struct hlist_head udptable[]) { struct sock *sk; struct hlist_node *node; - sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) + sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) if (inet_sk(sk)->num == num) return 1; return 0; } /** - * udp_get_port - common port lookup for IPv4 and IPv6 + * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up + * @udptable: hash list table, must be of UDP_HTABLE_SIZE + * @port_rover: pointer to record of last unallocated port * @saddr_comp: AF-dependent comparison of bound local IP addresses */ -int udp_get_port(struct sock *sk, unsigned short snum, - int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2)) +int __udp_lib_get_port(struct sock *sk, unsigned short snum, + struct hlist_head udptable[], int *port_rover, + int (*saddr_comp)(const struct sock *sk1, + const struct sock *sk2 ) ) { struct hlist_node *node; struct hlist_head *head; @@ -150,15 +148,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, if (snum == 0) { int best_size_so_far, best, result, i; - if (udp_port_rover > sysctl_local_port_range[1] || - udp_port_rover < sysctl_local_port_range[0]) - udp_port_rover = sysctl_local_port_range[0]; + if (*port_rover > sysctl_local_port_range[1] || + *port_rover < sysctl_local_port_range[0]) + *port_rover = sysctl_local_port_range[0]; best_size_so_far = 32767; - best = result = udp_port_rover; + best = result = *port_rover; for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { int size; - head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; if (hlist_empty(head)) { if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + @@ -179,15 +177,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); - if (!udp_lport_inuse(result)) + if (! __udp_lib_lport_inuse(result, udptable)) break; } if (i >= (1 << 16) / UDP_HTABLE_SIZE) goto fail; gotit: - udp_port_rover = snum = result; + *port_rover = snum = result; } else { - head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; sk_for_each(sk2, node, head) if (inet_sk(sk2)->num == snum && @@ -195,12 +193,12 @@ gotit: (!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (*saddr_cmp)(sk, sk2) ) + (*saddr_comp)(sk, sk2) ) goto fail; } inet_sk(sk)->num = snum; if (sk_unhashed(sk)) { - head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; sk_add_node(sk, head); sock_prot_inc_use(sk->sk_prot); } @@ -210,7 +208,13 @@ fail: return error; } -static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +__inline__ int udp_get_port(struct sock *sk, unsigned short snum, + int (*scmp)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); +} + +inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) { struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); @@ -224,34 +228,20 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); } - -static void udp_v4_hash(struct sock *sk) -{ - BUG(); -} - -static void udp_v4_unhash(struct sock *sk) -{ - write_lock_bh(&udp_hash_lock); - if (sk_del_node_init(sk)) { - inet_sk(sk)->num = 0; - sock_prot_dec_use(sk->sk_prot); - } - write_unlock_bh(&udp_hash_lock); -} - /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ -static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) +static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, + __be32 daddr, __be16 dport, + int dif, struct hlist_head udptable[]) { struct sock *sk, *result = NULL; struct hlist_node *node; unsigned short hnum = ntohs(dport); int badness = -1; - sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); if (inet->num == hnum && !ipv6_only_sock(sk)) { @@ -285,20 +275,10 @@ static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, } } } - return result; -} - -static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) -{ - struct sock *sk; - - read_lock(&udp_hash_lock); - sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif); - if (sk) - sock_hold(sk); + if (result) + sock_hold(result); read_unlock(&udp_hash_lock); - return sk; + return result; } static inline struct sock *udp_v4_mcast_next(struct sock *sk, @@ -340,7 +320,7 @@ found: * to find the appropriate port. */ -void udp_err(struct sk_buff *skb, u32 info) +void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) { struct inet_sock *inet; struct iphdr *iph = (struct iphdr*)skb->data; @@ -351,7 +331,8 @@ void udp_err(struct sk_buff *skb, u32 info) int harderr; int err; - sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); + sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, + skb->dev->ifindex, udptable ); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; /* No socket for error */ @@ -405,6 +386,11 @@ out: sock_put(sk); } +__inline__ void udp_err(struct sk_buff *skb, u32 info) +{ + return __udp4_lib_err(skb, info, udp_hash); +} + /* * Throw away all pending data and cancel the corking. Socket is locked. */ @@ -419,16 +405,56 @@ static void udp_flush_pending_frames(struct sock *sk) } } +/** + * udp4_hwcsum_outgoing - handle outgoing HW checksumming + * @sk: socket we are sending on + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, int len ) +{ + unsigned int csum = 0, offset; + struct udphdr *uh = skb->h.uh; + + if (skb_queue_len(&sk->sk_write_queue) == 1) { + /* + * Only one fragment on the socket. + */ + skb->csum = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); + } else { + /* + * HW-checksum won't work as there are two or more + * fragments on the socket so that all csums of sk_buffs + * should be together + */ + offset = skb->h.raw - skb->data; + skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed = CHECKSUM_NONE; + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + + uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = -1; + } +} + /* * Push out all pending data as one UDP datagram. Socket is locked. */ -static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) +int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) { struct inet_sock *inet = inet_sk(sk); struct flowi *fl = &inet->cork.fl; struct sk_buff *skb; struct udphdr *uh; int err = 0; + u32 csum = 0; /* Grab the skbuff where UDP header space exists. */ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) @@ -443,52 +469,28 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) uh->len = htons(up->len); uh->check = 0; - if (sk->sk_no_check == UDP_CSUM_NOXMIT) { + if (up->pcflag) /* UDP-Lite */ + csum = udplite_csum_outgoing(sk, skb); + + else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ + skb->ip_summed = CHECKSUM_NONE; goto send; - } - if (skb_queue_len(&sk->sk_write_queue) == 1) { - /* - * Only one fragment on the socket. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - skb->csum = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, 0); - } else { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, skb->csum); - if (uh->check == 0) - uh->check = -1; - } - } else { - unsigned int csum = 0; - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - int offset = (unsigned char *)uh - skb->data; - skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - skb->ip_summed = CHECKSUM_NONE; - } else { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - } + udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); + goto send; + + } else /* `normal' UDP */ + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, + sk->sk_protocol, csum ); + if (uh->check == 0) + uh->check = -1; - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, - up->len, IPPROTO_UDP, csum); - if (uh->check == 0) - uh->check = -1; - } send: err = ip_push_pending_frames(sk); out: @@ -497,12 +499,6 @@ out: return err; } - -static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base) -{ - return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); -} - int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { @@ -516,8 +512,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, __be32 daddr, faddr, saddr; __be16 dport; u8 tos; - int err; + int err, is_udplite = up->pcflag; int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); if (len > 0xFFFF) return -EMSGSIZE; @@ -622,7 +619,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { .daddr = faddr, .saddr = saddr, .tos = tos } }, - .proto = IPPROTO_UDP, + .proto = sk->sk_protocol, .uli_u = { .ports = { .sport = inet->sport, .dport = dport } } }; @@ -668,8 +665,9 @@ back_from_confirm: do_append_data: up->len += ulen; - err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, rt, + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), &ipc, rt, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); if (err) udp_flush_pending_frames(sk); @@ -684,7 +682,7 @@ out: if (free) kfree(ipc.opt); if (!err) { - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); + UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); return len; } /* @@ -695,7 +693,7 @@ out: * seems like overkill. */ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); + UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); } return err; @@ -707,8 +705,8 @@ do_confirm: goto out; } -static int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) +int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags) { struct udp_sock *up = udp_sk(sk); int ret; @@ -795,29 +793,18 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return(0); } -static __inline__ int __udp_checksum_complete(struct sk_buff *skb) -{ - return __skb_checksum_complete(skb); -} - -static __inline__ int udp_checksum_complete(struct sk_buff *skb) -{ - return skb->ip_summed != CHECKSUM_UNNECESSARY && - __udp_checksum_complete(skb); -} - /* * This should be easy, if there is something there we * return it, otherwise we block. */ -static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, int *addr_len) +int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; - int copied, err; + int copied, err, copy_only, is_udplite = IS_UDPLITE(sk); /* * Check any passed addresses @@ -839,15 +826,25 @@ try_again: msg->msg_flags |= MSG_TRUNC; } - if (skb->ip_summed==CHECKSUM_UNNECESSARY) { - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else if (msg->msg_flags&MSG_TRUNC) { - if (__udp_checksum_complete(skb)) + /* + * Decide whether to checksum and/or copy data. + * + * UDP: checksum may have been computed in HW, + * (re-)compute it if message is truncated. + * UDP-Lite: always needs to checksum, no HW support. + */ + copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); + + if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { + if (__udp_lib_checksum_complete(skb)) goto csum_copy_err; - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else { + copy_only = 1; + } + + if (copy_only) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); if (err == -EINVAL) @@ -880,7 +877,7 @@ out: return err; csum_copy_err: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); skb_kill_datagram(sk, skb, flags); @@ -912,11 +909,6 @@ int udp_disconnect(struct sock *sk, int flags) return 0; } -static void udp_close(struct sock *sk, long timeout) -{ - sk_common_release(sk); -} - /* return: * 1 if the the UDP system should process it * 0 if we should drop this packet @@ -1022,7 +1014,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) * Note that in the success and error cases, the skb is assumed to * have either been requeued or freed. */ -static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) { struct udp_sock *up = udp_sk(sk); int rc; @@ -1030,10 +1022,8 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) /* * Charge it to the socket, dropping if the queue is full. */ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - return -1; - } + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; nf_reset(skb); if (up->encap_type) { @@ -1057,31 +1047,68 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if (ret < 0) { /* process the ESP packet */ ret = xfrm4_rcv_encap(skb, up->encap_type); - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return -ret; } /* FALLTHROUGH -- it's a UDP Packet */ } - if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { - if (__udp_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return -1; + /* + * UDP-Lite specific tests, ignored on UDP sockets + */ + if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + /* + * MIB statistics other than incrementing the error count are + * disabled for the following two types of errors: these depend + * on the application settings, not on the functioning of the + * protocol stack as such. + * + * RFC 3828 here recommends (sec 3.3): "There should also be a + * way ... to ... at least let the receiving application block + * delivery of packets with coverage values less than a value + * provided by the application." + */ + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " + "%d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; } + /* The next case involves violating the min. coverage requested + * by the receiver. This is subtle: if receiver wants x and x is + * greater than the buffersize/MTU then receiver will complain + * that it wants x while sender emits packets of smaller size y. + * Therefore the above ...()->partial_cov statement is essential. + */ + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING + "UDPLITE: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { + if (__udp_lib_checksum_complete(skb)) + goto drop; skb->ip_summed = CHECKSUM_UNNECESSARY; } if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { /* Note that an ENOMEM error is charged twice */ if (rc == -ENOMEM) - UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return -1; + UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); + goto drop; } - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return 0; + +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); + kfree_skb(skb); + return -1; } /* @@ -1090,14 +1117,16 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ -static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, - __be32 saddr, __be32 daddr) +static int __udp4_lib_mcast_deliver(struct sk_buff *skb, + struct udphdr *uh, + __be32 saddr, __be32 daddr, + struct hlist_head udptable[]) { struct sock *sk; int dif; read_lock(&udp_hash_lock); - sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); dif = skb->dev->ifindex; sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (sk) { @@ -1131,65 +1160,75 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, * Otherwise, csum completion requires chacksumming packet body, * including udp header and folding it to skb->csum. */ -static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, - unsigned short ulen, __be32 saddr, __be32 daddr) +static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) { if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) + if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, + skb->len, IPPROTO_UDP, skb->csum )) skb->ip_summed = CHECKSUM_UNNECESSARY; } if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); + skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, + skb->nh.iph->daddr, + skb->len, IPPROTO_UDP, 0); /* Probably, we should checksum udp header (it should be in cache * in any case) and data in tiny packets (< rx copybreak). */ + + /* UDP = UDP-Lite with a non-partial checksum coverage */ + UDP_SKB_CB(skb)->partial_cov = 0; } /* * All we need to do is get the socket, and then do a checksum. */ -int udp_rcv(struct sk_buff *skb) +int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int is_udplite) { struct sock *sk; - struct udphdr *uh; + struct udphdr *uh = skb->h.uh; unsigned short ulen; struct rtable *rt = (struct rtable*)skb->dst; __be32 saddr = skb->nh.iph->saddr; __be32 daddr = skb->nh.iph->daddr; - int len = skb->len; /* - * Validate the packet and the UDP length. + * Validate the packet. */ if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto no_header; - - uh = skb->h.uh; + goto drop; /* No space for header. */ ulen = ntohs(uh->len); - - if (ulen > len || ulen < sizeof(*uh)) + if (ulen > skb->len) goto short_packet; - if (pskb_trim_rcsum(skb, ulen)) - goto short_packet; + if(! is_udplite ) { /* UDP validates ulen. */ + + if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) + goto short_packet; - udp_checksum_init(skb, uh, ulen, saddr, daddr); + udp4_csum_init(skb, uh); + + } else { /* UDP-Lite validates cscov. */ + if (udplite4_csum_init(skb, uh)) + goto csum_error; + } if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return udp_v4_mcast_deliver(skb, uh, saddr, daddr); + return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); + sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, + skb->dev->ifindex, udptable ); if (sk != NULL) { int ret = udp_queue_rcv_skb(sk, skb); sock_put(sk); /* a return value > 0 means to resubmit the input, but - * it it wants the return to be -protocol, or 0 + * it wants the return to be -protocol, or 0 */ if (ret > 0) return -ret; @@ -1201,10 +1240,10 @@ int udp_rcv(struct sk_buff *skb) nf_reset(skb); /* No socket. Drop packet silently, if checksum is wrong */ - if (udp_checksum_complete(skb)) + if (udp_lib_checksum_complete(skb)) goto csum_error; - UDP_INC_STATS_BH(UDP_MIB_NOPORTS); + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1215,36 +1254,40 @@ int udp_rcv(struct sk_buff *skb) return(0); short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + is_udplite? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), ulen, - len, + skb->len, NIPQUAD(daddr), ntohs(uh->dest)); -no_header: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return(0); + goto drop; csum_error: /* * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + is_udplite? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest), ulen); drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return(0); } -static int udp_destroy_sock(struct sock *sk) +__inline__ int udp_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udp_hash, 0); +} + +int udp_destroy_sock(struct sock *sk) { lock_sock(sk); udp_flush_pending_frames(sk); @@ -1293,6 +1336,32 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, } break; + /* + * UDP-Lite's partial checksum coverage (RFC 3828). + */ + /* The sender sets actual checksum coverage length via this option. + * The case coverage > packet length is handled by send module. */ + case UDPLITE_SEND_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ + val = 8; + up->pcslen = val; + up->pcflag |= UDPLITE_SEND_CC; + break; + + /* The receiver specifies a minimum checksum coverage value. To make + * sense, this should be set to at least 8 (as done below). If zero is + * used, this again means full checksum coverage. */ + case UDPLITE_RECV_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Avoid silly minimal values. */ + val = 8; + up->pcrlen = val; + up->pcflag |= UDPLITE_RECV_CC; + break; + default: err = -ENOPROTOOPT; break; @@ -1301,21 +1370,21 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, return err; } -static int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return ip_setsockopt(sk, level, optname, optval, optlen); - return do_udp_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_setsockopt(sk, level, optname, optval, optlen); + return ip_setsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return compat_ip_setsockopt(sk, level, optname, optval, optlen); - return do_udp_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_setsockopt(sk, level, optname, optval, optlen); + return compat_ip_setsockopt(sk, level, optname, optval, optlen); } #endif @@ -1342,6 +1411,16 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, val = up->encap_type; break; + /* The following two cannot be changed on UDP sockets, the return is + * always 0 (which corresponds to the full checksum coverage of UDP). */ + case UDPLITE_SEND_CSCOV: + val = up->pcslen; + break; + + case UDPLITE_RECV_CSCOV: + val = up->pcrlen; + break; + default: return -ENOPROTOOPT; }; @@ -1353,21 +1432,21 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, return 0; } -static int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return ip_getsockopt(sk, level, optname, optval, optlen); - return do_udp_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_getsockopt(sk, level, optname, optval, optlen); + return ip_getsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udp_getsockopt(struct sock *sk, int level, int optname, +int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return compat_ip_getsockopt(sk, level, optname, optval, optlen); - return do_udp_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udp_getsockopt(sk, level, optname, optval, optlen); + return compat_ip_getsockopt(sk, level, optname, optval, optlen); } #endif /** @@ -1387,7 +1466,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) { unsigned int mask = datagram_poll(file, sock, wait); struct sock *sk = sock->sk; - + int is_lite = IS_UDPLITE(sk); + /* Check for false positives due to checksum errors */ if ( (mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && @@ -1397,8 +1477,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) spin_lock_bh(&rcvq->lock); while ((skb = skb_peek(rcvq)) != NULL) { - if (udp_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + if (udp_lib_checksum_complete(skb)) { + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite); __skb_unlink(skb, rcvq); kfree_skb(skb); } else { @@ -1420,7 +1500,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) struct proto udp_prot = { .name = "UDP", .owner = THIS_MODULE, - .close = udp_close, + .close = udp_lib_close, .connect = ip4_datagram_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, @@ -1431,8 +1511,8 @@ struct proto udp_prot = { .recvmsg = udp_recvmsg, .sendpage = udp_sendpage, .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_v4_hash, - .unhash = udp_v4_unhash, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, .get_port = udp_v4_get_port, .obj_size = sizeof(struct udp_sock), #ifdef CONFIG_COMPAT @@ -1451,7 +1531,7 @@ static struct sock *udp_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; - sk_for_each(sk, node, &udp_hash[state->bucket]) { + sk_for_each(sk, node, state->hashtable + state->bucket) { if (sk->sk_family == state->family) goto found; } @@ -1472,7 +1552,7 @@ try_again: } while (sk && sk->sk_family != state->family); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { - sk = sk_head(&udp_hash[state->bucket]); + sk = sk_head(state->hashtable + state->bucket); goto try_again; } return sk; @@ -1522,6 +1602,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) if (!s) goto out; s->family = afinfo->family; + s->hashtable = afinfo->hashtable; s->seq_ops.start = udp_seq_start; s->seq_ops.next = udp_seq_next; s->seq_ops.show = afinfo->seq_show; @@ -1588,7 +1669,7 @@ static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) atomic_read(&sp->sk_refcnt), sp); } -static int udp4_seq_show(struct seq_file *seq, void *v) +int udp4_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_printf(seq, "%-127s\n", @@ -1611,6 +1692,7 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { .owner = THIS_MODULE, .name = "udp", .family = AF_INET, + .hashtable = udp_hash, .seq_show = udp4_seq_show, .seq_fops = &udp4_seq_fops, }; diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h new file mode 100644 index 000000000000..f6f4277ba6dc --- /dev/null +++ b/net/ipv4/udp_impl.h @@ -0,0 +1,38 @@ +#ifndef _UDP4_IMPL_H +#define _UDP4_IMPL_H +#include +#include +#include +#include + +extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); +extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); + +extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, + struct hlist_head udptable[], int *port_rover, + int (*)(const struct sock*,const struct sock*)); +extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); + + +extern int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); + +#ifdef CONFIG_COMPAT +extern int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int compat_udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +#endif +extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len); +extern int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags); +extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); +extern int udp_destroy_sock(struct sock *sk); + +#ifdef CONFIG_PROC_FS +extern int udp4_seq_show(struct seq_file *seq, void *v); +#endif +#endif /* _UDP4_IMPL_H */ diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c new file mode 100644 index 000000000000..561de6d8c734 --- /dev/null +++ b/net/ipv4/udplite.c @@ -0,0 +1,119 @@ +/* + * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). + * + * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" +DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; + +struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; +static int udplite_port_rover; + +__inline__ int udplite_get_port(struct sock *sk, unsigned short p, + int (*c)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); +} + +static __inline__ int udplite_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +__inline__ int udplite_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udplite_hash, 1); +} + +__inline__ void udplite_err(struct sk_buff *skb, u32 info) +{ + return __udp4_lib_err(skb, info, udplite_hash); +} + +static struct net_protocol udplite_protocol = { + .handler = udplite_rcv, + .err_handler = udplite_err, + .no_policy = 1, +}; + +struct proto udplite_prot = { + .name = "UDP-Lite", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v4_get_port, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif +}; + +static struct inet_protosw udplite4_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplite_prot, + .ops = &inet_dgram_ops, + .capability = -1, + .no_check = 0, /* must checksum (RFC 3828) */ + .flags = INET_PROTOSW_PERMANENT, +}; + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite4_seq_fops; +static struct udp_seq_afinfo udplite4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite", + .family = AF_INET, + .hashtable = udplite_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udplite4_seq_fops, +}; +#endif + +void __init udplite4_register(void) +{ + if (proto_register(&udplite_prot, 1)) + goto out_register_err; + + if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) + goto out_unregister_proto; + + inet_register_protosw(&udplite4_protosw); + +#ifdef CONFIG_PROC_FS + if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ + printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); +#endif + return; + +out_unregister_proto: + proto_unregister(&udplite_prot); +out_register_err: + printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); +} + +EXPORT_SYMBOL(udplite_hash); +EXPORT_SYMBOL(udplite_prot); +EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index da766234607b..d4107bb701b5 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -199,6 +199,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { switch (iph->protocol) { case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index addcc011bc01..8bacda109b7f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -5,8 +5,8 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \ - protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ + route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ + raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ ip6_flowlabel.o ipv6_syms.o inet6_connection_sock.o diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 92bfccf62cb7..1eb1c7f261d4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -737,8 +738,13 @@ static int __init init_ipv6_mibs(void) if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), __alignof__(struct udp_mib)) < 0) goto err_udp_mib; + if (snmp6_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib), + __alignof__(struct udp_mib)) < 0) + goto err_udplite_mib; return 0; +err_udplite_mib: + snmp6_mib_free((void **)udp_stats_in6); err_udp_mib: snmp6_mib_free((void **)icmpv6_statistics); err_icmp_mib: @@ -753,6 +759,7 @@ static void cleanup_ipv6_mibs(void) snmp6_mib_free((void **)ipv6_statistics); snmp6_mib_free((void **)icmpv6_statistics); snmp6_mib_free((void **)udp_stats_in6); + snmp6_mib_free((void **)udplite_stats_in6); } static int __init inet6_init(void) @@ -780,10 +787,14 @@ static int __init inet6_init(void) if (err) goto out_unregister_tcp_proto; - err = proto_register(&rawv6_prot, 1); + err = proto_register(&udplitev6_prot, 1); if (err) goto out_unregister_udp_proto; + err = proto_register(&rawv6_prot, 1); + if (err) + goto out_unregister_udplite_proto; + /* Register the socket-side information for inet6_create. */ for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) @@ -837,6 +848,8 @@ static int __init inet6_init(void) goto proc_tcp6_fail; if (udp6_proc_init()) goto proc_udp6_fail; + if (udplite6_proc_init()) + goto proc_udplite6_fail; if (ipv6_misc_proc_init()) goto proc_misc6_fail; @@ -862,6 +875,7 @@ static int __init inet6_init(void) /* Init v6 transport protocols. */ udpv6_init(); + udplitev6_init(); tcpv6_init(); ipv6_packet_init(); @@ -879,6 +893,8 @@ proc_if6_fail: proc_anycast6_fail: ipv6_misc_proc_exit(); proc_misc6_fail: + udplite6_proc_exit(); +proc_udplite6_fail: udp6_proc_exit(); proc_udp6_fail: tcp6_proc_exit(); @@ -902,6 +918,8 @@ out_unregister_sock: sock_unregister(PF_INET6); out_unregister_raw_proto: proto_unregister(&rawv6_prot); +out_unregister_udplite_proto: + proto_unregister(&udplitev6_prot); out_unregister_udp_proto: proto_unregister(&udpv6_prot); out_unregister_tcp_proto: @@ -919,6 +937,7 @@ static void __exit inet6_exit(void) ac6_proc_exit(); ipv6_misc_proc_exit(); udp6_proc_exit(); + udplite6_proc_exit(); tcp6_proc_exit(); raw6_proc_exit(); #endif diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index de6b91981b30..1eafcfc95e81 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -239,6 +240,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) break; @@ -276,11 +278,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sk->sk_family = PF_INET; tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); } else { + struct proto *prot = &udp_prot; + + if (sk->sk_protocol == IPPROTO_UDPLITE) + prot = &udplite_prot; local_bh_disable(); sock_prot_dec_use(sk->sk_prot); - sock_prot_inc_use(&udp_prot); + sock_prot_inc_use(prot); local_bh_enable(); - sk->sk_prot = &udp_prot; + sk->sk_prot = prot; sk->sk_socket->ops = &inet_dgram_ops; sk->sk_family = PF_INET; } @@ -813,6 +819,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 0cf537d30185..3cb6bb79cc05 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -270,11 +270,15 @@ static void dump_packet(const struct nf_loginfo *info, } break; } - case IPPROTO_UDP: { + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { struct udphdr _udph, *uh; - /* Max length: 10 "PROTO=UDP " */ - printk("PROTO=UDP "); + if (currenthdr == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + printk("PROTO=UDP " ); + else /* Max length: 14 "PROTO=UDPLITE " */ + printk("PROTO=UDPLITE "); if (fragment) break; diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 4158d386b0aa..35249d8487bb 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -49,6 +49,8 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) fold_prot_inuse(&tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", fold_prot_inuse(&udpv6_prot)); + seq_printf(seq, "UDPLITE6: inuse %d\n", + fold_prot_inuse(&udplitev6_prot)); seq_printf(seq, "RAW6: inuse %d\n", fold_prot_inuse(&rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", @@ -133,6 +135,14 @@ static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_SENTINEL }; +static struct snmp_mib snmp6_udplite6_list[] = { + SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), + SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), + SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), + SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), + SNMP_MIB_SENTINEL +}; + static unsigned long fold_field(void *mib[], int offt) { @@ -167,6 +177,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); + snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); } return 0; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 886300d13a59..5a64027bf2fc 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -38,26 +38,18 @@ #include #include -#include -#include - -#include #include #include #include #include -#include -#include -#include #include -#include #include - #include #include #include #include +#include "udp_impl.h" DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; @@ -66,23 +58,9 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); } -static void udp_v6_hash(struct sock *sk) -{ - BUG(); -} - -static void udp_v6_unhash(struct sock *sk) -{ - write_lock_bh(&udp_hash_lock); - if (sk_del_node_init(sk)) { - inet_sk(sk)->num = 0; - sock_prot_dec_use(sk->sk_prot); - } - write_unlock_bh(&udp_hash_lock); -} - -static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, - struct in6_addr *daddr, u16 dport, int dif) +static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, + struct in6_addr *daddr, __be16 dport, + int dif, struct hlist_head udptable[]) { struct sock *sk, *result = NULL; struct hlist_node *node; @@ -90,7 +68,7 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, int badness = -1; read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); if (inet->num == hnum && sk->sk_family == PF_INET6) { @@ -131,21 +109,12 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, return result; } -/* - * - */ - -static void udpv6_close(struct sock *sk, long timeout) -{ - sk_common_release(sk); -} - /* * This should be easy, if there is something there we * return it, otherwise we block. */ -static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, +int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { @@ -153,7 +122,7 @@ static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct inet_sock *inet = inet_sk(sk); struct sk_buff *skb; size_t copied; - int err; + int err, copy_only, is_udplite = IS_UDPLITE(sk); if (addr_len) *addr_len=sizeof(struct sockaddr_in6); @@ -172,15 +141,21 @@ try_again: msg->msg_flags |= MSG_TRUNC; } - if (skb->ip_summed==CHECKSUM_UNNECESSARY) { - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else if (msg->msg_flags&MSG_TRUNC) { - if (__skb_checksum_complete(skb)) + /* + * Decide whether to checksum and/or copy data. + */ + copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); + + if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { + if (__udp_lib_checksum_complete(skb)) goto csum_copy_err; - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, - copied); - } else { + copy_only = 1; + } + + if (copy_only) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); if (err == -EINVAL) goto csum_copy_err; @@ -231,14 +206,15 @@ csum_copy_err: skb_kill_datagram(sk, skb, flags); if (flags & MSG_DONTWAIT) { - UDP6_INC_STATS_USER(UDP_MIB_INERRORS); + UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); return -EAGAIN; } goto try_again; } -static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) +void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info, + struct hlist_head udptable[] ) { struct ipv6_pinfo *np; struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; @@ -248,8 +224,8 @@ static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct sock *sk; int err; - sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, inet6_iif(skb)); - + sk = __udp6_lib_lookup(daddr, uh->dest, + saddr, uh->source, inet6_iif(skb), udptable); if (sk == NULL) return; @@ -270,31 +246,55 @@ out: sock_put(sk); } -static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +static __inline__ void udpv6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, int type, + int code, int offset, __u32 info ) +{ + return __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); +} + +int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) { + struct udp_sock *up = udp_sk(sk); int rc; - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - return -1; - } + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; - if (skb_checksum_complete(skb)) { - UDP6_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return 0; + /* + * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). + */ + if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" + " %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " + "too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } } + if (udp_lib_checksum_complete(skb)) + goto drop; + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { /* Note that an ENOMEM error is charged twice */ if (rc == -ENOMEM) - UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); - UDP6_INC_STATS_BH(UDP_MIB_INERRORS); - kfree_skb(skb); - return 0; + UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); + goto drop; } - UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); return 0; +drop: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); + kfree_skb(skb); + return -1; } static struct sock *udp_v6_mcast_next(struct sock *sk, @@ -338,15 +338,15 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ -static void udpv6_mcast_deliver(struct udphdr *uh, - struct in6_addr *saddr, struct in6_addr *daddr, - struct sk_buff *skb) +static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, + struct in6_addr *daddr, struct hlist_head udptable[]) { struct sock *sk, *sk2; + const struct udphdr *uh = skb->h.uh; int dif; read_lock(&udp_hash_lock); - sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); dif = inet6_iif(skb); sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) { @@ -364,9 +364,34 @@ static void udpv6_mcast_deliver(struct udphdr *uh, udpv6_queue_rcv_skb(sk, skb); out: read_unlock(&udp_hash_lock); + return 0; } -static int udpv6_rcv(struct sk_buff **pskb) +static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) + +{ + if (uh->check == 0) { + /* RFC 2460 section 8.1 says that we SHOULD log + this error. Well, it is reasonable. + */ + LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); + return 1; + } + if (skb->ip_summed == CHECKSUM_COMPLETE && + !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, + skb->len, IPPROTO_UDP, skb->csum )) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (skb->ip_summed != CHECKSUM_UNNECESSARY) + skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, + skb->len, IPPROTO_UDP, 0); + + return (UDP_SKB_CB(skb)->partial_cov = 0); +} + +int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], + int is_udplite) { struct sk_buff *skb = *pskb; struct sock *sk; @@ -383,44 +408,39 @@ static int udpv6_rcv(struct sk_buff **pskb) uh = skb->h.uh; ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; - /* Check for jumbo payload */ - if (ulen == 0) - ulen = skb->len; + if(! is_udplite ) { /* UDP validates ulen. */ - if (ulen > skb->len || ulen < sizeof(*uh)) - goto short_packet; + /* Check for jumbo payload */ + if (ulen == 0) + ulen = skb->len; - if (uh->check == 0) { - /* RFC 2460 section 8.1 says that we SHOULD log - this error. Well, it is reasonable. - */ - LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); - goto discard; - } + if (ulen < sizeof(*uh)) + goto short_packet; - if (ulen < skb->len) { - if (pskb_trim_rcsum(skb, ulen)) - goto discard; - saddr = &skb->nh.ipv6h->saddr; - daddr = &skb->nh.ipv6h->daddr; - uh = skb->h.uh; - } + if (ulen < skb->len) { + if (pskb_trim_rcsum(skb, ulen)) + goto short_packet; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + uh = skb->h.uh; + } - if (skb->ip_summed == CHECKSUM_COMPLETE && - !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (udp6_csum_init(skb, uh)) + goto discard; - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); + } else { /* UDP-Lite validates cscov. */ + if (udplite6_csum_init(skb, uh)) + goto discard; + } /* * Multicast receive code */ - if (ipv6_addr_is_multicast(daddr)) { - udpv6_mcast_deliver(uh, saddr, daddr, skb); - return 0; - } + if (ipv6_addr_is_multicast(daddr)) + return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); /* Unicast */ @@ -428,15 +448,16 @@ static int udpv6_rcv(struct sk_buff **pskb) * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, inet6_iif(skb)); + sk = __udp6_lib_lookup(saddr, uh->source, + daddr, uh->dest, inet6_iif(skb), udptable); if (sk == NULL) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard; - if (skb_checksum_complete(skb)) + if (udp_lib_checksum_complete(skb)) goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); + UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); @@ -451,14 +472,20 @@ static int udpv6_rcv(struct sk_buff **pskb) return(0); short_packet: - if (net_ratelimit()) - printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len); + LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", + is_udplite? "-Lite" : "", ulen, skb->len); discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS); + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return(0); } + +static __inline__ int udpv6_rcv(struct sk_buff **pskb) +{ + return __udp6_lib_rcv(pskb, udp_hash, 0); +} + /* * Throw away all pending data and cancel the corking. Socket is locked. */ @@ -484,6 +511,7 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) struct inet_sock *inet = inet_sk(sk); struct flowi *fl = &inet->cork.fl; int err = 0; + u32 csum = 0; /* Grab the skbuff where UDP header space exists. */ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) @@ -498,35 +526,17 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) uh->len = htons(up->len); uh->check = 0; - if (sk->sk_no_check == UDP_CSUM_NOXMIT) { - skb->ip_summed = CHECKSUM_NONE; - goto send; - } - - if (skb_queue_len(&sk->sk_write_queue) == 1) { - skb->csum = csum_partial((char *)uh, - sizeof(struct udphdr), skb->csum); - uh->check = csum_ipv6_magic(&fl->fl6_src, - &fl->fl6_dst, - up->len, fl->proto, skb->csum); - } else { - u32 tmp_csum = 0; - - skb_queue_walk(&sk->sk_write_queue, skb) { - tmp_csum = csum_add(tmp_csum, skb->csum); - } - tmp_csum = csum_partial((char *)uh, - sizeof(struct udphdr), tmp_csum); - tmp_csum = csum_ipv6_magic(&fl->fl6_src, - &fl->fl6_dst, - up->len, fl->proto, tmp_csum); - uh->check = tmp_csum; + if (up->pcflag) + csum = udplite_csum_outgoing(sk, skb); + else + csum = udp_csum_outgoing(sk, skb); - } + /* add protocol-dependent pseudo-header */ + uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, + up->len, fl->proto, csum ); if (uh->check == 0) uh->check = -1; -send: err = ip6_push_pending_frames(sk); out: up->len = 0; @@ -534,7 +544,7 @@ out: return err; } -static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, +int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { struct ipv6_txoptions opt_space; @@ -554,6 +564,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; int err; int connected = 0; + int is_udplite = up->pcflag; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); /* destination address check */ if (sin6) { @@ -694,7 +706,7 @@ do_udp_sendmsg: opt = fl6_merge_options(&opt_space, flowlabel, opt); opt = ipv6_fixup_options(&opt_space, opt); - fl.proto = IPPROTO_UDP; + fl.proto = sk->sk_protocol; ipv6_addr_copy(&fl.fl6_dst, daddr); if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) ipv6_addr_copy(&fl.fl6_src, &np->saddr); @@ -761,7 +773,8 @@ back_from_confirm: do_append_data: up->len += ulen; - err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), hlimit, tclass, opt, &fl, (struct rt6_info*)dst, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); @@ -793,7 +806,7 @@ do_append_data: out: fl6_sock_release(flowlabel); if (!err) { - UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); + UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); return len; } /* @@ -804,7 +817,7 @@ out: * seems like overkill. */ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); + UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); } return err; @@ -816,7 +829,7 @@ do_confirm: goto out; } -static int udpv6_destroy_sock(struct sock *sk) +int udpv6_destroy_sock(struct sock *sk) { lock_sock(sk); udp_v6_flush_pending_frames(sk); @@ -854,7 +867,6 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, release_sock(sk); } break; - case UDP_ENCAP: switch (val) { case 0: @@ -866,6 +878,24 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, } break; + case UDPLITE_SEND_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ + val = 8; + up->pcslen = val; + up->pcflag |= UDPLITE_SEND_CC; + break; + + case UDPLITE_RECV_CSCOV: + if (!up->pcflag) /* Disable the option on UDP sockets */ + return -ENOPROTOOPT; + if (val != 0 && val < 8) /* Avoid silly minimal values. */ + val = 8; + up->pcrlen = val; + up->pcflag |= UDPLITE_RECV_CC; + break; + default: err = -ENOPROTOOPT; break; @@ -874,22 +904,21 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, return err; } -static int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return ipv6_setsockopt(sk, level, optname, optval, optlen); - return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + return ipv6_setsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) +int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) { - if (level != SOL_UDP) - return compat_ipv6_setsockopt(sk, level, optname, - optval, optlen); - return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_setsockopt(sk, level, optname, optval, optlen); + return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); } #endif @@ -916,6 +945,14 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, val = up->encap_type; break; + case UDPLITE_SEND_CSCOV: + val = up->pcslen; + break; + + case UDPLITE_RECV_CSCOV: + val = up->pcrlen; + break; + default: return -ENOPROTOOPT; }; @@ -927,22 +964,21 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, return 0; } -static int udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return ipv6_getsockopt(sk, level, optname, optval, optlen); - return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + return ipv6_getsockopt(sk, level, optname, optval, optlen); } #ifdef CONFIG_COMPAT -static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) +int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) { - if (level != SOL_UDP) - return compat_ipv6_getsockopt(sk, level, optname, - optval, optlen); - return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + if (level == SOL_UDP || level == SOL_UDPLITE) + return do_udpv6_getsockopt(sk, level, optname, optval, optlen); + return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); } #endif @@ -983,7 +1019,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket atomic_read(&sp->sk_refcnt), sp); } -static int udp6_seq_show(struct seq_file *seq, void *v) +int udp6_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_printf(seq, @@ -1002,6 +1038,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { .owner = THIS_MODULE, .name = "udp6", .family = AF_INET6, + .hashtable = udp_hash, .seq_show = udp6_seq_show, .seq_fops = &udp6_seq_fops, }; @@ -1021,7 +1058,7 @@ void udp6_proc_exit(void) { struct proto udpv6_prot = { .name = "UDPv6", .owner = THIS_MODULE, - .close = udpv6_close, + .close = udp_lib_close, .connect = ip6_datagram_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, @@ -1031,8 +1068,8 @@ struct proto udpv6_prot = { .sendmsg = udpv6_sendmsg, .recvmsg = udpv6_recvmsg, .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_v6_hash, - .unhash = udp_v6_unhash, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, .get_port = udp_v6_get_port, .obj_size = sizeof(struct udp6_sock), #ifdef CONFIG_COMPAT diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h new file mode 100644 index 000000000000..ec9878899128 --- /dev/null +++ b/net/ipv6/udp_impl.h @@ -0,0 +1,34 @@ +#ifndef _UDP6_IMPL_H +#define _UDP6_IMPL_H +#include +#include +#include +#include +#include + +extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int ); +extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, + int , int , int , __be32 , struct hlist_head []); + +extern int udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +extern int udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +#ifdef CONFIG_COMPAT +extern int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen); +extern int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +#endif +extern int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len); +extern int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len, + int noblock, int flags, int *addr_len); +extern int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); +extern int udpv6_destroy_sock(struct sock *sk); + +#ifdef CONFIG_PROC_FS +extern int udp6_seq_show(struct seq_file *seq, void *v); +#endif +#endif /* _UDP6_IMPL_H */ diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c new file mode 100644 index 000000000000..e0ec5e63004a --- /dev/null +++ b/net/ipv6/udplite.c @@ -0,0 +1,105 @@ +/* + * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. + * See also net/ipv4/udplite.c + * + * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" + +DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; + +static __inline__ int udplitev6_rcv(struct sk_buff **pskb) +{ + return __udp6_lib_rcv(pskb, udplite_hash, 1); +} + +static __inline__ void udplitev6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) +{ + return __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); +} + +static struct inet6_protocol udplitev6_protocol = { + .handler = udplitev6_rcv, + .err_handler = udplitev6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +static __inline__ int udplite_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +struct proto udplitev6_prot = { + .name = "UDPLITEv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v6_get_port, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif +}; + +static struct inet_protosw udplite6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplitev6_prot, + .ops = &inet6_dgram_ops, + .capability = -1, + .no_check = 0, + .flags = INET_PROTOSW_PERMANENT, +}; + +void __init udplitev6_init(void) +{ + if (inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE) < 0) + printk(KERN_ERR "%s: Could not register.\n", __FUNCTION__); + + inet6_register_protosw(&udplite6_protosw); +} + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite6_seq_fops; +static struct udp_seq_afinfo udplite6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite6", + .family = AF_INET6, + .hashtable = udplite_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udplite6_seq_fops, +}; + +int __init udplite6_proc_init(void) +{ + return udp_proc_register(&udplite6_seq_afinfo); +} + +void udplite6_proc_exit(void) +{ + udp_proc_unregister(&udplite6_seq_afinfo); +} +#endif diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 2fba1f0739aa..8dffd4daae9c 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -274,6 +274,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl) break; case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index b4293058c6ff..1602086c7fd6 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c @@ -1,5 +1,5 @@ -/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in - the same place so we can treat them as equal. */ +/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports: + ports are in the same place so we can treat them as equal. */ /* (C) 1999-2001 Paul `Rusty' Russell * (C) 2002-2004 Netfilter Core Team @@ -162,6 +162,7 @@ check(u_int16_t proto, { /* Must specify supported protocol, no unknown flags or bad count */ return (proto == IPPROTO_TCP || proto == IPPROTO_UDP + || proto == IPPROTO_UDPLITE || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP) && !(ip_invflags & XT_INV_PROTO) && (match_flags == XT_MULTIPORT_SOURCE diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index e76a68e0bc66..46414b562a19 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c @@ -10,7 +10,7 @@ #include #include -MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6"); +MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6"); MODULE_LICENSE("GPL"); MODULE_ALIAS("xt_tcp"); MODULE_ALIAS("xt_udp"); @@ -234,6 +234,24 @@ static struct xt_match xt_tcpudp_match[] = { .proto = IPPROTO_UDP, .me = THIS_MODULE, }, + { + .name = "udplite", + .family = AF_INET, + .checkentry = udp_checkentry, + .match = udp_match, + .matchsize = sizeof(struct xt_udp), + .proto = IPPROTO_UDPLITE, + .me = THIS_MODULE, + }, + { + .name = "udplite", + .family = AF_INET6, + .checkentry = udp_checkentry, + .match = udp_match, + .matchsize = sizeof(struct xt_udp), + .proto = IPPROTO_UDPLITE, + .me = THIS_MODULE, + }, }; static int __init xt_tcpudp_init(void) -- cgit v1.2.3-71-gd317 From 714e85be3557222bc25f69c252326207c900a7db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 20:51:49 -0800 Subject: [IPV6]: Assorted trivial endianness annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 14 ++++++++------ include/net/arp.h | 2 +- include/net/ip.h | 11 ++++++----- net/ipv4/af_inet.c | 6 +++--- net/ipv4/arp.c | 2 +- net/ipv4/cipso_ipv4.c | 8 ++++---- net/ipv4/devinet.c | 10 +++++----- net/ipv4/ip_output.c | 2 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 4 ++-- net/ipv4/syncookies.c | 18 +++++++++--------- net/ipv4/tcp_ipv4.c | 10 +++++----- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_timer.c | 2 +- 15 files changed, 50 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 5a0ab04627bc..c0f7aec331c2 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -124,12 +124,13 @@ static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) * Check if a mask is acceptable. */ -static __inline__ int bad_mask(u32 mask, u32 addr) +static __inline__ int bad_mask(__be32 mask, __be32 addr) { + __u32 hmask; if (addr & (mask = ~mask)) return 1; - mask = ntohl(mask); - if (mask & (mask+1)) + hmask = ntohl(mask); + if (hmask & (hmask+1)) return 1; return 0; } @@ -190,11 +191,12 @@ static __inline__ __be32 inet_make_mask(int logmask) return 0; } -static __inline__ int inet_mask_len(__u32 mask) +static __inline__ int inet_mask_len(__be32 mask) { - if (!(mask = ntohl(mask))) + __u32 hmask = ntohl(mask); + if (!hmask) return 0; - return 32 - ffz(~mask); + return 32 - ffz(~hmask); } diff --git a/include/net/arp.h b/include/net/arp.h index 6a3d9a7d302b..f02664568600 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -16,7 +16,7 @@ extern void arp_send(int type, int ptype, __be32 dest_ip, struct net_device *dev, __be32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th); extern int arp_bind_neighbour(struct dst_entry *dst); -extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir); +extern int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir); extern void arp_ifdown(struct net_device *dev); extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, diff --git a/include/net/ip.h b/include/net/ip.h index 949fa8683626..412e8114667d 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -123,7 +123,7 @@ extern int ip4_datagram_connect(struct sock *sk, * multicast packets. */ -static inline void ip_tr_mc_map(u32 addr, char *buf) +static inline void ip_tr_mc_map(__be32 addr, char *buf) { buf[0]=0xC0; buf[1]=0x00; @@ -238,9 +238,9 @@ static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst * Map a multicast IP onto multicast MAC for type ethernet. */ -static inline void ip_eth_mc_map(u32 addr, char *buf) +static inline void ip_eth_mc_map(__be32 naddr, char *buf) { - addr=ntohl(addr); + __u32 addr=ntohl(naddr); buf[0]=0x01; buf[1]=0x00; buf[2]=0x5e; @@ -256,13 +256,14 @@ static inline void ip_eth_mc_map(u32 addr, char *buf) * Leave P_Key as 0 to be filled in by driver. */ -static inline void ip_ib_mc_map(u32 addr, char *buf) +static inline void ip_ib_mc_map(__be32 naddr, char *buf) { + __u32 addr; buf[0] = 0; /* Reserved */ buf[1] = 0xff; /* Multicast QPN */ buf[2] = 0xff; buf[3] = 0xff; - addr = ntohl(addr); + addr = ntohl(naddr); buf[4] = 0xff; buf[5] = 0x12; /* link local scope */ buf[6] = 0x40; /* IPv4 signature */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8db39f7e3bf0..1144900d37f6 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -644,7 +644,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, sin->sin_port = inet->dport; sin->sin_addr.s_addr = inet->daddr; } else { - __u32 addr = inet->rcv_saddr; + __be32 addr = inet->rcv_saddr; if (!addr) addr = inet->saddr; sin->sin_port = inet->sport; @@ -995,8 +995,8 @@ static int inet_sk_reselect_saddr(struct sock *sk) struct inet_sock *inet = inet_sk(sk); int err; struct rtable *rt; - __u32 old_saddr = inet->saddr; - __u32 new_saddr; + __be32 old_saddr = inet->saddr; + __be32 new_saddr; __be32 daddr = inet->daddr; if (inet->opt && inet->opt->srr) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index cfb5d3de9c84..3981e8be9ab8 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -203,7 +203,7 @@ struct neigh_table arp_tbl = { .gc_thresh3 = 1024, }; -int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) +int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) { switch (dev->type) { case ARPHRD_ETHER: diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 6460233407c7..c3a61ebbadef 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -966,7 +966,7 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, buf[0] = IPOPT_CIPSO; buf[1] = CIPSO_V4_HDR_LEN + len; - *(u32 *)&buf[2] = htonl(doi_def->doi); + *(__be32 *)&buf[2] = htonl(doi_def->doi); return 0; } @@ -1140,7 +1140,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2]))); + doi_def = cipso_v4_doi_getdef(ntohl(*((__be32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; @@ -1370,7 +1370,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) if (ret_val == 0) return ret_val; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) { @@ -1436,7 +1436,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) return 0; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index f38cbbae0ae3..a1b356c8aa59 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -577,20 +577,20 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg * Determine a default network mask, based on the IP address. */ -static __inline__ int inet_abc_len(u32 addr) +static __inline__ int inet_abc_len(__be32 addr) { int rc = -1; /* Something else, probably a multicast. */ if (ZERONET(addr)) rc = 0; else { - addr = ntohl(addr); + __u32 haddr = ntohl(addr); - if (IN_CLASSA(addr)) + if (IN_CLASSA(haddr)) rc = 8; - else if (IN_CLASSB(addr)) + else if (IN_CLASSB(haddr)) rc = 16; - else if (IN_CLASSC(addr)) + else if (IN_CLASSC(haddr)) rc = 24; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index def32d8d3b06..90942a384a45 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -341,7 +341,7 @@ packet_routed: /* OK, we know where to send it, allocate and build IP header. */ iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); - *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); + *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); iph->tot_len = htons(skb->len); if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok) iph->frag_off = htons(IP_DF); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 4b132953bcc2..57d4bae6f080 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -355,7 +355,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) sin = (struct sockaddr_in *)msg->msg_name; if (sin) { sin->sin_family = AF_INET; - sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset); + sin->sin_addr.s_addr = *(__be32*)(skb->nh.raw + serr->addr_offset); sin->sin_port = serr->port; memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 5c31dead2bdc..a6c63bbd9ddb 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -854,8 +854,8 @@ static void raw_seq_stop(struct seq_file *seq, void *v) static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i) { struct inet_sock *inet = inet_sk(sp); - unsigned int dest = inet->daddr, - src = inet->rcv_saddr; + __be32 dest = inet->daddr, + src = inet->rcv_saddr; __u16 destp = 0, srcp = inet->num; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d7152b2b2c64..ee00b6506ab4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -566,8 +566,8 @@ static inline u32 rt_score(struct rtable *rt) static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { - return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | - (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) | + return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | + (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr)) | (fl1->mark ^ fl2->mark) | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) | diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 661e0a4bca72..6b19530905af 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -35,23 +35,23 @@ module_init(init_syncookies); #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) -static u32 cookie_hash(u32 saddr, u32 daddr, u32 sport, u32 dport, +static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u32 count, int c) { __u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS]; memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c])); - tmp[0] = saddr; - tmp[1] = daddr; - tmp[2] = (sport << 16) + dport; + tmp[0] = (__force u32)saddr; + tmp[1] = (__force u32)daddr; + tmp[2] = ((__force u32)sport << 16) + (__force u32)dport; tmp[3] = count; sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5); return tmp[17]; } -static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, - __u16 dport, __u32 sseq, __u32 count, +static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, + __be16 dport, __u32 sseq, __u32 count, __u32 data) { /* @@ -80,8 +80,8 @@ static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport, * "maxdiff" if the current (passed-in) "count". The return value * is (__u32)-1 if this test fails. */ -static __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, - __u16 sport, __u16 dport, __u32 sseq, +static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr, + __be16 sport, __be16 dport, __u32 sseq, __u32 count, __u32 maxdiff) { __u32 diff; @@ -220,7 +220,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, } ireq = inet_rsk(req); treq = tcp_rsk(req); - treq->rcv_isn = htonl(skb->h.th->seq) - 1; + treq->rcv_isn = ntohl(skb->h.th->seq) - 1; treq->snt_isn = cookie; req->mss = mss; ireq->rmt_port = skb->h.th->source; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8c8e8112f98d..0ca8dead03b0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -542,7 +542,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct { struct tcphdr th; #ifdef CONFIG_TCP_MD5SIG - u32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; + __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; #endif } rep; struct ip_reply_arg arg; @@ -618,9 +618,9 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, struct tcphdr *th = skb->h.th; struct { struct tcphdr th; - u32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) + __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) #ifdef CONFIG_TCP_MD5SIG - + (TCPOLEN_MD5SIG_ALIGNED >> 2) + + (TCPOLEN_MD5SIG_ALIGNED >> 2) #endif ]; } rep; @@ -2333,8 +2333,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) struct tcp_sock *tp = tcp_sk(sp); const struct inet_connection_sock *icsk = inet_csk(sp); struct inet_sock *inet = inet_sk(sp); - unsigned int dest = inet->daddr; - unsigned int src = inet->rcv_saddr; + __be32 dest = inet->daddr; + __be32 src = inet->rcv_saddr; __u16 destp = ntohs(inet->dport); __u16 srcp = ntohs(inet->sport); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4a0ee901a888..383cb38461c5 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -493,7 +493,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, struct request_sock **prev) { struct tcphdr *th = skb->h.th; - u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); int paws_reject = 0; struct tcp_options_received tmp_opt; struct sock *child; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index fb09ade5897b..3355c276b611 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -297,7 +297,7 @@ static void tcp_retransmit_timer(struct sock *sk) if (net_ratelimit()) { struct inet_sock *inet = inet_sk(sk); printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", - NIPQUAD(inet->daddr), htons(inet->dport), + NIPQUAD(inet->daddr), ntohs(inet->dport), inet->num, tp->snd_una, tp->snd_nxt); } #endif -- cgit v1.2.3-71-gd317 From b09b845ca6724c3bbdc00c0cb2313258c7189ca9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 20:52:19 -0800 Subject: [RANDOM]: Annotate random.h IP helpers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/char/random.c | 48 ++++++++++++++++++++++++------------------------ include/linux/random.h | 20 ++++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/random.c b/drivers/char/random.c index eb6b13f4211a..d40df30c2b10 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1466,8 +1466,8 @@ static __init int seqgen_init(void) late_initcall(seqgen_init); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, - __u16 sport, __u16 dport) +__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, + __be16 sport, __be16 dport) { struct timeval tv; __u32 seq; @@ -1479,10 +1479,10 @@ __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, */ memcpy(hash, saddr, 16); - hash[4]=(sport << 16) + dport; + hash[4]=((__force u16)sport << 16) + (__force u16)dport; memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); - seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; + seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; seq += keyptr->count; do_gettimeofday(&tv); @@ -1496,7 +1496,7 @@ EXPORT_SYMBOL(secure_tcpv6_sequence_number); /* The code below is shamelessly stolen from secure_tcp_sequence_number(). * All blames to Andrey V. Savochkin . */ -__u32 secure_ip_id(__u32 daddr) +__u32 secure_ip_id(__be32 daddr) { struct keydata *keyptr; __u32 hash[4]; @@ -1508,7 +1508,7 @@ __u32 secure_ip_id(__u32 daddr) * The dest ip address is placed in the starting vector, * which is then hashed with random data. */ - hash[0] = daddr; + hash[0] = (__force __u32)daddr; hash[1] = keyptr->secret[9]; hash[2] = keyptr->secret[10]; hash[3] = keyptr->secret[11]; @@ -1518,8 +1518,8 @@ __u32 secure_ip_id(__u32 daddr) #ifdef CONFIG_INET -__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport) +__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) { struct timeval tv; __u32 seq; @@ -1532,9 +1532,9 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, * Note that the words are placed into the starting vector, which is * then mixed with a partial MD4 over random data. */ - hash[0]=saddr; - hash[1]=daddr; - hash[2]=(sport << 16) + dport; + hash[0]=(__force u32)saddr; + hash[1]=(__force u32)daddr; + hash[2]=((__force u16)sport << 16) + (__force u16)dport; hash[3]=keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; @@ -1559,7 +1559,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, EXPORT_SYMBOL(secure_tcp_sequence_number); /* Generate secure starting point for ephemeral IPV4 transport port search */ -u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) +u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[4]; @@ -1568,25 +1568,25 @@ u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) * Pick a unique starting offset for each ephemeral port search * (saddr, daddr, dport) and 48bits of random data. */ - hash[0] = saddr; - hash[1] = daddr; - hash[2] = dport ^ keyptr->secret[10]; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = (__force u32)dport ^ keyptr->secret[10]; hash[3] = keyptr->secret[11]; return half_md4_transform(hash, keyptr->secret); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dport) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[12]; memcpy(hash, saddr, 16); - hash[4] = dport; + hash[4] = (__force u32)dport; memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); - return twothirdsMD4Transform(daddr, hash); + return twothirdsMD4Transform((const __u32 *)daddr, hash); } #endif @@ -1595,17 +1595,17 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo * bit's 32-47 increase every key exchange * 0-31 hash(source, dest) */ -u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport) +u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) { struct timeval tv; u64 seq; __u32 hash[4]; struct keydata *keyptr = get_keyptr(); - hash[0] = saddr; - hash[1] = daddr; - hash[2] = (sport << 16) + dport; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; hash[3] = keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret); @@ -1641,7 +1641,7 @@ unsigned int get_random_int(void) * drain on it), and uses halfMD4Transform within the second. We * also mix it with jiffies and the PID: */ - return secure_ip_id(current->pid + jiffies); + return secure_ip_id((__force __be32)(current->pid + jiffies)); } /* diff --git a/include/linux/random.h b/include/linux/random.h index 0248b30e306d..01ad71033d65 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -51,16 +51,16 @@ extern void add_interrupt_randomness(int irq); extern void get_random_bytes(void *buf, int nbytes); void generate_random_uuid(unsigned char uuid_out[16]); -extern __u32 secure_ip_id(__u32 daddr); -extern u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport); -extern u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, - __u16 dport); -extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport); -extern __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, - __u16 sport, __u16 dport); -extern u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport); +extern __u32 secure_ip_id(__be32 daddr); +extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); +extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, + __be16 dport); +extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport); +extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, + __be16 sport, __be16 dport); +extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport); #ifndef MODULE extern struct file_operations random_fops, urandom_fops; -- cgit v1.2.3-71-gd317 From 42d224aa170a4f7446cea6c972d9302d524545e5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:11:08 -0800 Subject: [NETFILTER]: More trivial annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack_tftp.h | 2 +- net/ipv4/netfilter/ip_conntrack_amanda.c | 2 +- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h index cde9729aa173..a404fc0abf0e 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h @@ -4,7 +4,7 @@ #define TFTP_PORT 69 struct tftphdr { - u_int16_t opcode; + __be16 opcode; }; #define TFTP_OPCODE_READ 1 diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 6c7383a8e42b..7fca246615d5 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -180,7 +180,7 @@ static struct ip_conntrack_helper amanda_helper = { .help = help, .name = "amanda", - .tuple = { .src = { .u = { __constant_htons(10080) } }, + .tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } }, .dst = { .protonum = IPPROTO_UDP }, }, .mask = { .src = { .u = { 0xFFFF } }, diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 6cb9070cd0bc..a06b340ea414 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -1153,7 +1153,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_q931 = { .me = THIS_MODULE, .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ , .timeout = 240, - .tuple = {.src = {.u = {__constant_htons(Q931_PORT)}}, + .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}}, .dst = {.protonum = IPPROTO_TCP}}, .mask = {.src = {.u = {0xFFFF}}, .dst = {.protonum = 0xFF}}, @@ -1746,7 +1746,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_ras = { .me = THIS_MODULE, .max_expected = 32, .timeout = 240, - .tuple = {.src = {.u = {__constant_htons(RAS_PORT)}}, + .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}}, .dst = {.protonum = IPPROTO_UDP}}, .mask = {.src = {.u = {0xFFFE}}, .dst = {.protonum = 0xFF}}, -- cgit v1.2.3-71-gd317 From 30d492da738a8d5f4ec884b3e1a13eef97714994 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:11:29 -0800 Subject: [ATM]: Annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/atmarp.h | 2 +- include/linux/atmbr2684.h | 4 ++-- include/linux/atmmpc.h | 16 ++++++++-------- include/net/atmclip.h | 2 +- net/atm/br2684.c | 2 +- net/atm/clip.c | 10 +++++----- net/atm/lec.c | 6 +++--- net/atm/lec.h | 6 +++--- net/atm/mpc.c | 26 +++++++++++++------------- net/atm/mpc.h | 6 +++--- net/atm/mpoa_caches.c | 14 +++++++------- net/atm/mpoa_caches.h | 16 ++++++++-------- net/atm/mpoa_proc.c | 6 +++--- 13 files changed, 58 insertions(+), 58 deletions(-) (limited to 'include/linux') diff --git a/include/linux/atmarp.h b/include/linux/atmarp.h index 24f82338f59a..ee108f9e9cb7 100644 --- a/include/linux/atmarp.h +++ b/include/linux/atmarp.h @@ -37,7 +37,7 @@ enum atmarp_ctrl_type { struct atmarp_ctrl { enum atmarp_ctrl_type type; /* message type */ int itf_num;/* interface number (if present) */ - uint32_t ip; /* IP address (act_need only) */ + __be32 ip; /* IP address (act_need only) */ }; #endif diff --git a/include/linux/atmbr2684.h b/include/linux/atmbr2684.h index 7981b733f1ef..969fb6c9e1cc 100644 --- a/include/linux/atmbr2684.h +++ b/include/linux/atmbr2684.h @@ -86,8 +86,8 @@ struct atm_backend_br2684 { * efficient per-if in/out filters, this support will be removed */ struct br2684_filter { - __u32 prefix; /* network byte order */ - __u32 netmask; /* 0 = disable filter */ + __be32 prefix; /* network byte order */ + __be32 netmask; /* 0 = disable filter */ }; struct br2684_filter_set { diff --git a/include/linux/atmmpc.h b/include/linux/atmmpc.h index 5fbfa68136d3..ea1650425a12 100644 --- a/include/linux/atmmpc.h +++ b/include/linux/atmmpc.h @@ -13,7 +13,7 @@ struct atmmpc_ioc { int dev_num; - uint32_t ipaddr; /* the IP address of the shortcut */ + __be32 ipaddr; /* the IP address of the shortcut */ int type; /* ingress or egress */ }; @@ -21,8 +21,8 @@ typedef struct in_ctrl_info { uint8_t Last_NHRP_CIE_code; uint8_t Last_Q2931_cause_value; uint8_t eg_MPC_ATM_addr[ATM_ESA_LEN]; - uint32_t tag; - uint32_t in_dst_ip; /* IP address this ingress MPC sends packets to */ + __be32 tag; + __be32 in_dst_ip; /* IP address this ingress MPC sends packets to */ uint16_t holding_time; uint32_t request_id; } in_ctrl_info; @@ -30,10 +30,10 @@ typedef struct in_ctrl_info { typedef struct eg_ctrl_info { uint8_t DLL_header[256]; uint8_t DH_length; - uint32_t cache_id; - uint32_t tag; - uint32_t mps_ip; - uint32_t eg_dst_ip; /* IP address to which ingress MPC sends packets */ + __be32 cache_id; + __be32 tag; + __be32 mps_ip; + __be32 eg_dst_ip; /* IP address to which ingress MPC sends packets */ uint8_t in_MPC_data_ATM_addr[ATM_ESA_LEN]; uint16_t holding_time; } eg_ctrl_info; @@ -49,7 +49,7 @@ struct mpc_parameters { struct k_message { uint16_t type; - uint32_t ip_mask; + __be32 ip_mask; uint8_t MPS_ctrl[ATM_ESA_LEN]; union { in_ctrl_info in_info; diff --git a/include/net/atmclip.h b/include/net/atmclip.h index 90fcc98e676f..b5a51a7bb364 100644 --- a/include/net/atmclip.h +++ b/include/net/atmclip.h @@ -36,7 +36,7 @@ struct clip_vcc { struct atmarp_entry { - u32 ip; /* IP address */ + __be32 ip; /* IP address */ struct clip_vcc *vccs; /* active VCCs; NULL if resolution is pending */ unsigned long expires; /* entry expiration time */ diff --git a/net/atm/br2684.c b/net/atm/br2684.c index d00cca97eb33..b04162f10d85 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -372,7 +372,7 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, void __user *arg) /* Returns 1 if packet should be dropped */ static inline int -packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) +packet_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) { if (brvcc->filter.netmask == 0) return 0; /* no filter in place */ diff --git a/net/atm/clip.c b/net/atm/clip.c index 7af2c411da82..1c416934b7c1 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -54,7 +54,7 @@ static struct atm_vcc *atmarpd; static struct neigh_table clip_tbl; static struct timer_list idle_timer; -static int to_atmarpd(enum atmarp_ctrl_type type, int itf, unsigned long ip) +static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) { struct sock *sk; struct atmarp_ctrl *ctrl; @@ -220,7 +220,7 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb) || memcmp(skb->data, llc_oui, sizeof (llc_oui))) skb->protocol = htons(ETH_P_IP); else { - skb->protocol = ((u16 *) skb->data)[3]; + skb->protocol = ((__be16 *) skb->data)[3]; skb_pull(skb, RFC1483LLC_LEN); if (skb->protocol == htons(ETH_P_ARP)) { PRIV(skb->dev)->stats.rx_packets++; @@ -430,7 +430,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) here = skb_push(skb, RFC1483LLC_LEN); memcpy(here, llc_oui, sizeof(llc_oui)); - ((u16 *) here)[3] = skb->protocol; + ((__be16 *) here)[3] = skb->protocol; } atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = vcc->atm_options; @@ -509,7 +509,7 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout) return 0; } -static int clip_setentry(struct atm_vcc *vcc, u32 ip) +static int clip_setentry(struct atm_vcc *vcc, __be32 ip) { struct neighbour *neigh; struct atmarp_entry *entry; @@ -752,7 +752,7 @@ static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) err = clip_mkip(vcc, arg); break; case ATMARP_SETENTRY: - err = clip_setentry(vcc, arg); + err = clip_setentry(vcc, (__force __be32)arg); break; case ATMARP_ENCAP: err = clip_encap(vcc, arg); diff --git a/net/atm/lec.c b/net/atm/lec.c index 66c57c1091a8..9f5f931743bd 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -204,9 +204,9 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc) memset(rdesc, 0, ETH_ALEN); /* offset 4 comes from LAN destination field in LE control frames */ if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT)) - memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(uint16_t)); + memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(__be16)); else { - memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t)); + memcpy(&rdesc[4], &trh->rseg[1], sizeof(__be16)); rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0)); } @@ -775,7 +775,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) unsigned char *src, *dst; atm_return(vcc, skb->truesize); - if (*(uint16_t *) skb->data == htons(priv->lecid) || + if (*(__be16 *) skb->data == htons(priv->lecid) || !priv->lecd || !(dev->flags & IFF_UP)) { /* * Probably looping back, or if lecd is missing, diff --git a/net/atm/lec.h b/net/atm/lec.h index 877f50939696..24cc95f86741 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -14,14 +14,14 @@ #define LEC_HEADER_LEN 16 struct lecdatahdr_8023 { - unsigned short le_header; + __be16 le_header; unsigned char h_dest[ETH_ALEN]; unsigned char h_source[ETH_ALEN]; - unsigned short h_type; + __be16 h_type; }; struct lecdatahdr_8025 { - unsigned short le_header; + __be16 le_header; unsigned char ac_pad; unsigned char fc; unsigned char h_dest[ETH_ALEN]; diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 0d2b994af511..f15f5d847860 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -152,7 +152,7 @@ static struct mpoa_client *find_mpc_by_lec(struct net_device *dev) /* * Overwrites the old entry or makes a new one. */ -struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos) +struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos) { struct atm_mpoa_qos *entry; @@ -177,7 +177,7 @@ struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos) return entry; } -struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip) +struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip) { struct atm_mpoa_qos *qos; @@ -460,11 +460,11 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) in_cache_entry *entry; struct iphdr *iph; char *buff; - uint32_t ipaddr = 0; + __be32 ipaddr = 0; static struct { struct llc_snap_hdr hdr; - uint32_t tag; + __be32 tag; } tagged_llc_snap_hdr = { {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}}, 0 @@ -559,7 +559,7 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg) struct mpoa_client *mpc; struct atmmpc_ioc ioc_data; in_cache_entry *in_entry; - uint32_t ipaddr; + __be32 ipaddr; bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc)); if (bytes_left != 0) { @@ -638,7 +638,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) struct sk_buff *new_skb; eg_cache_entry *eg; struct mpoa_client *mpc; - uint32_t tag; + __be32 tag; char *tmp; ddprintk("mpoa: (%s) mpc_push:\n", dev->name); @@ -683,7 +683,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) } tmp = skb->data + sizeof(struct llc_snap_hdr); - tag = *(uint32_t *)tmp; + tag = *(__be32 *)tmp; eg = mpc->eg_ops->get_by_tag(tag, mpc); if (eg == NULL) { @@ -1029,7 +1029,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; + __be32 dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry; entry = mpc->in_ops->get(dst_ip, mpc); @@ -1066,7 +1066,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) */ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; + __be32 dst_ip = msg->content.in_info.in_dst_ip; struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip); eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client); @@ -1102,7 +1102,7 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; + __be32 dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip)); @@ -1148,8 +1148,8 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t dst_ip = msg->content.in_info.in_dst_ip; - uint32_t mask = msg->ip_mask; + __be32 dst_ip = msg->content.in_info.in_dst_ip; + __be32 mask = msg->ip_mask; in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); if(entry == NULL){ @@ -1173,7 +1173,7 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) { - uint32_t cache_id = msg->content.eg_info.cache_id; + __be32 cache_id = msg->content.eg_info.cache_id; eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc); if (entry == NULL) { diff --git a/net/atm/mpc.h b/net/atm/mpc.h index 3c7981a229e8..51f460d005c3 100644 --- a/net/atm/mpc.h +++ b/net/atm/mpc.h @@ -36,14 +36,14 @@ struct mpoa_client { struct atm_mpoa_qos { struct atm_mpoa_qos *next; - uint32_t ipaddr; + __be32 ipaddr; struct atm_qos qos; }; /* MPOA QoS operations */ -struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos); -struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip); +struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos); +struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip); int atm_mpoa_delete_qos(struct atm_mpoa_qos *qos); /* Display QoS entries. This is for the procfs */ diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index fbf13cdcf46e..f3b99b38c91b 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -22,7 +22,7 @@ #define ddprintk(format,args...) #endif -static in_cache_entry *in_cache_get(uint32_t dst_ip, +static in_cache_entry *in_cache_get(__be32 dst_ip, struct mpoa_client *client) { in_cache_entry *entry; @@ -42,9 +42,9 @@ static in_cache_entry *in_cache_get(uint32_t dst_ip, return NULL; } -static in_cache_entry *in_cache_get_with_mask(uint32_t dst_ip, +static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip, struct mpoa_client *client, - uint32_t mask) + __be32 mask) { in_cache_entry *entry; @@ -84,7 +84,7 @@ static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc, return NULL; } -static in_cache_entry *in_cache_add_entry(uint32_t dst_ip, +static in_cache_entry *in_cache_add_entry(__be32 dst_ip, struct mpoa_client *client) { in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL); @@ -319,7 +319,7 @@ static void in_destroy_cache(struct mpoa_client *mpc) return; } -static eg_cache_entry *eg_cache_get_by_cache_id(uint32_t cache_id, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc) { eg_cache_entry *entry; @@ -339,7 +339,7 @@ static eg_cache_entry *eg_cache_get_by_cache_id(uint32_t cache_id, struct mpoa_c } /* This can be called from any context since it saves CPU flags */ -static eg_cache_entry *eg_cache_get_by_tag(uint32_t tag, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) { unsigned long flags; eg_cache_entry *entry; @@ -380,7 +380,7 @@ static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_clie return NULL; } -static eg_cache_entry *eg_cache_get_by_src_ip(uint32_t ipaddr, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc) { eg_cache_entry *entry; diff --git a/net/atm/mpoa_caches.h b/net/atm/mpoa_caches.h index 6c9886a03d0b..84de977def2e 100644 --- a/net/atm/mpoa_caches.h +++ b/net/atm/mpoa_caches.h @@ -29,12 +29,12 @@ typedef struct in_cache_entry { } in_cache_entry; struct in_cache_ops{ - in_cache_entry *(*add_entry)(uint32_t dst_ip, + in_cache_entry *(*add_entry)(__be32 dst_ip, struct mpoa_client *client); - in_cache_entry *(*get)(uint32_t dst_ip, struct mpoa_client *client); - in_cache_entry *(*get_with_mask)(uint32_t dst_ip, + in_cache_entry *(*get)(__be32 dst_ip, struct mpoa_client *client); + in_cache_entry *(*get_with_mask)(__be32 dst_ip, struct mpoa_client *client, - uint32_t mask); + __be32 mask); in_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); void (*put)(in_cache_entry *entry); @@ -56,17 +56,17 @@ typedef struct eg_cache_entry{ struct atm_vcc *shortcut; uint32_t packets_rcvd; uint16_t entry_state; - uint32_t latest_ip_addr; /* The src IP address of the last packet */ + __be32 latest_ip_addr; /* The src IP address of the last packet */ struct eg_ctrl_info ctrl_info; atomic_t use; } eg_cache_entry; struct eg_cache_ops{ eg_cache_entry *(*add_entry)(struct k_message *msg, struct mpoa_client *client); - eg_cache_entry *(*get_by_cache_id)(uint32_t cache_id, struct mpoa_client *client); - eg_cache_entry *(*get_by_tag)(uint32_t cache_id, struct mpoa_client *client); + eg_cache_entry *(*get_by_cache_id)(__be32 cache_id, struct mpoa_client *client); + eg_cache_entry *(*get_by_tag)(__be32 cache_id, struct mpoa_client *client); eg_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); - eg_cache_entry *(*get_by_src_ip)(uint32_t ipaddr, struct mpoa_client *client); + eg_cache_entry *(*get_by_src_ip)(__be32 ipaddr, struct mpoa_client *client); void (*put)(eg_cache_entry *entry); void (*remove_entry)(eg_cache_entry *entry, struct mpoa_client *client); void (*update)(eg_cache_entry *entry, uint16_t holding_time); diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c index d37b8911b3ab..3844c85d602f 100644 --- a/net/atm/mpoa_proc.c +++ b/net/atm/mpoa_proc.c @@ -231,14 +231,14 @@ static int parse_qos(const char *buff) */ unsigned char ip[4]; int tx_pcr, tx_sdu, rx_pcr, rx_sdu; - uint32_t ipaddr; + __be32 ipaddr; struct atm_qos qos; memset(&qos, 0, sizeof(struct atm_qos)); if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu", ip, ip+1, ip+2, ip+3) == 4) { - ipaddr = *(uint32_t *)ip; + ipaddr = *(__be32 *)ip; return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); } @@ -250,7 +250,7 @@ static int parse_qos(const char *buff) ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8) return 0; - ipaddr = *(uint32_t *)ip; + ipaddr = *(__be32 *)ip; qos.txtp.traffic_class = ATM_CBR; qos.txtp.max_pcr = tx_pcr; qos.txtp.max_sdu = tx_sdu; -- cgit v1.2.3-71-gd317 From 47c183fa5ea7feebc356da8ccbd9105a41f8e534 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:11:51 -0800 Subject: [BRIDGE]: Annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_bridge.h | 2 +- include/linux/netfilter_bridge/ebt_802_3.h | 10 +++++----- include/linux/netfilter_bridge/ebt_among.h | 2 +- include/linux/netfilter_bridge/ebt_arp.h | 14 +++++++------- include/linux/netfilter_bridge/ebt_ip.h | 8 ++++---- include/linux/netfilter_bridge/ebt_vlan.h | 2 +- include/linux/netfilter_bridge/ebtables.h | 2 +- net/bridge/br_netfilter.c | 2 +- net/bridge/netfilter/ebt_802_3.c | 2 +- net/bridge/netfilter/ebt_among.c | 22 +++++++++++----------- net/bridge/netfilter/ebt_arp.c | 6 +++--- net/bridge/netfilter/ebt_ip.c | 4 ++-- net/bridge/netfilter/ebt_log.c | 6 +++--- net/bridge/netfilter/ebt_vlan.c | 2 +- 14 files changed, 42 insertions(+), 42 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index 9a4dd11af86e..6c4613f8ad75 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -64,7 +64,7 @@ static inline int nf_bridge_pad(const struct sk_buff *skb) struct bridge_skb_cb { union { - __u32 ipv4; + __be32 ipv4; } daddr; }; diff --git a/include/linux/netfilter_bridge/ebt_802_3.h b/include/linux/netfilter_bridge/ebt_802_3.h index b9f712c14a0a..07f044ff1a6b 100644 --- a/include/linux/netfilter_bridge/ebt_802_3.h +++ b/include/linux/netfilter_bridge/ebt_802_3.h @@ -28,21 +28,21 @@ struct hdr_ui { uint8_t ssap; uint8_t ctrl; uint8_t orig[3]; - uint16_t type; + __be16 type; }; struct hdr_ni { uint8_t dsap; uint8_t ssap; - uint16_t ctrl; + __be16 ctrl; uint8_t orig[3]; - uint16_t type; + __be16 type; }; struct ebt_802_3_hdr { uint8_t daddr[6]; uint8_t saddr[6]; - uint16_t len; + __be16 len; union { struct hdr_ui ui; struct hdr_ni ni; @@ -61,7 +61,7 @@ static inline struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb) struct ebt_802_3_info { uint8_t sap; - uint16_t type; + __be16 type; uint8_t bitmask; uint8_t invflags; }; diff --git a/include/linux/netfilter_bridge/ebt_among.h b/include/linux/netfilter_bridge/ebt_among.h index 307c1fed8511..7654069233ca 100644 --- a/include/linux/netfilter_bridge/ebt_among.h +++ b/include/linux/netfilter_bridge/ebt_among.h @@ -32,7 +32,7 @@ struct ebt_mac_wormhash_tuple { uint32_t cmp[2]; - uint32_t ip; + __be32 ip; }; struct ebt_mac_wormhash diff --git a/include/linux/netfilter_bridge/ebt_arp.h b/include/linux/netfilter_bridge/ebt_arp.h index 537ec6b487a2..97e4dbde1f89 100644 --- a/include/linux/netfilter_bridge/ebt_arp.h +++ b/include/linux/netfilter_bridge/ebt_arp.h @@ -14,13 +14,13 @@ struct ebt_arp_info { - uint16_t htype; - uint16_t ptype; - uint16_t opcode; - uint32_t saddr; - uint32_t smsk; - uint32_t daddr; - uint32_t dmsk; + __be16 htype; + __be16 ptype; + __be16 opcode; + __be32 saddr; + __be32 smsk; + __be32 daddr; + __be32 dmsk; unsigned char smaddr[ETH_ALEN]; unsigned char smmsk[ETH_ALEN]; unsigned char dmaddr[ETH_ALEN]; diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h index 7247385cdcb1..d6847475bf2e 100644 --- a/include/linux/netfilter_bridge/ebt_ip.h +++ b/include/linux/netfilter_bridge/ebt_ip.h @@ -28,10 +28,10 @@ /* the same values are used for the invflags */ struct ebt_ip_info { - uint32_t saddr; - uint32_t daddr; - uint32_t smsk; - uint32_t dmsk; + __be32 saddr; + __be32 daddr; + __be32 smsk; + __be32 dmsk; uint8_t tos; uint8_t protocol; uint8_t bitmask; diff --git a/include/linux/netfilter_bridge/ebt_vlan.h b/include/linux/netfilter_bridge/ebt_vlan.h index cb1fcc41565f..1d98be4031e7 100644 --- a/include/linux/netfilter_bridge/ebt_vlan.h +++ b/include/linux/netfilter_bridge/ebt_vlan.h @@ -10,7 +10,7 @@ struct ebt_vlan_info { uint16_t id; /* VLAN ID {1-4095} */ uint8_t prio; /* VLAN User Priority {0-7} */ - uint16_t encap; /* VLAN Encapsulated frame code {0-65535} */ + __be16 encap; /* VLAN Encapsulated frame code {0-65535} */ uint8_t bitmask; /* Args bitmask bit 1=1 - ID arg, bit 2=1 User-Priority arg, bit 3=1 encap*/ uint8_t invflags; /* Inverse bitmask bit 1=1 - inversed ID arg, diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index b1a7cc90877b..e6ea70de24d5 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -141,7 +141,7 @@ struct ebt_entry { /* this needs to be the first field */ unsigned int bitmask; unsigned int invflags; - uint16_t ethproto; + __be16 ethproto; /* the physical in-dev */ char in[IFNAMSIZ]; /* the logical in-dev */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index ac181be13d83..2a5d31b1a196 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -381,7 +381,7 @@ static int check_hbh_len(struct sk_buff *skb) case IPV6_TLV_JUMBO: if (skb->nh.raw[off + 1] != 4 || (off & 3) != 2) goto bad; - pkt_len = ntohl(*(u32 *) (skb->nh.raw + off + 2)); + pkt_len = ntohl(*(__be32 *) (skb->nh.raw + off + 2)); if (pkt_len <= IPV6_MAXPLEN || skb->nh.ipv6h->payload_len) goto bad; diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c index d42f63f5e9f8..9abbc09ccdc3 100644 --- a/net/bridge/netfilter/ebt_802_3.c +++ b/net/bridge/netfilter/ebt_802_3.c @@ -17,7 +17,7 @@ static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device * { struct ebt_802_3_info *info = (struct ebt_802_3_info *)data; struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb); - uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; + __be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; if (info->bitmask & EBT_802_3_SAP) { if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c index a614485828af..ce97c4285f9a 100644 --- a/net/bridge/netfilter/ebt_among.c +++ b/net/bridge/netfilter/ebt_among.c @@ -15,7 +15,7 @@ #include static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh, - const char *mac, uint32_t ip) + const char *mac, __be32 ip) { /* You may be puzzled as to how this code works. * Some tricks were used, refer to @@ -70,7 +70,7 @@ static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash return 0; } -static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr) +static int get_ip_dst(const struct sk_buff *skb, __be32 *addr) { if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { struct iphdr _iph, *ih; @@ -81,16 +81,16 @@ static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr) *addr = ih->daddr; } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { struct arphdr _arph, *ah; - uint32_t buf, *bp; + __be32 buf, *bp; ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); if (ah == NULL || - ah->ar_pln != sizeof(uint32_t) || + ah->ar_pln != sizeof(__be32) || ah->ar_hln != ETH_ALEN) return -1; bp = skb_header_pointer(skb, sizeof(struct arphdr) + - 2 * ETH_ALEN + sizeof(uint32_t), - sizeof(uint32_t), &buf); + 2 * ETH_ALEN + sizeof(__be32), + sizeof(__be32), &buf); if (bp == NULL) return -1; *addr = *bp; @@ -98,7 +98,7 @@ static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr) return 0; } -static int get_ip_src(const struct sk_buff *skb, uint32_t *addr) +static int get_ip_src(const struct sk_buff *skb, __be32 *addr) { if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { struct iphdr _iph, *ih; @@ -109,15 +109,15 @@ static int get_ip_src(const struct sk_buff *skb, uint32_t *addr) *addr = ih->saddr; } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { struct arphdr _arph, *ah; - uint32_t buf, *bp; + __be32 buf, *bp; ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); if (ah == NULL || - ah->ar_pln != sizeof(uint32_t) || + ah->ar_pln != sizeof(__be32) || ah->ar_hln != ETH_ALEN) return -1; bp = skb_header_pointer(skb, sizeof(struct arphdr) + - ETH_ALEN, sizeof(uint32_t), &buf); + ETH_ALEN, sizeof(__be32), &buf); if (bp == NULL) return -1; *addr = *bp; @@ -133,7 +133,7 @@ static int ebt_filter_among(const struct sk_buff *skb, struct ebt_among_info *info = (struct ebt_among_info *) data; const char *dmac, *smac; const struct ebt_mac_wormhash *wh_dst, *wh_src; - uint32_t dip = 0, sip = 0; + __be32 dip = 0, sip = 0; wh_dst = ebt_among_wh_dst(info); wh_src = ebt_among_wh_src(info); diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index a6c81d9f73b8..9c599800a900 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c @@ -35,10 +35,10 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in return EBT_NOMATCH; if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) { - uint32_t _addr, *ap; + __be32 _addr, *ap; /* IPv4 addresses are always 4 bytes */ - if (ah->ar_pln != sizeof(uint32_t)) + if (ah->ar_pln != sizeof(__be32)) return EBT_NOMATCH; if (info->bitmask & EBT_ARP_SRC_IP) { ap = skb_header_pointer(skb, sizeof(struct arphdr) + @@ -53,7 +53,7 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in if (info->bitmask & EBT_ARP_DST_IP) { ap = skb_header_pointer(skb, sizeof(struct arphdr) + - 2*ah->ar_hln+sizeof(uint32_t), + 2*ah->ar_hln+sizeof(__be32), sizeof(_addr), &_addr); if (ap == NULL) return EBT_NOMATCH; diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c index 65b665ce57b5..e4c642448e1b 100644 --- a/net/bridge/netfilter/ebt_ip.c +++ b/net/bridge/netfilter/ebt_ip.c @@ -20,8 +20,8 @@ #include struct tcpudphdr { - uint16_t src; - uint16_t dst; + __be16 src; + __be16 dst; }; static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 466ed3440b74..a184f879f253 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -38,8 +38,8 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask, struct tcpudphdr { - uint16_t src; - uint16_t dst; + __be16 src; + __be16 dst; }; struct arppayload @@ -130,7 +130,7 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum, * then log the ARP payload */ if (ah->ar_hrd == htons(1) && ah->ar_hln == ETH_ALEN && - ah->ar_pln == sizeof(uint32_t)) { + ah->ar_pln == sizeof(__be32)) { struct arppayload _arpp, *ap; ap = skb_header_pointer(skb, sizeof(_arph), diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c index a2b452862b73..7ee377622964 100644 --- a/net/bridge/netfilter/ebt_vlan.c +++ b/net/bridge/netfilter/ebt_vlan.c @@ -55,7 +55,7 @@ ebt_filter_vlan(const struct sk_buff *skb, unsigned short id; /* VLAN ID, given from frame TCI */ unsigned char prio; /* user_priority, given from frame TCI */ /* VLAN encapsulated Type/Length field, given from orig frame */ - unsigned short encap; + __be16 encap; fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame); if (fp == NULL) -- cgit v1.2.3-71-gd317 From a64b78a077a71c9b9c0c1b0be699083379783c3d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:12:29 -0800 Subject: [NET]: Annotate net_srandom(). Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/net.h b/include/linux/net.h index 15c733b816f0..6f0dfeba509a 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -196,7 +196,7 @@ extern struct socket *sockfd_lookup(int fd, int *err); extern int net_ratelimit(void); #define net_random() random32() -#define net_srandom(seed) srandom32(seed) +#define net_srandom(seed) srandom32((__force u32)seed) extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t len); -- cgit v1.2.3-71-gd317 From 2bc357987a6510e61d33f3b20fa989fb2b6a10b8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:14:18 -0800 Subject: [NET]: Introduce types for checksums. New types - for 16bit checksums and "unfolded" 32bit variant. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/types.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/types.h b/include/linux/types.h index 9f11fdd2bd72..745c409ebbb5 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -182,6 +182,8 @@ typedef __u32 __bitwise __be32; typedef __u64 __bitwise __le64; typedef __u64 __bitwise __be64; #endif +typedef __u16 __bitwise __sum16; +typedef __u32 __bitwise __wsum; #ifdef __KERNEL__ typedef unsigned __bitwise__ gfp_t; -- cgit v1.2.3-71-gd317 From 9981a0e36a572e9fcf84bfab915fdc93bed0e3c9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:24:30 -0800 Subject: [NET]: Annotate checksums in on-the-wire packets. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/dccp.h | 2 +- include/linux/icmp.h | 2 +- include/linux/icmpv6.h | 2 +- include/linux/igmp.h | 2 +- include/linux/ip.h | 2 +- include/linux/tcp.h | 2 +- include/linux/udp.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index d308f1228b61..72cc355d7a03 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -30,7 +30,7 @@ struct dccp_hdr { #else #error "Adjust your defines" #endif - __u16 dccph_checksum; + __sum16 dccph_checksum; #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 dccph_x:1, dccph_type:4, diff --git a/include/linux/icmp.h b/include/linux/icmp.h index 878cfe4e587f..24da4fbc1a2f 100644 --- a/include/linux/icmp.h +++ b/include/linux/icmp.h @@ -68,7 +68,7 @@ struct icmphdr { __u8 type; __u8 code; - __be16 checksum; + __sum16 checksum; union { struct { __be16 id; diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index dc79396aac25..68d3526c3a05 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -7,7 +7,7 @@ struct icmp6hdr { __u8 icmp6_type; __u8 icmp6_code; - __be16 icmp6_cksum; + __sum16 icmp6_cksum; union { diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 21dd56905271..6e7ea2f0a57c 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -30,7 +30,7 @@ struct igmphdr { __u8 type; __u8 code; /* For newer IGMP */ - __be16 csum; + __sum16 csum; __be32 group; }; diff --git a/include/linux/ip.h b/include/linux/ip.h index ecee9bb27d0e..1d36b971a8b5 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -98,7 +98,7 @@ struct iphdr { __be16 frag_off; __u8 ttl; __u8 protocol; - __be16 check; + __sum16 check; __be32 saddr; __be32 daddr; /*The options start here. */ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0aecfc955591..dd61b172ac68 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -52,7 +52,7 @@ struct tcphdr { #error "Adjust your defines" #endif __be16 window; - __be16 check; + __sum16 check; __be16 urg_ptr; }; diff --git a/include/linux/udp.h b/include/linux/udp.h index 564f3b050105..7e08c07efe0f 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -23,7 +23,7 @@ struct udphdr { __be16 source; __be16 dest; __be16 len; - __be16 check; + __sum16 check; }; /* UDP socket options */ -- cgit v1.2.3-71-gd317 From 44bb93633f57a55979f3c2589b10fd6a2bfc7c08 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:36:14 -0800 Subject: [NET]: Annotate csum_partial() callers in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/socket.h | 2 +- include/linux/sunrpc/xdr.h | 2 +- net/core/iovec.c | 4 ++-- net/core/skbuff.c | 2 +- net/ipv4/ip_output.c | 8 ++++---- net/unix/af_unix.c | 3 ++- 6 files changed, 11 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/socket.h b/include/linux/socket.h index 592b66679823..92cd38efad7f 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -293,7 +293,7 @@ extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, extern int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, - unsigned int len, int *csump); + unsigned int len, __wsum *csump); extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index ac69e5511606..9a527c364394 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -151,7 +151,7 @@ typedef struct { struct sk_buff *skb; unsigned int offset; size_t count; - unsigned int csum; + __wsum csum; } skb_reader_t; typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); diff --git a/net/core/iovec.c b/net/core/iovec.c index 65e4b56fbc77..04b249c40b5b 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -158,9 +158,9 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, * call to this function will be unaligned also. */ int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, - int offset, unsigned int len, int *csump) + int offset, unsigned int len, __wsum *csump) { - int csum = *csump; + __wsum csum = *csump; int partial_cnt = 0, err = 0; /* Skip over the finished iovecs */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index dfa02cc8d687..c0e3427057fc 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1265,7 +1265,7 @@ unsigned int skb_checksum(const struct sk_buff *skb, int offset, end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end - offset) > 0) { - unsigned int csum2; + __wsum csum2; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 5f3e35c03637..f9194f7e39d3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -682,7 +682,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk if (memcpy_fromiovecend(to, iov, offset, len) < 0) return -EFAULT; } else { - unsigned int csum = 0; + __wsum csum = 0; if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) return -EFAULT; skb->csum = csum_block_add(skb->csum, csum, odd); @@ -690,11 +690,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk return 0; } -static inline unsigned int +static inline __wsum csum_page(struct page *page, int offset, int copy) { char *kaddr; - unsigned int csum; + __wsum csum; kaddr = kmap(page); csum = csum_partial(kaddr + offset, copy, 0); kunmap(page); @@ -1166,7 +1166,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, } if (skb->ip_summed == CHECKSUM_NONE) { - unsigned int csum; + __wsum csum; csum = csum_page(page, offset, len); skb->csum = csum_block_add(skb->csum, csum, skb->len); } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b43a27828df5..2f208c7f4d43 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -151,8 +151,9 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) * each socket state is protected by separate rwlock. */ -static inline unsigned unix_hash_fold(unsigned hash) +static inline unsigned unix_hash_fold(__wsum n) { + unsigned hash = (__force unsigned)n; hash ^= hash>>16; hash ^= hash>>8; return hash&(UNIX_HASH_SIZE-1); -- cgit v1.2.3-71-gd317 From 5084205faf45384fff25c4cf77dd5c96279283ad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:36:34 -0800 Subject: [NET]: Annotate callers of csum_partial_copy_...() and csum_and_copy...() in net/* Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 3 +-- include/net/sock.h | 2 +- net/core/datagram.c | 6 +++--- net/core/skbuff.c | 2 +- net/ipv4/ip_output.c | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e3ae544b3956..64fa7f4c702d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1199,8 +1199,7 @@ static inline int skb_add_data(struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_NONE) { int err = 0; - unsigned int csum = csum_and_copy_from_user(from, - skb_put(skb, copy), + __wsum csum = csum_and_copy_from_user(from, skb_put(skb, copy), copy, 0, &err); if (!err) { skb->csum = csum_block_add(skb->csum, csum, off); diff --git a/include/net/sock.h b/include/net/sock.h index 35ffbdd35d3e..dc4b92b8abea 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1088,7 +1088,7 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from, { if (skb->ip_summed == CHECKSUM_NONE) { int err = 0; - unsigned int csum = csum_and_copy_from_user(from, + __wsum csum = csum_and_copy_from_user(from, page_address(page) + off, copy, 0, &err); if (err) diff --git a/net/core/datagram.c b/net/core/datagram.c index e5a05a046fef..0d9c9bac4006 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -321,7 +321,7 @@ fault: static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 __user *to, int len, - unsigned int *csump) + __wsum *csump) { int start = skb_headlen(skb); int pos = 0; @@ -350,7 +350,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end - offset) > 0) { - unsigned int csum2; + __wsum csum2; int err = 0; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -386,7 +386,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, end = start + list->len; if ((copy = end - offset) > 0) { - unsigned int csum2 = 0; + __wsum csum2 = 0; if (copy > len) copy = len; if (skb_copy_and_csum_datagram(list, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c0e3427057fc..da6683f4b31d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1342,7 +1342,7 @@ unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end - offset) > 0) { - unsigned int csum2; + __wsum csum2; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f9194f7e39d3..1da3d32f8289 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1314,7 +1314,7 @@ void ip_flush_pending_frames(struct sock *sk) static int ip_reply_glue_bits(void *dptr, char *to, int offset, int len, int odd, struct sk_buff *skb) { - unsigned int csum; + __wsum csum; csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0); skb->csum = csum_block_add(skb->csum, csum, odd); -- cgit v1.2.3-71-gd317 From 2bbbc86890ac4c911c5057f69af93853e52a42a8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:37:14 -0800 Subject: [NET]: Annotate skb_checksum() and callers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- net/core/skbuff.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 64fa7f4c702d..784129fb61d4 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1334,8 +1334,8 @@ extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); extern void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); -extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, - int len, unsigned int csum); +extern __wsum skb_checksum(const struct sk_buff *skb, int offset, + int len, __wsum csum); extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); extern int skb_store_bits(const struct sk_buff *skb, int offset, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6e8c15b39eb8..be9b541f536f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1240,8 +1240,8 @@ EXPORT_SYMBOL(skb_store_bits); /* Checksum skb data. */ -unsigned int skb_checksum(const struct sk_buff *skb, int offset, - int len, unsigned int csum) +__wsum skb_checksum(const struct sk_buff *skb, int offset, + int len, __wsum csum) { int start = skb_headlen(skb); int i, copy = start - offset; -- cgit v1.2.3-71-gd317 From 81d77662763ae527ba3a9b9275467901aaab7dfd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:37:33 -0800 Subject: [NET]: Annotate skb_copy_and_csum_bits() and callers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- net/core/skbuff.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 784129fb61d4..874ca029fbb9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1340,9 +1340,9 @@ extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); extern int skb_store_bits(const struct sk_buff *skb, int offset, void *from, int len); -extern unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, +extern __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, - unsigned int csum); + __wsum csum); extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); extern void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index be9b541f536f..07c25d601922 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1315,8 +1315,8 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, /* Both of above in one bottle. */ -unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, - u8 *to, int len, unsigned int csum) +__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, + u8 *to, int len, __wsum csum) { int start = skb_headlen(skb); int i, copy = start - offset; @@ -1368,7 +1368,7 @@ unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, struct sk_buff *list = skb_shinfo(skb)->frag_list; for (; list; list = list->next) { - unsigned int csum2; + __wsum csum2; int end; BUG_TRAP(start <= offset + len); -- cgit v1.2.3-71-gd317 From b51655b958dfb1176bfcf99466231fdbef8751ff Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:40:42 -0800 Subject: [NET]: Annotate __skb_checksum_complete() and friends. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter.h | 6 +++--- include/linux/netfilter_ipv4.h | 2 +- include/linux/netfilter_ipv6.h | 2 +- include/linux/skbuff.h | 2 +- include/net/tcp.h | 2 +- include/net/udp.h | 8 ++++---- net/core/datagram.c | 2 +- net/core/netpoll.c | 4 ++-- net/ipv4/netfilter.c | 4 ++-- net/ipv4/tcp_input.c | 4 ++-- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/netfilter.c | 4 ++-- net/ipv6/tcp_ipv6.c | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index b7e67d1d4382..707bb2e53c4e 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -290,7 +290,7 @@ extern u_int16_t nf_proto_csum_update(struct sk_buff *skb, struct nf_afinfo { unsigned short family; - unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook, + __sum16 (*checksum)(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); void (*saveroute)(const struct sk_buff *skb, struct nf_info *info); @@ -305,12 +305,12 @@ static inline struct nf_afinfo *nf_get_afinfo(unsigned short family) return rcu_dereference(nf_afinfo[family]); } -static inline unsigned int +static inline __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol, unsigned short family) { struct nf_afinfo *afinfo; - unsigned int csum = 0; + __sum16 csum = 0; rcu_read_lock(); afinfo = nf_get_afinfo(family); diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 5b63a231a76b..5821eb5a0a3e 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -79,7 +79,7 @@ enum nf_ip_hook_priorities { #ifdef __KERNEL__ extern int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type); extern int ip_xfrm_me_harder(struct sk_buff **pskb); -extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, +extern __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); #endif /*__KERNEL__*/ diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index d97e268cdfe5..ab81a6dc94ea 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -74,7 +74,7 @@ enum nf_ip6_hook_priorities { #ifdef CONFIG_NETFILTER extern int ip6_route_me_harder(struct sk_buff *skb); -extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, +extern __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); extern int ipv6_netfilter_init(void); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 874ca029fbb9..41753667541d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1398,7 +1398,7 @@ static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval * extern void __net_timestamp(struct sk_buff *skb); -extern unsigned int __skb_checksum_complete(struct sk_buff *skb); +extern __sum16 __skb_checksum_complete(struct sk_buff *skb); /** * skb_checksum_complete - Calculate checksum of an entire packet diff --git a/include/net/tcp.h b/include/net/tcp.h index 826aaecdb994..aa7989c53791 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -814,7 +814,7 @@ static inline __sum16 tcp_v4_check(struct tcphdr *th, int len, return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base); } -static inline int __tcp_checksum_complete(struct sk_buff *skb) +static inline __sum16 __tcp_checksum_complete(struct sk_buff *skb) { return __skb_checksum_complete(skb); } diff --git a/include/net/udp.h b/include/net/udp.h index 39e825a6909a..c5ccd9a3387b 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -69,15 +69,15 @@ struct sk_buff; /* * Generic checksumming routines for UDP(-Lite) v4 and v6 */ -static inline u16 __udp_lib_checksum_complete(struct sk_buff *skb) +static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) { if (! UDP_SKB_CB(skb)->partial_cov) return __skb_checksum_complete(skb); - return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov, - skb->csum)); + return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov, + skb->csum)); } -static __inline__ int udp_lib_checksum_complete(struct sk_buff *skb) +static inline __sum16 udp_lib_checksum_complete(struct sk_buff *skb) { return skb->ip_summed != CHECKSUM_UNNECESSARY && __udp_lib_checksum_complete(skb); diff --git a/net/core/datagram.c b/net/core/datagram.c index 0d9c9bac4006..797fdd4352ce 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -411,7 +411,7 @@ fault: return -EFAULT; } -unsigned int __skb_checksum_complete(struct sk_buff *skb) +__sum16 __skb_checksum_complete(struct sk_buff *skb) { __sum16 sum; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 26ee1791aa02..8be3681d3d80 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -77,8 +77,8 @@ static void queue_process(void *p) } } -static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, - unsigned short ulen, __be32 saddr, __be32 daddr) +static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, + unsigned short ulen, __be32 saddr, __be32 daddr) { __wsum psum; diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index b797a37c01ce..a68966059b50 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -162,11 +162,11 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, +__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol) { struct iphdr *iph = skb->nh.iph; - unsigned int csum = 0; + __sum16 csum = 0; switch (skb->ip_summed) { case CHECKSUM_COMPLETE: diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6ab3423674bb..9304034c0c47 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3790,9 +3790,9 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) return err; } -static int __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) +static __sum16 __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) { - int result; + __sum16 result; if (sock_owned_by_user(sk)) { local_bh_enable(); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ca8dead03b0..dadf80272413 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1544,7 +1544,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -static int tcp_v4_checksum_init(struct sk_buff *skb) +static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_COMPLETE) { if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 8d1b542806c1..f6294e5bcb31 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -80,11 +80,11 @@ static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, +__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol) { struct ipv6hdr *ip6h = skb->nh.ipv6h; - unsigned int csum = 0; + __sum16 csum = 0; switch (skb->ip_summed) { case CHECKSUM_COMPLETE: diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 394bc54c5c21..147ce499f509 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1527,7 +1527,7 @@ out: return NULL; } -static int tcp_v6_checksum_init(struct sk_buff *skb) +static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_COMPLETE) { if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, -- cgit v1.2.3-71-gd317 From 43bc0ca7eadc024e9e5b935fa5e0892df4fec9eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:43:23 -0800 Subject: [NET]: netfilter checksum annotations Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter.h | 26 +++++++++++++++---- .../linux/netfilter_ipv4/ip_conntrack_proto_gre.h | 4 +-- net/ipv4/netfilter/ip_nat_core.c | 6 ++--- net/ipv4/netfilter/ip_nat_helper.c | 30 ++++++++-------------- net/ipv4/netfilter/ip_nat_proto_gre.c | 8 +++--- net/ipv4/netfilter/ip_nat_proto_icmp.c | 6 ++--- net/ipv4/netfilter/ip_nat_proto_tcp.c | 5 ++-- net/ipv4/netfilter/ip_nat_proto_udp.c | 7 ++--- net/ipv4/netfilter/ipt_ECN.c | 11 +++----- net/ipv4/netfilter/ipt_TCPMSS.c | 24 ++++++----------- net/ipv4/netfilter/ipt_TOS.c | 5 ++-- net/ipv4/netfilter/ipt_TTL.c | 5 ++-- net/netfilter/core.c | 27 ++++++++----------- 13 files changed, 70 insertions(+), 94 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 707bb2e53c4e..6ab5e2d6133e 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -282,11 +282,27 @@ extern void nf_invalidate_cache(int pf); Returns true or false. */ extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); -extern u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, - u_int32_t csum); -extern u_int16_t nf_proto_csum_update(struct sk_buff *skb, - u_int32_t oldval, u_int32_t newval, - u_int16_t csum, int pseudohdr); +static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to) +{ + __be32 diff[] = { ~from, to }; + + *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum))); +} + +static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to) +{ + nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to); +} + +extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, + __be32 from, __be32 to, int pseudohdr); + +static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb, + __be16 from, __be16 to, int pseudohdr) +{ + nf_proto_csum_replace4(sum, skb, (__force __be32)from, + (__force __be32)to, pseudohdr); +} struct nf_afinfo { unsigned short family; diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h index 1d853aa873eb..e371e0fc1672 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h @@ -102,11 +102,11 @@ static inline __be32 *gre_key(struct gre_hdr *greh) } /* get pointer ot gre csum, if present */ -static inline u_int16_t *gre_csum(struct gre_hdr *greh) +static inline __sum16 *gre_csum(struct gre_hdr *greh) { if (!greh->csum) return NULL; - return (u_int16_t *) (greh+sizeof(*greh)); + return (__sum16 *) (greh+sizeof(*greh)); } #endif /* __KERNEL__ */ diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 4b6260a97408..9d1a5175dcd4 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -362,12 +362,10 @@ manip_pkt(u_int16_t proto, iph = (void *)(*pskb)->data + iphdroff; if (maniptype == IP_NAT_MANIP_SRC) { - iph->check = nf_csum_update(~iph->saddr, target->src.ip, - iph->check); + nf_csum_replace4(&iph->check, iph->saddr, target->src.ip); iph->saddr = target->src.ip; } else { - iph->check = nf_csum_update(~iph->daddr, target->dst.ip, - iph->check); + nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip); iph->daddr = target->dst.ip; } return 1; diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 3e7fd64c2162..ee80feb4b2a9 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -188,10 +188,8 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, csum_partial((char *)tcph, datalen, 0)); } else - tcph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ htons(0xFFFF), - htons(datalen), - tcph->check, 1); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldlen), htons(datalen), 1); if (rep_len != match_len) { set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); @@ -266,10 +264,8 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, if (!udph->check) udph->check = CSUM_MANGLED_0; } else - udph->check = nf_proto_csum_update(*pskb, - htons(oldlen) ^ htons(0xFFFF), - htons(datalen), - udph->check, 1); + nf_proto_csum_replace2(&udph->check, *pskb, + htons(oldlen), htons(datalen), 1); return 1; } EXPORT_SYMBOL(ip_nat_mangle_udp_packet); @@ -307,14 +303,10 @@ sack_adjust(struct sk_buff *skb, ntohl(sack->start_seq), new_start_seq, ntohl(sack->end_seq), new_end_seq); - tcph->check = nf_proto_csum_update(skb, - ~sack->start_seq, - new_start_seq, - tcph->check, 0); - tcph->check = nf_proto_csum_update(skb, - ~sack->end_seq, - new_end_seq, - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->start_seq, new_start_seq, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->end_seq, new_end_seq, 0); sack->start_seq = new_start_seq; sack->end_seq = new_end_seq; sackoff += sizeof(*sack); @@ -397,10 +389,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb, else newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); - tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq, - tcph->check, 0); - tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack, - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index bf91f9312b3c..95810202d849 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -129,11 +129,9 @@ gre_manip_pkt(struct sk_buff **pskb, } if (greh->csum) { /* FIXME: Never tested this code... */ - *(gre_csum(greh)) = - nf_proto_csum_update(*pskb, - ~*(gre_key(greh)), - tuple->dst.u.gre.key, - *(gre_csum(greh)), 0); + nf_proto_csum_replace4(gre_csum(greh), *pskb, + *(gre_key(greh)), + tuple->dst.u.gre.key, 0); } *(gre_key(greh)) = tuple->dst.u.gre.key; break; diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c index 3f6efc13ac74..75266fe3e0fa 100644 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c @@ -66,10 +66,8 @@ icmp_manip_pkt(struct sk_buff **pskb, return 0; hdr = (struct icmphdr *)((*pskb)->data + hdroff); - hdr->checksum = nf_proto_csum_update(*pskb, - hdr->un.echo.id ^ htons(0xFFFF), - tuple->src.u.icmp.id, - hdr->checksum, 0); + nf_proto_csum_replace2(&hdr->checksum, *pskb, + hdr->un.echo.id, tuple->src.u.icmp.id, 0); hdr->un.echo.id = tuple->src.u.icmp.id; return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c index 12deb13b93b1..b586d18b3fb3 100644 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c @@ -129,9 +129,8 @@ tcp_manip_pkt(struct sk_buff **pskb, if (hdrsize < sizeof(*hdr)) return 1; - hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1); - hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport, - hdr->check, 0); + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index 82f8a6ab07ec..5ced0877b32f 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c @@ -115,11 +115,8 @@ udp_manip_pkt(struct sk_buff **pskb, } if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { - hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, - hdr->check, 1); - hdr->check = nf_proto_csum_update(*pskb, - *portptr ^ htons(0xFFFF), newport, - hdr->check, 0); + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0); if (!hdr->check) hdr->check = CSUM_MANGLED_0; } diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 1aa4517fbcdb..b55d670a24df 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -28,17 +28,16 @@ static inline int set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) { struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { + __u8 oldtos; if (!skb_make_writable(pskb, sizeof(struct iphdr))) return 0; iph = (*pskb)->nh.iph; oldtos = iph->tos; iph->tos &= ~IPT_ECN_IP_MASK; iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); - iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), - htons(iph->tos), iph->check); + nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } return 1; } @@ -72,10 +71,8 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) if (einfo->operation & IPT_ECN_OP_SET_CWR) tcph->cwr = einfo->proto.tcp.cwr; - tcph->check = nf_proto_csum_update((*pskb), - oldval ^ htons(0xFFFF), - ((__be16 *)tcph)[6], - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + oldval, ((__be16 *)tcph)[6], 0); return 1; } diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index 108b6b76311f..93eb5c3c1884 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c @@ -97,10 +97,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt[i+2] = (newmss & 0xff00) >> 8; opt[i+3] = (newmss & 0x00ff); - tcph->check = nf_proto_csum_update(*pskb, - htons(oldmss)^htons(0xFFFF), - htons(newmss), - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldmss), htons(newmss), 0); return IPT_CONTINUE; } } @@ -126,28 +124,22 @@ ipt_tcpmss_target(struct sk_buff **pskb, opt = (u_int8_t *)tcph + sizeof(struct tcphdr); memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); - tcph->check = nf_proto_csum_update(*pskb, - htons(tcplen) ^ htons(0xFFFF), - htons(tcplen + TCPOLEN_MSS), - tcph->check, 1); + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); opt[0] = TCPOPT_MSS; opt[1] = TCPOLEN_MSS; opt[2] = (newmss & 0xff00) >> 8; opt[3] = (newmss & 0x00ff); - tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt), - tcph->check, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0); oldval = ((__be16 *)tcph)[6]; tcph->doff += TCPOLEN_MSS/4; - tcph->check = nf_proto_csum_update(*pskb, - oldval ^ htons(0xFFFF), - ((__be16 *)tcph)[6], - tcph->check, 0); + nf_proto_csum_replace2(&tcph->check, *pskb, + oldval, ((__be16 *)tcph)[6], 0); newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); - iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF), - newtotlen, iph->check); + nf_csum_replace2(&iph->check, iph->tot_len, newtotlen); iph->tot_len = newtotlen; return IPT_CONTINUE; } diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 83b80b3a5d2f..18e74ac4d425 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c @@ -30,16 +30,15 @@ target(struct sk_buff **pskb, { const struct ipt_tos_target_info *tosinfo = targinfo; struct iphdr *iph = (*pskb)->nh.iph; - u_int16_t oldtos; if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { + __u8 oldtos; if (!skb_make_writable(pskb, sizeof(struct iphdr))) return NF_DROP; iph = (*pskb)->nh.iph; oldtos = iph->tos; iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; - iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF), - htons(iph->tos), iph->check); + nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } return IPT_CONTINUE; } diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index ac9517d62af0..fffe5ca82e91 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c @@ -54,9 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb, } if (new_ttl != iph->ttl) { - iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF), - htons(new_ttl << 8), - iph->check); + nf_csum_replace2(&iph->check, htons(iph->ttl << 8), + htons(new_ttl << 8)); iph->ttl = new_ttl; } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index d80b935b3a92..17f9e1cbc73b 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -222,28 +222,21 @@ copy_skb: } EXPORT_SYMBOL(skb_make_writable); -u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, u_int32_t csum) -{ - u_int32_t diff[] = { oldval, newval }; - - return csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum)); -} -EXPORT_SYMBOL(nf_csum_update); - -u_int16_t nf_proto_csum_update(struct sk_buff *skb, - u_int32_t oldval, u_int32_t newval, - u_int16_t csum, int pseudohdr) +void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, + __be32 from, __be32 to, int pseudohdr) { + __be32 diff[] = { ~from, to }; if (skb->ip_summed != CHECKSUM_PARTIAL) { - csum = nf_csum_update(oldval, newval, csum); + *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), + ~csum_unfold(*sum))); if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = nf_csum_update(oldval, newval, skb->csum); + skb->csum = ~csum_partial((char *)diff, sizeof(diff), + ~skb->csum); } else if (pseudohdr) - csum = ~nf_csum_update(oldval, newval, ~csum); - - return csum; + *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff), + csum_unfold(*sum))); } -EXPORT_SYMBOL(nf_proto_csum_update); +EXPORT_SYMBOL(nf_proto_csum_replace4); /* This does not belong here, but locally generated errors need it if connection tracking in use: without this, connection may not be in hash table, and hence -- cgit v1.2.3-71-gd317 From 1f61ab5ca5cca939a6509892d84b34849e155036 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 21:44:08 -0800 Subject: [NET]: Preliminaty annotation of skb->csum. It's still not completely right; we need to split it into anon unions of __wsum and unsigned - for cases when we use it for partial checksum and for offset of checksum in skb Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 41753667541d..fcab543d79ac 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -273,8 +273,8 @@ struct sk_buff { unsigned int len, data_len, - mac_len, - csum; + mac_len; + __wsum csum; __u32 priority; __u8 local_df:1, cloned:1, -- cgit v1.2.3-71-gd317 From bac0dff6cd194f7a28f7e840c9b6a7aa71c6ef97 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 19 Nov 2006 14:15:05 -0800 Subject: [BNX2]: Add 5709 PCI ID. Add PCI ID and detection for 5709 copper and SerDes chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 13 +++++++++++-- include/linux/pci_ids.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 92897efbc263..157463b4fa9f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -86,6 +86,7 @@ typedef enum { NC370F, BCM5708, BCM5708S, + BCM5709, } board_t; /* indexed by board_t, above */ @@ -99,6 +100,7 @@ static const struct { { "HP NC370F Multifunction Gigabit Server Adapter" }, { "Broadcom NetXtreme II BCM5708 1000Base-T" }, { "Broadcom NetXtreme II BCM5708 1000Base-SX" }, + { "Broadcom NetXtreme II BCM5709 1000Base-T" }, }; static struct pci_device_id bnx2_pci_tbl[] = { @@ -116,6 +118,8 @@ static struct pci_device_id bnx2_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 }, { 0, } }; @@ -5854,10 +5858,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->phy_addr = 1; /* Disable WOL support if we are running on a SERDES chip. */ - if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) { + if (CHIP_NUM(bp) == CHIP_NUM_5709) { + if (CHIP_BOND_ID(bp) != BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) + bp->phy_flags |= PHY_SERDES_FLAG; + } else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) bp->phy_flags |= PHY_SERDES_FLAG; + + if (bp->phy_flags & PHY_SERDES_FLAG) { bp->flags |= NO_WOL_FLAG; - if (CHIP_NUM(bp) == CHIP_NUM_5708) { + if (CHIP_NUM(bp) != CHIP_NUM_5706) { bp->phy_addr = 2; reg = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index fd5033b8a927..c09da1e30c54 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1897,6 +1897,7 @@ #define PCI_VENDOR_ID_BROADCOM 0x14e4 #define PCI_DEVICE_ID_TIGON3_5752 0x1600 #define PCI_DEVICE_ID_TIGON3_5752M 0x1601 +#define PCI_DEVICE_ID_NX2_5709 0x1639 #define PCI_DEVICE_ID_TIGON3_5700 0x1644 #define PCI_DEVICE_ID_TIGON3_5701 0x1645 #define PCI_DEVICE_ID_TIGON3_5702 0x1646 -- cgit v1.2.3-71-gd317 From 82e3ab9dbeebd5c8d5402ad1607d22086271a56d Mon Sep 17 00:00:00 2001 From: Ian McDonald Date: Mon, 20 Nov 2006 19:19:32 -0200 Subject: [DCCP]: Adds the tx buffer sysctls This one got lost on the way from Ian to Gerrit to me, fix it. Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/dccp.txt | 4 ++++ include/linux/sysctl.h | 1 + net/dccp/sysctl.c | 9 +++++++++ 3 files changed, 14 insertions(+) (limited to 'include/linux') diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 1910d097a0ad..dda15886bcb5 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -100,6 +100,10 @@ rx_ccid = 2 seq_window = 100 The initial sequence window (sec. 7.5.2). +tx_qlen = 5 + The size of the transmit buffer in packets. A value of 0 corresponds + to an unbounded transmit buffer. + Notes ===== diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 2e8c5ad82793..61dd99c6c2a5 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -617,6 +617,7 @@ enum { NET_DCCP_DEFAULT_REQ_RETRIES = 7, NET_DCCP_DEFAULT_RETRIES1 = 8, NET_DCCP_DEFAULT_RETRIES2 = 9, + NET_DCCP_DEFAULT_TX_QLEN = 10, }; /* /proc/sys/net/ipx */ diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 8b62061e5701..4775ba3faa04 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -91,6 +91,15 @@ static struct ctl_table dccp_default_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .ctl_name = NET_DCCP_DEFAULT_TX_QLEN, + .procname = "tx_qlen", + .data = &sysctl_dccp_tx_qlen, + .maxlen = sizeof(sysctl_dccp_tx_qlen), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .ctl_name = 0, } }; -- cgit v1.2.3-71-gd317 From f3ffaf14681e3cad61006873be8656ab41b793e0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 16:59:12 -0800 Subject: [SCTP]: Annotate SCTP headers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/sctp.h | 72 ++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sctp.h b/include/linux/sctp.h index 6ec66dec29f7..35108fe7a686 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -57,17 +57,17 @@ /* Section 3.1. SCTP Common Header Format */ typedef struct sctphdr { - __u16 source; - __u16 dest; - __u32 vtag; - __u32 checksum; + __be16 source; + __be16 dest; + __be32 vtag; + __be32 checksum; } __attribute__((packed)) sctp_sctphdr_t; /* Section 3.2. Chunk Field Descriptions. */ typedef struct sctp_chunkhdr { __u8 type; __u8 flags; - __u16 length; + __be16 length; } __attribute__((packed)) sctp_chunkhdr_t; @@ -153,8 +153,8 @@ enum { SCTP_CHUNK_FLAG_T = 0x01 }; */ typedef struct sctp_paramhdr { - __u16 type; - __u16 length; + __be16 type; + __be16 length; } __attribute__((packed)) sctp_paramhdr_t; typedef enum { @@ -203,10 +203,10 @@ enum { SCTP_PARAM_ACTION_MASK = __constant_htons(0xc000), }; /* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ typedef struct sctp_datahdr { - __u32 tsn; - __u16 stream; - __u16 ssn; - __u32 ppid; + __be32 tsn; + __be16 stream; + __be16 ssn; + __be32 ppid; __u8 payload[0]; } __attribute__((packed)) sctp_datahdr_t; @@ -232,11 +232,11 @@ enum { SCTP_DATA_FRAG_MASK = 0x03, }; * endpoints. */ typedef struct sctp_inithdr { - __u32 init_tag; - __u32 a_rwnd; - __u16 num_outbound_streams; - __u16 num_inbound_streams; - __u32 initial_tsn; + __be32 init_tag; + __be32 a_rwnd; + __be16 num_outbound_streams; + __be16 num_inbound_streams; + __be32 initial_tsn; __u8 params[0]; } __attribute__((packed)) sctp_inithdr_t; @@ -261,7 +261,7 @@ typedef struct sctp_ipv6addr_param { /* Section 3.3.2.1 Cookie Preservative (9) */ typedef struct sctp_cookie_preserve_param { sctp_paramhdr_t param_hdr; - uint32_t lifespan_increment; + __be32 lifespan_increment; } __attribute__((packed)) sctp_cookie_preserve_param_t; /* Section 3.3.2.1 Host Name Address (11) */ @@ -273,7 +273,7 @@ typedef struct sctp_hostname_param { /* Section 3.3.2.1 Supported Address Types (12) */ typedef struct sctp_supported_addrs_param { sctp_paramhdr_t param_hdr; - uint16_t types[0]; + __be16 types[0]; } __attribute__((packed)) sctp_supported_addrs_param_t; /* Appendix A. ECN Capable (32768) */ @@ -284,7 +284,7 @@ typedef struct sctp_ecn_capable_param { /* ADDIP Section 3.2.6 Adaption Layer Indication */ typedef struct sctp_adaption_ind_param { struct sctp_paramhdr param_hdr; - __u32 adaption_ind; + __be32 adaption_ind; } __attribute__((packed)) sctp_adaption_ind_param_t; /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): @@ -316,11 +316,11 @@ typedef struct sctp_unrecognized_param { */ typedef struct sctp_gap_ack_block { - __u16 start; - __u16 end; + __be16 start; + __be16 end; } __attribute__((packed)) sctp_gap_ack_block_t; -typedef uint32_t sctp_dup_tsn_t; +typedef __be32 sctp_dup_tsn_t; typedef union { sctp_gap_ack_block_t gab; @@ -328,10 +328,10 @@ typedef union { } sctp_sack_variable_t; typedef struct sctp_sackhdr { - __u32 cum_tsn_ack; - __u32 a_rwnd; - __u16 num_gap_ack_blocks; - __u16 num_dup_tsns; + __be32 cum_tsn_ack; + __be32 a_rwnd; + __be16 num_gap_ack_blocks; + __be16 num_dup_tsns; sctp_sack_variable_t variable[0]; } __attribute__((packed)) sctp_sackhdr_t; @@ -371,7 +371,7 @@ typedef struct sctp_abort_chunk { * and the highest consecutive acking value. */ typedef struct sctp_shutdownhdr { - __u32 cum_tsn_ack; + __be32 cum_tsn_ack; } __attribute__((packed)) sctp_shutdownhdr_t; struct sctp_shutdown_chunk_t { @@ -382,8 +382,8 @@ struct sctp_shutdown_chunk_t { /* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */ typedef struct sctp_errhdr { - __u16 cause; - __u16 length; + __be16 cause; + __be16 length; __u8 variable[0]; } __attribute__((packed)) sctp_errhdr_t; @@ -462,7 +462,7 @@ typedef enum { * Explicit Congestion Notification Echo (ECNE) (12) */ typedef struct sctp_ecnehdr { - __u32 lowest_tsn; + __be32 lowest_tsn; } sctp_ecnehdr_t; typedef struct sctp_ecne_chunk { @@ -474,7 +474,7 @@ typedef struct sctp_ecne_chunk { * Congestion Window Reduced (CWR) (13) */ typedef struct sctp_cwrhdr { - __u32 lowest_tsn; + __be32 lowest_tsn; } sctp_cwrhdr_t; typedef struct sctp_cwr_chunk { @@ -529,12 +529,12 @@ typedef struct sctp_cwr_chunk { * chunks this field MUST be filled in. */ struct sctp_fwdtsn_skip { - __u16 stream; - __u16 ssn; + __be16 stream; + __be16 ssn; } __attribute__((packed)); struct sctp_fwdtsn_hdr { - __u32 new_cum_tsn; + __be32 new_cum_tsn; struct sctp_fwdtsn_skip skip[0]; } __attribute((packed)); @@ -578,11 +578,11 @@ struct sctp_fwdtsn_chunk { */ typedef struct sctp_addip_param { sctp_paramhdr_t param_hdr; - __u32 crr_id; + __be32 crr_id; } __attribute__((packed)) sctp_addip_param_t; typedef struct sctp_addiphdr { - __u32 serial; + __be32 serial; __u8 params[0]; } __attribute__((packed)) sctp_addiphdr_t; -- cgit v1.2.3-71-gd317 From 962c837275e8a8c1df41f1882e971636093cdee4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 17:26:08 -0800 Subject: [SCTP]: Netfilter sctp annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sctp.h | 2 +- net/netfilter/xt_sctp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/linux/netfilter/nf_conntrack_sctp.h index b8994d9fd1a9..5cf2c115cce4 100644 --- a/include/linux/netfilter/nf_conntrack_sctp.h +++ b/include/linux/netfilter/nf_conntrack_sctp.h @@ -20,7 +20,7 @@ struct ip_ct_sctp { enum sctp_conntrack state; - u_int32_t vtag[IP_CT_DIR_MAX]; + __be32 vtag[IP_CT_DIR_MAX]; u_int32_t ttag[IP_CT_DIR_MAX]; }; diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index 7956acaaa24b..71bf036f833c 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c @@ -71,7 +71,7 @@ match_packet(const struct sk_buff *skb, duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", ++i, offset, sch->type, htons(sch->length), sch->flags); - offset += (htons(sch->length) + 3) & ~3; + offset += (ntohs(sch->length) + 3) & ~3; duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); -- cgit v1.2.3-71-gd317 From ff1dcadb1b55dbf471c5ed109dbbdf06bd19ef3b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 18:07:29 -0800 Subject: [NET]: Split skb->csum ... into anonymous union of __wsum and __u32 (csum and csum_offset resp.) Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/net/cassini.c | 2 +- drivers/net/e1000/e1000_main.c | 2 +- drivers/net/ixgb/ixgb_main.c | 2 +- drivers/net/myri10ge/myri10ge.c | 2 +- drivers/net/sk98lin/skge.c | 4 ++-- drivers/net/skge.c | 2 +- drivers/net/sky2.c | 2 +- drivers/net/sungem.c | 2 +- drivers/net/sunhme.c | 2 +- include/linux/skbuff.h | 5 ++++- net/core/dev.c | 4 ++-- net/core/skbuff.c | 2 +- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv4/udp.c | 2 +- net/ipv6/tcp_ipv6.c | 4 ++-- 15 files changed, 22 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 521c5b71023c..fd2cc13f7d97 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2825,7 +2825,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring, u64 csum_start_off, csum_stuff_off; csum_start_off = (u64) (skb->h.raw - skb->data); - csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; ctrl = TX_DESC_CSUM_EN | CAS_BASE(TX_DESC_CSUM_START, csum_start_off) | diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7a0828869ecf..32dde0adb683 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2826,7 +2826,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index e09f575a3a38..7b127212e62b 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1249,7 +1249,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb) if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) { struct ixgb_buffer *buffer_info; css = skb->h.raw - skb->data; - cso = (skb->h.raw + skb->csum) - skb->data; + cso = css + skb->csum_offset; i = adapter->tx_ring.next_to_use; context_desc = IXGB_CONTEXT_DESC(adapter->tx_ring, i); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 806081b59733..36350e6db1c1 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1955,7 +1955,7 @@ again: flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST); if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { cksum_offset = (skb->h.raw - skb->data); - pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data; + pseudo_hdr_offset = cksum_offset + skb->csum_offset; /* If the headers are excessively large, then we must * fall back to a software checksum */ if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index a5d41ebc9fb4..12cbfd190dd7 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -1562,7 +1562,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ if (pMessage->ip_summed == CHECKSUM_PARTIAL) { u16 hdrlen = pMessage->h.raw - pMessage->data; - u16 offset = hdrlen + pMessage->csum; + u16 offset = hdrlen + pMessage->csum_offset; if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && (pAC->GIni.GIChipRev == 0) && @@ -1681,7 +1681,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ */ if (pMessage->ip_summed == CHECKSUM_PARTIAL) { u16 hdrlen = pMessage->h.raw - pMessage->data; - u16 offset = hdrlen + pMessage->csum; + u16 offset = hdrlen + pMessage->csum_offset; Control = BMU_STFWD; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 27b537c8d5e3..5513907e8393 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2565,7 +2565,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) td->csum_offs = 0; td->csum_start = offset; - td->csum_write = offset + skb->csum; + td->csum_write = offset + skb->csum_offset; } else control = BMU_CHECK; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 0ef1848b9761..842abd9396c6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1350,7 +1350,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) u32 tcpsum; tcpsum = offset << 16; /* sum start */ - tcpsum |= offset + skb->csum; /* sum write */ + tcpsum |= offset + skb->csum_offset; /* sum write */ ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; if (skb->nh.iph->protocol == IPPROTO_UDP) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 253e96e7ad20..334c6cfd6595 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1030,7 +1030,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) u64 csum_start_off, csum_stuff_off; csum_start_off = (u64) (skb->h.raw - skb->data); - csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; ctrl = (TXDCTRL_CENAB | (csum_start_off << 15) | diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 9d7cd130c19d..ec432ea879fb 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2272,7 +2272,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 csum_start_off, csum_stuff_off; csum_start_off = (u32) (skb->h.raw - skb->data); - csum_stuff_off = (u32) ((skb->h.raw + skb->csum) - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE | ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) | diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index fcab543d79ac..14ec16d2d9ba 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -274,7 +274,10 @@ struct sk_buff { unsigned int len, data_len, mac_len; - __wsum csum; + union { + __wsum csum; + __u32 csum_offset; + }; __u32 priority; __u8 local_df:1, cloned:1, diff --git a/net/core/dev.c b/net/core/dev.c index 1a36b17f4b51..59d058a3b504 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1191,9 +1191,9 @@ int skb_checksum_help(struct sk_buff *skb) offset = skb->tail - skb->h.raw; BUG_ON(offset <= 0); - BUG_ON(skb->csum + 2 > offset); + BUG_ON(skb->csum_offset + 2 > offset); - *(__sum16*)(skb->h.raw + skb->csum) = csum_fold(csum); + *(__sum16*)(skb->h.raw + skb->csum_offset) = csum_fold(csum); out_set_summed: skb->ip_summed = CHECKSUM_NONE; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 07c25d601922..a90bc439488e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1414,7 +1414,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) skb->len - csstart, 0); if (skb->ip_summed == CHECKSUM_PARTIAL) { - long csstuff = csstart + skb->csum; + long csstuff = csstart + skb->csum_offset; *((__sum16 *)(to + csstuff)) = csum_fold(csum); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e9d467124c4d..4913f25e5ad5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -504,7 +504,7 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_PARTIAL) { th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); } else { th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr, csum_partial((char *)th, @@ -526,7 +526,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) th->check = 0; th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); skb->ip_summed = CHECKSUM_PARTIAL; return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 28e4cf662ce0..1807a30694d9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -422,7 +422,7 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, /* * Only one fragment on the socket. */ - skb->csum = offsetof(struct udphdr, check); + skb->csum_offset = offsetof(struct udphdr, check); uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); } else { /* diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0adb337c4b7e..517c50024bfc 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -948,7 +948,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_PARTIAL) { th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); } else { th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, csum_partial((char *)th, th->doff<<2, @@ -970,7 +970,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) th->check = 0; th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, IPPROTO_TCP, 0); - skb->csum = offsetof(struct tcphdr, check); + skb->csum_offset = offsetof(struct tcphdr, check); skb->ip_summed = CHECKSUM_PARTIAL; return 0; } -- cgit v1.2.3-71-gd317 From d61c167dd0797a16584f7a922dd5d50efad1d28a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 27 Nov 2006 12:31:45 -0200 Subject: [NET]: Add documentation for TFRC structures This adds documentation for the TFRC structure fields. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tfrc.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tfrc.h b/include/linux/tfrc.h index 7dab7831c3cb..31a9b25276fe 100644 --- a/include/linux/tfrc.h +++ b/include/linux/tfrc.h @@ -1,7 +1,8 @@ #ifndef _LINUX_TFRC_H_ #define _LINUX_TFRC_H_ /* - * include/linux/tfrc.h + * TFRC - Data Structures for the TCP-Friendly Rate Control congestion + * control mechanism as specified in RFC 3448. * * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005 Ian McDonald @@ -13,15 +14,30 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ - #include +/** tfrc_rx_info - TFRC Receiver Data Structure + * + * @tfrcrx_x_recv: receiver estimate of sending rate (3.2.2) + * @tfrcrx_rtt: round-trip-time (communicated by sender) + * @tfrcrx_p: current estimate of loss event rate (3.2.2) + */ struct tfrc_rx_info { __u32 tfrcrx_x_recv; __u32 tfrcrx_rtt; __u32 tfrcrx_p; }; +/** tfrc_tx_info - TFRC Sender Data Structure + * + * @tfrctx_x: computed transmit rate (4.3 (4)) + * @tfrctx_x_recv: receiver estimate of send rate (4.3) + * @tfrctx_x_calc: return value of throughput equation (3.1) + * @tfrctx_rtt: (moving average) estimate of RTT (4.3) + * @tfrctx_p: current loss event rate (5.4) + * @tfrctx_rto: estimate of RTO, equals 4*RTT (4.3) + * @tfrctx_ipi: inter-packet interval (4.6) + */ struct tfrc_tx_info { __u32 tfrctx_x; __u32 tfrctx_x_recv; -- cgit v1.2.3-71-gd317 From 4e9b82693542003b028c8494e9e3c49615b91ce7 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 27 Nov 2006 09:25:58 -0800 Subject: [NETLINK]: Remove unused dst_pid field in netlink_skb_parms The destination PID is passed directly to netlink_unicast() respectively netlink_multicast(). Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 - net/decnet/dn_route.c | 2 -- net/ipv4/fib_frontend.c | 1 - net/ipv4/netfilter/ip_conntrack_netlink.c | 4 +--- net/netfilter/nf_conntrack_netlink.c | 4 +--- net/netlink/af_netlink.c | 1 - net/xfrm/xfrm_user.c | 2 -- 7 files changed, 2 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index e61e1e138421..b3b9b609ee89 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -141,7 +141,6 @@ struct netlink_skb_parms { struct ucred creds; /* Skb credentials */ __u32 pid; - __u32 dst_pid; __u32 dst_group; kernel_cap_t eff_cap; __u32 loginuid; /* Login (audit) uid */ diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index f759d6f422ea..4eb985236aee 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1592,8 +1592,6 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; - NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; - err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0); if (err == 0) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 14025345cc56..d47b72af89ed 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -811,7 +811,6 @@ static void nl_fib_input(struct sock *sk, int len) pid = nlh->nlmsg_pid; /*pid of sending process */ NETLINK_CB(skb).pid = 0; /* from kernel */ - NETLINK_CB(skb).dst_pid = pid; NETLINK_CB(skb).dst_group = 0; /* unicast */ netlink_unicast(sk, skb, pid, MSG_DONTWAIT); } diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 55f0ae641081..1bb8ed33c5bc 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -743,7 +743,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ip_conntrack_put(ct); return -ENOMEM; } - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, 1, ct); @@ -1273,8 +1272,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb2) goto out; - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; - + err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1, exp); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index ab67c2be2b5d..cfb35fd8d9b9 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -752,7 +752,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, nf_ct_put(ct); return -ENOMEM; } - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, 1, ct); @@ -1300,8 +1299,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb2) goto out; - NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; - + err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1, exp); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index f61d81b3c61c..3baafb10f8f3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1153,7 +1153,6 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; NETLINK_CB(skb).pid = nlk->pid; - NETLINK_CB(skb).dst_pid = dst_pid; NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); selinux_get_task_sid(current, &(NETLINK_CB(skb).sid)); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 6c4d2f49d9e5..8dbb38b91de2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -650,7 +650,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, if (!skb) return ERR_PTR(-ENOMEM); - NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; info.in_skb = in_skb; info.out_skb = skb; info.nlmsg_seq = seq; @@ -1168,7 +1167,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, if (!skb) return ERR_PTR(-ENOMEM); - NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; info.in_skb = in_skb; info.out_skb = skb; info.nlmsg_seq = seq; -- cgit v1.2.3-71-gd317 From e3703b3de1f049b38733ba520e5038f23063068e Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 27 Nov 2006 09:27:07 -0800 Subject: [RTNETLINK]: Add rtnl_put_cacheinfo() to unify some code IPv4, IPv6, and DECNet all use struct rta_cacheinfo in a similiar way, therefore rtnl_put_cacheinfo() is added to reuse code. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 3 +++ net/core/rtnetlink.c | 20 ++++++++++++++++++++ net/decnet/dn_route.c | 16 +++++----------- net/ipv4/route.c | 26 +++++++++++--------------- net/ipv6/route.c | 19 ++++++------------- 5 files changed, 45 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 33b3d0ab3a91..493297acdae8 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -585,6 +585,9 @@ extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, struct nlmsghdr *nlh, gfp_t flags); extern void rtnl_set_sk_err(u32 group, int error); extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); +extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, + u32 id, u32 ts, u32 tsage, long expires, + u32 error); extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 0cb4d9e53a07..e76539a5eb5e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -212,6 +212,26 @@ nla_put_failure: return nla_nest_cancel(skb, mx); } +int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, + u32 ts, u32 tsage, long expires, u32 error) +{ + struct rta_cacheinfo ci = { + .rta_lastuse = jiffies_to_clock_t(jiffies - dst->lastuse), + .rta_used = dst->__use, + .rta_clntref = atomic_read(&(dst->__refcnt)), + .rta_error = error, + .rta_id = id, + .rta_ts = ts, + .rta_tsage = tsage, + }; + + if (expires) + ci.rta_expires = jiffies_to_clock_t(expires); + + return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci); +} + +EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); static void set_operstate(struct net_device *dev, unsigned char transition) { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 4eb985236aee..9881933167bd 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1469,7 +1469,7 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, struct rtmsg *r; struct nlmsghdr *nlh; unsigned char *b = skb->tail; - struct rta_cacheinfo ci; + long expires; nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); r = NLMSG_DATA(nlh); @@ -1502,16 +1502,10 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto rtattr_failure; - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - if (rt->u.dst.expires) - ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_error = rt->u.dst.error; - ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; - RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; + if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, expires, + rt->u.dst.error) < 0) + goto rtattr_failure; if (rt->fl.iif) RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ee00b6506ab4..9f3924c4905e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2629,7 +2629,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, struct rtable *rt = (struct rtable*)skb->dst; struct rtmsg *r; struct nlmsghdr *nlh; - struct rta_cacheinfo ci; + long expires; + u32 id = 0, ts = 0, tsage = 0, error; nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); if (nlh == NULL) @@ -2676,20 +2677,13 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto nla_put_failure; - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - if (rt->u.dst.expires) - ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_error = rt->u.dst.error; - ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; + error = rt->u.dst.error; + expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; if (rt->peer) { - ci.rta_id = rt->peer->ip_id_count; + id = rt->peer->ip_id_count; if (rt->peer->tcp_ts_stamp) { - ci.rta_ts = rt->peer->tcp_ts; - ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; + ts = rt->peer->tcp_ts; + tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; } } @@ -2708,7 +2702,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, } else { if (err == -EMSGSIZE) goto nla_put_failure; - ci.rta_error = err; + error = err; } } } else @@ -2716,7 +2710,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif); } - NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + if (rtnl_put_cacheinfo(skb, &rt->u.dst, id, ts, tsage, + expires, error) < 0) + goto nla_put_failure; return nlmsg_end(skb, nlh); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0bf17a3cf085..9f80518aacbd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2027,7 +2027,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, { struct rtmsg *rtm; struct nlmsghdr *nlh; - struct rta_cacheinfo ci; + long expires; u32 table; if (prefix) { /* user wants prefix routes only */ @@ -2101,18 +2101,11 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - if (rt->rt6i_expires) - ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - ci.rta_error = rt->u.dst.error; - ci.rta_id = 0; - ci.rta_ts = 0; - ci.rta_tsage = 0; - NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + + expires = rt->rt6i_expires ? rt->rt6i_expires - jiffies : 0; + if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, + expires, rt->u.dst.error) < 0) + goto nla_put_failure; return nlmsg_end(skb, nlh); -- cgit v1.2.3-71-gd317 From d5c42c0ec4f7fd5a4e19e33a2d561758b67c55c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 27 Nov 2006 17:58:02 -0200 Subject: [NET]: Pack struct hh_cache [acme@newtoy net-2.6.20]$ pahole net/ipv4/tcp.o hh_cache /* /pub/scm/linux/kernel/git/acme/net-2.6.20/include/linux/netdevice.h:190 */ struct hh_cache { struct hh_cache * hh_next; /* 0 4 */ atomic_t hh_refcnt; /* 4 4 */ __be16 hh_type; /* 8 2 */ /* XXX 2 bytes hole, try to pack */ int hh_len; /* 12 4 */ int (*hh_output)(); /* 16 4 */ rwlock_t hh_lock; /* 20 36 */ long unsigned int hh_data[24]; /* 56 96 */ }; /* size: 152, sum members: 150, holes: 1, sum holes: 2 */ [acme@newtoy net-2.6.20]$ find net -name "*.[ch]" | xargs grep 'hh_len.\+=' | sort -u net/atm/br2684.c: hh->hh_len = PADLEN + ETH_HLEN; net/ethernet/eth.c: hh->hh_len = ETH_HLEN; net/ipv4/ipconfig.c: int hh_len = LL_RESERVED_SPACE(dev); net/ipv4/ip_output.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); net/ipv4/ip_output.c: int hh_len = LL_RESERVED_SPACE(dev); net/ipv4/netfilter.c: hh_len = (*pskb)->dst->dev->hard_header_len; net/ipv4/raw.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); net/ipv6/ip6_output.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); net/ipv6/netfilter/ip6t_REJECT.c: hh_len = (dst->dev->hard_header_len + 15)&~15; net/ipv6/raw.c: hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); [acme@newtoy net-2.6.20]$ [acme@newtoy net-2.6.20]$ find include -name "*.h" | xargs grep 'define ETH_HLEN' include/linux/if_ether.h:#define ETH_HLEN 14 /* Total octets in header. */ (((dev)->hard_header_len&~(HH_DATA_MOD - 1)) + HH_DATA_MOD) [acme@newtoy net-2.6.20]$ pahole net/ipv4/tcp.o net_device | grep hard_header_len short unsigned int hard_header_len; /* 106 2 */ [acme@newtoy net-2.6.20]$ So I think we're safe in turning hh_len an u16, end result: [acme@newtoy net-2.6.20]$ codiff -sV /tmp/tcp.o.before net/ipv4/tcp.o /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/tcp.c: struct hh_cache | -4 hh_len; from: int /* 12(0) 4(0) */ to: u16 /* 10(0) 2(0) */ 1 struct changed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index caa3c2593719..949eada46ce1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -196,7 +196,7 @@ struct hh_cache * NOTE: For VLANs, this will be the * encapuslated type. --BLG */ - int hh_len; /* length of header */ + u16 hh_len; /* length of header */ int (*hh_output)(struct sk_buff *skb); rwlock_t hh_lock; -- cgit v1.2.3-71-gd317 From 2ff52f282cf287d60e9eda1f3b5ec83e00a86130 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 28 Nov 2006 00:48:32 -0200 Subject: [TCP]: Change tcp_header_len member in tcp_sock to u16 With this we eliminate the last hole in struct tcp_sock. End result: [acme@newtoy net-2.6.20]$ codiff -sV /tmp/tcp.o.before net/ipv4/tcp.o /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/tcp.c: struct tcp_sock | -4 tcp_header_len; from: int /* 1000(0) 4(0) */ to: u16 /* 1000(0) 2(0) */ 1 struct changed [acme@newtoy net-2.6.20]$ Now sizeof(tcp_sock) is just... [acme@newtoy net-2.6.20]$ pahole --sizes ../OUTPUT/qemu/net-2.6.20/net/ipv4/tcp.o | grep -w tcp_sock struct tcp_sock: 1500 0 1500 bytes ;-) Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tcp.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index dd61b172ac68..b42ff0efc2df 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -227,7 +227,8 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) struct tcp_sock { /* inet_connection_sock has to be the first member of tcp_sock */ struct inet_connection_sock inet_conn; - int tcp_header_len; /* Bytes of tcp header to send */ + u16 tcp_header_len; /* Bytes of tcp header to send */ + u16 xmit_size_goal; /* Goal for segmenting output packets */ /* * Header prediction flags @@ -268,8 +269,6 @@ struct tcp_sock { __u32 snd_wnd; /* The window we expect to receive */ __u32 max_window; /* Maximal window ever seen from peer */ __u32 mss_cache; /* Cached effective mss, not including SACKS */ - __u16 xmit_size_goal; /* Goal for segmenting output packets */ - /* XXX Two bytes hole, try to pack */ __u32 window_clamp; /* Maximal window to advertise */ __u32 rcv_ssthresh; /* Current window clamp */ -- cgit v1.2.3-71-gd317 From 3a137d2065571864be0301b9ebd72ddb01060997 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 28 Nov 2006 01:12:38 -0200 Subject: [TCP]: Renove the __ prefix on the struct tcp_sock members As this struct is not userland visible at all. Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tcp.h | 156 ++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 78 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index b42ff0efc2df..3cc70d1a3504 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -185,17 +185,17 @@ struct tcp_sack_block_wire { }; struct tcp_sack_block { - __u32 start_seq; - __u32 end_seq; + u32 start_seq; + u32 end_seq; }; struct tcp_options_received { /* PAWS/RTTM data */ long ts_recent_stamp;/* Time we stored ts_recent (for aging) */ - __u32 ts_recent; /* Time stamp to echo next */ - __u32 rcv_tsval; /* Time stamp value */ - __u32 rcv_tsecr; /* Time stamp echo reply */ - __u16 saw_tstamp : 1, /* Saw TIMESTAMP on last packet */ + u32 ts_recent; /* Time stamp to echo next */ + u32 rcv_tsval; /* Time stamp value */ + u32 rcv_tsecr; /* Time stamp echo reply */ + u16 saw_tstamp : 1, /* Saw TIMESTAMP on last packet */ tstamp_ok : 1, /* TIMESTAMP seen on SYN packet */ dsack : 1, /* D-SACK is scheduled */ wscale_ok : 1, /* Wscale seen on SYN packet */ @@ -203,10 +203,10 @@ struct tcp_options_received { snd_wscale : 4, /* Window scaling received from sender */ rcv_wscale : 4; /* Window scaling to send to receiver */ /* SACKs data */ - __u8 eff_sacks; /* Size of SACK array to send with next packet */ - __u8 num_sacks; /* Number of SACK blocks */ - __u16 user_mss; /* mss requested by user in ioctl */ - __u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ + u8 eff_sacks; /* Size of SACK array to send with next packet */ + u8 num_sacks; /* Number of SACK blocks */ + u16 user_mss; /* mss requested by user in ioctl */ + u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ }; struct tcp_request_sock { @@ -215,8 +215,8 @@ struct tcp_request_sock { /* Only used by TCP MD5 Signature so far. */ struct tcp_request_sock_ops *af_specific; #endif - __u32 rcv_isn; - __u32 snt_isn; + u32 rcv_isn; + u32 snt_isn; }; static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) @@ -241,13 +241,13 @@ struct tcp_sock { * read the code and the spec side by side (and laugh ...) * See RFC793 and RFC1122. The RFC writes these in capitals. */ - __u32 rcv_nxt; /* What we want to receive next */ - __u32 snd_nxt; /* Next sequence we send */ + u32 rcv_nxt; /* What we want to receive next */ + u32 snd_nxt; /* Next sequence we send */ - __u32 snd_una; /* First byte we want an ack for */ - __u32 snd_sml; /* Last byte of the most recently transmitted small packet */ - __u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ - __u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ + u32 snd_una; /* First byte we want an ack for */ + u32 snd_sml; /* Last byte of the most recently transmitted small packet */ + u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ + u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ /* Data for direct copy to user */ struct { @@ -265,30 +265,30 @@ struct tcp_sock { #endif } ucopy; - __u32 snd_wl1; /* Sequence for window update */ - __u32 snd_wnd; /* The window we expect to receive */ - __u32 max_window; /* Maximal window ever seen from peer */ - __u32 mss_cache; /* Cached effective mss, not including SACKS */ + u32 snd_wl1; /* Sequence for window update */ + u32 snd_wnd; /* The window we expect to receive */ + u32 max_window; /* Maximal window ever seen from peer */ + u32 mss_cache; /* Cached effective mss, not including SACKS */ - __u32 window_clamp; /* Maximal window to advertise */ - __u32 rcv_ssthresh; /* Current window clamp */ + u32 window_clamp; /* Maximal window to advertise */ + u32 rcv_ssthresh; /* Current window clamp */ - __u32 frto_highmark; /* snd_nxt when RTO occurred */ - __u8 reordering; /* Packet reordering metric. */ - __u8 frto_counter; /* Number of new acks after RTO */ - __u8 nonagle; /* Disable Nagle algorithm? */ - __u8 keepalive_probes; /* num of allowed keep alive probes */ + u32 frto_highmark; /* snd_nxt when RTO occurred */ + u8 reordering; /* Packet reordering metric. */ + u8 frto_counter; /* Number of new acks after RTO */ + u8 nonagle; /* Disable Nagle algorithm? */ + u8 keepalive_probes; /* num of allowed keep alive probes */ /* RTT measurement */ - __u32 srtt; /* smoothed round trip time << 3 */ - __u32 mdev; /* medium deviation */ - __u32 mdev_max; /* maximal mdev for the last rtt period */ - __u32 rttvar; /* smoothed mdev_max */ - __u32 rtt_seq; /* sequence number to update rttvar */ - - __u32 packets_out; /* Packets which are "in flight" */ - __u32 left_out; /* Packets which leaved network */ - __u32 retrans_out; /* Retransmitted packets out */ + u32 srtt; /* smoothed round trip time << 3 */ + u32 mdev; /* medium deviation */ + u32 mdev_max; /* maximal mdev for the last rtt period */ + u32 rttvar; /* smoothed mdev_max */ + u32 rtt_seq; /* sequence number to update rttvar */ + + u32 packets_out; /* Packets which are "in flight" */ + u32 left_out; /* Packets which leaved network */ + u32 retrans_out; /* Retransmitted packets out */ /* * Options received (usually on last packet, some only on SYN packets). */ @@ -297,20 +297,20 @@ struct tcp_sock { /* * Slow start and congestion control (see also Nagle, and Karn & Partridge) */ - __u32 snd_ssthresh; /* Slow start size threshold */ - __u32 snd_cwnd; /* Sending congestion window */ - __u16 snd_cwnd_cnt; /* Linear increase counter */ - __u16 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ - __u32 snd_cwnd_used; - __u32 snd_cwnd_stamp; + u32 snd_ssthresh; /* Slow start size threshold */ + u32 snd_cwnd; /* Sending congestion window */ + u16 snd_cwnd_cnt; /* Linear increase counter */ + u16 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ + u32 snd_cwnd_used; + u32 snd_cwnd_stamp; struct sk_buff_head out_of_order_queue; /* Out of order segments go here */ - __u32 rcv_wnd; /* Current receiver window */ - __u32 rcv_wup; /* rcv_nxt on last window update sent */ - __u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ - __u32 pushed_seq; /* Last pushed seq, required to talk to windows */ - __u32 copied_seq; /* Head of yet unread data */ + u32 rcv_wnd; /* Current receiver window */ + u32 rcv_wup; /* rcv_nxt on last window update sent */ + u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ + u32 pushed_seq; /* Last pushed seq, required to talk to windows */ + u32 copied_seq; /* Head of yet unread data */ /* SACKs data */ struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ @@ -331,26 +331,26 @@ struct tcp_sock { int retransmit_cnt_hint; int forward_cnt_hint; - __u16 advmss; /* Advertised MSS */ - __u16 prior_ssthresh; /* ssthresh saved at recovery start */ - __u32 lost_out; /* Lost packets */ - __u32 sacked_out; /* SACK'd packets */ - __u32 fackets_out; /* FACK'd packets */ - __u32 high_seq; /* snd_nxt at onset of congestion */ + u16 advmss; /* Advertised MSS */ + u16 prior_ssthresh; /* ssthresh saved at recovery start */ + u32 lost_out; /* Lost packets */ + u32 sacked_out; /* SACK'd packets */ + u32 fackets_out; /* FACK'd packets */ + u32 high_seq; /* snd_nxt at onset of congestion */ - __u32 retrans_stamp; /* Timestamp of the last retransmit, + u32 retrans_stamp; /* Timestamp of the last retransmit, * also used in SYN-SENT to remember stamp of * the first SYN. */ - __u32 undo_marker; /* tracking retrans started here. */ + u32 undo_marker; /* tracking retrans started here. */ int undo_retrans; /* number of undoable retransmissions. */ - __u32 urg_seq; /* Seq of received urgent pointer */ - __u16 urg_data; /* Saved octet of OOB data and control flags */ - __u8 urg_mode; /* In urgent mode */ - __u8 ecn_flags; /* ECN status bits. */ - __u32 snd_up; /* Urgent pointer */ + u32 urg_seq; /* Seq of received urgent pointer */ + u16 urg_data; /* Saved octet of OOB data and control flags */ + u8 urg_mode; /* In urgent mode */ + u8 ecn_flags; /* ECN status bits. */ + u32 snd_up; /* Urgent pointer */ - __u32 total_retrans; /* Total retransmits for entire connection */ - __u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */ + u32 total_retrans; /* Total retransmits for entire connection */ + u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */ unsigned int keepalive_time; /* time before keep alive takes place */ unsigned int keepalive_intvl; /* time interval between keep alive probes */ @@ -358,26 +358,26 @@ struct tcp_sock { unsigned long last_synq_overflow; - __u32 tso_deferred; + u32 tso_deferred; /* Receiver side RTT estimation */ struct { - __u32 rtt; - __u32 seq; - __u32 time; + u32 rtt; + u32 seq; + u32 time; } rcv_rtt_est; /* Receiver queue space */ struct { int space; - __u32 seq; - __u32 time; + u32 seq; + u32 time; } rcvq_space; /* TCP-specific MTU probe information. */ struct { - __u32 probe_seq_start; - __u32 probe_seq_end; + u32 probe_seq_start; + u32 probe_seq_end; } mtu_probe; #ifdef CONFIG_TCP_MD5SIG @@ -396,14 +396,14 @@ static inline struct tcp_sock *tcp_sk(const struct sock *sk) struct tcp_timewait_sock { struct inet_timewait_sock tw_sk; - __u32 tw_rcv_nxt; - __u32 tw_snd_nxt; - __u32 tw_rcv_wnd; - __u32 tw_ts_recent; + u32 tw_rcv_nxt; + u32 tw_snd_nxt; + u32 tw_rcv_wnd; + u32 tw_ts_recent; long tw_ts_recent_stamp; #ifdef CONFIG_TCP_MD5SIG - __u16 tw_md5_keylen; - __u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; + u16 tw_md5_keylen; + u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; #endif }; -- cgit v1.2.3-71-gd317 From 4384260443efe90a2ec0d907568dbc58ae792cd0 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 28 Nov 2006 18:14:10 -0200 Subject: [DCCP]: Remove allocation of sysctl numbers This is in response to a request sent earlier by Eric W. Biederman and replaces all sysctl numbers for net.dccp.default with CTL_UNNUMBERED. It has been tested to compile and to work. Commiter note: I've removed the use of CTL_UNNUMBERED, not setting .ctl_name sets it to 0, that is the what CTL_UNNUMBERED is, reason is to avoid unneeded source code cluttering. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/sysctl.h | 14 -------------- net/dccp/sysctl.c | 10 ---------- 2 files changed, 24 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 61dd99c6c2a5..94316a98e0d0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -606,20 +606,6 @@ enum { NET_DCCP_DEFAULT=1, }; -/* /proc/sys/net/dccp/default */ -enum { - NET_DCCP_DEFAULT_SEQ_WINDOW = 1, - NET_DCCP_DEFAULT_RX_CCID = 2, - NET_DCCP_DEFAULT_TX_CCID = 3, - NET_DCCP_DEFAULT_ACK_RATIO = 4, - NET_DCCP_DEFAULT_SEND_ACKVEC = 5, - NET_DCCP_DEFAULT_SEND_NDP = 6, - NET_DCCP_DEFAULT_REQ_RETRIES = 7, - NET_DCCP_DEFAULT_RETRIES1 = 8, - NET_DCCP_DEFAULT_RETRIES2 = 9, - NET_DCCP_DEFAULT_TX_QLEN = 10, -}; - /* /proc/sys/net/ipx */ enum { NET_IPX_PPROP_BROADCASTING=1, diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 4775ba3faa04..fdcfca3e9208 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -20,7 +20,6 @@ static struct ctl_table dccp_default_table[] = { { - .ctl_name = NET_DCCP_DEFAULT_SEQ_WINDOW, .procname = "seq_window", .data = &sysctl_dccp_feat_sequence_window, .maxlen = sizeof(sysctl_dccp_feat_sequence_window), @@ -28,7 +27,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_RX_CCID, .procname = "rx_ccid", .data = &sysctl_dccp_feat_rx_ccid, .maxlen = sizeof(sysctl_dccp_feat_rx_ccid), @@ -36,7 +34,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_TX_CCID, .procname = "tx_ccid", .data = &sysctl_dccp_feat_tx_ccid, .maxlen = sizeof(sysctl_dccp_feat_tx_ccid), @@ -44,7 +41,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_ACK_RATIO, .procname = "ack_ratio", .data = &sysctl_dccp_feat_ack_ratio, .maxlen = sizeof(sysctl_dccp_feat_ack_ratio), @@ -52,7 +48,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_SEND_ACKVEC, .procname = "send_ackvec", .data = &sysctl_dccp_feat_send_ack_vector, .maxlen = sizeof(sysctl_dccp_feat_send_ack_vector), @@ -60,7 +55,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_SEND_NDP, .procname = "send_ndp", .data = &sysctl_dccp_feat_send_ndp_count, .maxlen = sizeof(sysctl_dccp_feat_send_ndp_count), @@ -68,7 +62,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_REQ_RETRIES, .procname = "request_retries", .data = &sysctl_dccp_request_retries, .maxlen = sizeof(sysctl_dccp_request_retries), @@ -76,7 +69,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_RETRIES1, .procname = "retries1", .data = &sysctl_dccp_retries1, .maxlen = sizeof(sysctl_dccp_retries1), @@ -84,7 +76,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_RETRIES2, .procname = "retries2", .data = &sysctl_dccp_retries2, .maxlen = sizeof(sysctl_dccp_retries2), @@ -92,7 +83,6 @@ static struct ctl_table dccp_default_table[] = { .proc_handler = proc_dointvec, }, { - .ctl_name = NET_DCCP_DEFAULT_TX_QLEN, .procname = "tx_qlen", .data = &sysctl_dccp_tx_qlen, .maxlen = sizeof(sysctl_dccp_tx_qlen), -- cgit v1.2.3-71-gd317 From 5aed324369c94a2c38469c8288e42eb1a9fac400 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 28 Nov 2006 19:33:36 -0200 Subject: [DCCP]: Tidy up unused structures This removes and cleans up unused variables and structures which have become unnecessary following the introduction of the EWMA patch to automatically track the CCID 3 receiver/sender packet sizes `s'. It deprecates the PACKET_SIZE socket option by returning an error code and printing a deprecation warning if an application tries to read or write this socket option. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 4 +--- net/dccp/ccids/ccid3.h | 4 ---- net/dccp/proto.c | 8 ++++---- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 72cc355d7a03..ed6cc8962d87 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -200,7 +200,7 @@ struct dccp_so_feat { }; /* DCCP socket options */ -#define DCCP_SOCKOPT_PACKET_SIZE 1 +#define DCCP_SOCKOPT_PACKET_SIZE 1 /* XXX deprecated, without effect */ #define DCCP_SOCKOPT_SERVICE 2 #define DCCP_SOCKOPT_CHANGE_L 3 #define DCCP_SOCKOPT_CHANGE_R 4 @@ -460,7 +460,6 @@ struct dccp_ackvec; * @dccps_service_list - second .. last service code on passive socket * @dccps_timestamp_time - time of latest TIMESTAMP option * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option - * @dccps_packet_size - Set thru setsockopt * @dccps_l_ack_ratio - * @dccps_r_ack_ratio - * @dccps_pcslen - sender partial checksum coverage (via sockopt) @@ -495,7 +494,6 @@ struct dccp_sock { struct dccp_service_list *dccps_service_list; struct timeval dccps_timestamp_time; __u32 dccps_timestamp_echo; - __u32 dccps_packet_size; __u16 dccps_l_ack_ratio; __u16 dccps_r_ack_ratio; __u16 dccps_pcslen; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 970921700ce3..dbb884426dfa 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -42,10 +42,6 @@ #include #include "../ccid.h" -#define TFRC_MIN_PACKET_SIZE 16 -#define TFRC_STD_PACKET_SIZE 256 -#define TFRC_MAX_PACKET_SIZE 65535 - /* Two seconds as per RFC 3448 4.2 */ #define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 3c44d502e5c1..2604e34d8f38 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -470,7 +470,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, lock_sock(sk); switch (optname) { case DCCP_SOCKOPT_PACKET_SIZE: - dp->dccps_packet_size = val; + DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n"); + err = -EINVAL; break; case DCCP_SOCKOPT_CHANGE_L: if (optlen != sizeof(struct dccp_so_feat)) @@ -581,9 +582,8 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case DCCP_SOCKOPT_PACKET_SIZE: - val = dp->dccps_packet_size; - len = sizeof(dp->dccps_packet_size); - break; + DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n"); + return -EINVAL; case DCCP_SOCKOPT_SERVICE: return dccp_getsockopt_service(sk, len, (__be32 __user *)optval, optlen); -- cgit v1.2.3-71-gd317 From d62f9ed4a490309bd9e5df0b42ba5d096e7b5902 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:17 +0100 Subject: [NETFILTER]: nf_conntrack: automatic sysctl registation for conntrack protocols Add helper functions for sysctl registration with optional instantiating of common path elements (like net/netfilter) and use it for support for automatic registation of conntrack protocol sysctls. Signed-off-by: Patrick McHardy --- include/linux/netfilter.h | 10 ++ include/net/netfilter/nf_conntrack_l3proto.h | 6 ++ include/net/netfilter/nf_conntrack_l4proto.h | 6 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_proto.c | 102 ++++++++++++++++++++ net/netfilter/nf_sysctl.c | 134 +++++++++++++++++++++++++++ 6 files changed, 259 insertions(+) create mode 100644 net/netfilter/nf_sysctl.c (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 6ab5e2d6133e..f6f3fcbd70ed 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -117,6 +117,16 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n); int nf_register_sockopt(struct nf_sockopt_ops *reg); void nf_unregister_sockopt(struct nf_sockopt_ops *reg); +#ifdef CONFIG_SYSCTL +/* Sysctl registration */ +struct ctl_table_header *nf_register_sysctl_table(struct ctl_table *path, + struct ctl_table *table); +void nf_unregister_sysctl_table(struct ctl_table_header *header, + struct ctl_table *table); +extern struct ctl_table nf_net_netfilter_sysctl_path[]; +extern struct ctl_table nf_net_ipv4_netfilter_sysctl_path[]; +#endif /* CONFIG_SYSCTL */ + extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; /* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index 6364df059422..664ddcffe00d 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -75,6 +75,12 @@ struct nf_conntrack_l3proto int (*nfattr_to_tuple)(struct nfattr *tb[], struct nf_conntrack_tuple *t); +#ifdef CONFIG_SYSCTL + struct ctl_table_header *ctl_table_header; + struct ctl_table *ctl_table_path; + struct ctl_table *ctl_table; +#endif /* CONFIG_SYSCTL */ + /* Module (if any) which this is connected to. */ struct module *me; }; diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index c22804aa227e..fe1e8fa30d2f 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -76,6 +76,12 @@ struct nf_conntrack_l4proto int (*nfattr_to_tuple)(struct nfattr *tb[], struct nf_conntrack_tuple *t); +#ifdef CONFIG_SYSCTL + struct ctl_table_header **ctl_table_header; + struct ctl_table *ctl_table; + unsigned int *ctl_table_users; +#endif /* CONFIG_SYSCTL */ + /* Module (if any) which this is connected to. */ struct module *me; }; diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 627105df1040..84d529ded952 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o obj-$(CONFIG_NETFILTER) = netfilter.o +obj-$(CONFIG_SYSCTL) += nf_sysctl.o obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index a6a3b1ddd00d..941b5c3754af 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,34 @@ struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; +#ifdef CONFIG_SYSCTL +static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex); + +static int +nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, + struct ctl_table *table, unsigned int *users) +{ + if (*header == NULL) { + *header = nf_register_sysctl_table(path, table); + if (*header == NULL) + return -ENOMEM; + } + if (users != NULL) + (*users)++; + return 0; +} + +static void +nf_ct_unregister_sysctl(struct ctl_table_header **header, + struct ctl_table *table, unsigned int *users) +{ + if (users != NULL && --*users > 0) + return; + nf_unregister_sysctl_table(*header, table); + *header = NULL; +} +#endif + struct nf_conntrack_l4proto * __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) { @@ -124,6 +153,33 @@ static int kill_l4proto(struct nf_conn *i, void *data) l4proto->l3proto); } +static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) +{ + int err = 0; + +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l3proto->ctl_table != NULL) { + err = nf_ct_register_sysctl(&l3proto->ctl_table_header, + l3proto->ctl_table_path, + l3proto->ctl_table, NULL); + } + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif + return err; +} + +static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) +{ +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l3proto->ctl_table_header != NULL) + nf_ct_unregister_sysctl(&l3proto->ctl_table_header, + l3proto->ctl_table, NULL); + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif +} + int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) { int ret = 0; @@ -139,6 +195,12 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) goto out_unlock; } nf_ct_l3protos[proto->l3proto] = proto; + write_unlock_bh(&nf_conntrack_lock); + + ret = nf_ct_l3proto_register_sysctl(proto); + if (ret < 0) + nf_conntrack_l3proto_unregister(proto); + return ret; out_unlock: write_unlock_bh(&nf_conntrack_lock); @@ -165,6 +227,8 @@ int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic; write_unlock_bh(&nf_conntrack_lock); + nf_ct_l3proto_unregister_sysctl(proto); + /* Somebody could be still looking at the proto in bh. */ synchronize_net(); @@ -175,6 +239,36 @@ out: return ret; } +static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) +{ + int err = 0; + +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l4proto->ctl_table != NULL) { + err = nf_ct_register_sysctl(l4proto->ctl_table_header, + nf_net_netfilter_sysctl_path, + l4proto->ctl_table, + l4proto->ctl_table_users); + } + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif + return err; +} + +static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) +{ +#ifdef CONFIG_SYSCTL + mutex_lock(&nf_ct_proto_sysctl_mutex); + if (l4proto->ctl_table_header != NULL && + *l4proto->ctl_table_header != NULL) + nf_ct_unregister_sysctl(l4proto->ctl_table_header, + l4proto->ctl_table, + l4proto->ctl_table_users); + mutex_unlock(&nf_ct_proto_sysctl_mutex); +#endif +} + /* FIXME: Allow NULL functions and sub in pointers to generic for them. --RR */ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) @@ -230,6 +324,12 @@ retry: } nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto; + write_unlock_bh(&nf_conntrack_lock); + + ret = nf_ct_l4proto_register_sysctl(l4proto); + if (ret < 0) + nf_conntrack_l4proto_unregister(l4proto); + return ret; out_unlock: write_unlock_bh(&nf_conntrack_lock); @@ -257,6 +357,8 @@ int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) = &nf_conntrack_l4proto_generic; write_unlock_bh(&nf_conntrack_lock); + nf_ct_l4proto_unregister_sysctl(l4proto); + /* Somebody could be still looking at the proto in bh. */ synchronize_net(); diff --git a/net/netfilter/nf_sysctl.c b/net/netfilter/nf_sysctl.c new file mode 100644 index 000000000000..06ddddb2911f --- /dev/null +++ b/net/netfilter/nf_sysctl.c @@ -0,0 +1,134 @@ +/* nf_sysctl.c netfilter sysctl registration/unregistation + * + * Copyright (c) 2006 Patrick McHardy + */ +#include +#include +#include +#include + +static void +path_free(struct ctl_table *path, struct ctl_table *table) +{ + struct ctl_table *t, *next; + + for (t = path; t != NULL && t != table; t = next) { + next = t->child; + kfree(t); + } +} + +static struct ctl_table * +path_dup(struct ctl_table *path, struct ctl_table *table) +{ + struct ctl_table *t, *last = NULL, *tmp; + + for (t = path; t != NULL; t = t->child) { + /* twice the size since path elements are terminated by an + * empty element */ + tmp = kmemdup(t, 2 * sizeof(*t), GFP_KERNEL); + if (tmp == NULL) { + if (last != NULL) + path_free(path, table); + return NULL; + } + + if (last != NULL) + last->child = tmp; + else + path = tmp; + last = tmp; + } + + if (last != NULL) + last->child = table; + else + path = table; + + return path; +} + +struct ctl_table_header * +nf_register_sysctl_table(struct ctl_table *path, struct ctl_table *table) +{ + struct ctl_table_header *header; + + path = path_dup(path, table); + if (path == NULL) + return NULL; + header = register_sysctl_table(path, 0); + if (header == NULL) + path_free(path, table); + return header; +} +EXPORT_SYMBOL_GPL(nf_register_sysctl_table); + +void +nf_unregister_sysctl_table(struct ctl_table_header *header, + struct ctl_table *table) +{ + struct ctl_table *path = header->ctl_table; + + unregister_sysctl_table(header); + path_free(path, table); +} +EXPORT_SYMBOL_GPL(nf_unregister_sysctl_table); + +/* net/netfilter */ +static struct ctl_table nf_net_netfilter_table[] = { + { + .ctl_name = NET_NETFILTER, + .procname = "netfilter", + .mode = 0555, + }, + { + .ctl_name = 0 + } +}; +struct ctl_table nf_net_netfilter_sysctl_path[] = { + { + .ctl_name = CTL_NET, + .procname = "net", + .mode = 0555, + .child = nf_net_netfilter_table, + }, + { + .ctl_name = 0 + } +}; +EXPORT_SYMBOL_GPL(nf_net_netfilter_sysctl_path); + +/* net/ipv4/netfilter */ +static struct ctl_table nf_net_ipv4_netfilter_table[] = { + { + .ctl_name = NET_IPV4_NETFILTER, + .procname = "netfilter", + .mode = 0555, + }, + { + .ctl_name = 0 + } +}; +static struct ctl_table nf_net_ipv4_table[] = { + { + .ctl_name = NET_IPV4, + .procname = "ipv4", + .mode = 0555, + .child = nf_net_ipv4_netfilter_table, + }, + { + .ctl_name = 0 + } +}; +struct ctl_table nf_net_ipv4_netfilter_sysctl_path[] = { + { + .ctl_name = CTL_NET, + .procname = "net", + .mode = 0555, + .child = nf_net_ipv4_table, + }, + { + .ctl_name = 0 + } +}; +EXPORT_SYMBOL_GPL(nf_net_ipv4_netfilter_sysctl_path); -- cgit v1.2.3-71-gd317 From 468ec44bd5a863736d955f78b8c38896f26864a1 Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Wed, 29 Nov 2006 02:35:23 +0100 Subject: [NETFILTER]: conntrack: add '_get' to {ip, nf}_conntrack_expect_find We usually uses 'xxx_find_get' for function which increments reference count. Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack.h | 2 +- include/net/netfilter/nf_conntrack_expect.h | 2 +- net/ipv4/netfilter/ip_conntrack_core.c | 2 +- net/ipv4/netfilter/ip_conntrack_helper_pptp.c | 4 ++-- net/ipv4/netfilter/ip_conntrack_netlink.c | 4 ++-- net/ipv4/netfilter/ip_conntrack_standalone.c | 2 +- net/ipv4/netfilter/ip_nat_helper_pptp.c | 2 +- net/netfilter/nf_conntrack_expect.c | 2 +- net/netfilter/nf_conntrack_netlink.c | 4 ++-- net/netfilter/nf_conntrack_standalone.c | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 64e868034c4a..61da56941dce 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -277,7 +277,7 @@ extern struct ip_conntrack_expect * __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_expect * -ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_tuple_hash * __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 5aa483e03455..2d335f024c85 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -53,7 +53,7 @@ struct nf_conntrack_expect * __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); struct nf_conntrack_expect * -nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); +nf_conntrack_expect_find_get(const struct nf_conntrack_tuple *tuple); struct nf_conntrack_expect * find_expectation(const struct nf_conntrack_tuple *tuple); diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 8b848aa77bfc..4d1f954d459b 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -233,7 +233,7 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) /* Just find a expectation corresponding to a tuple. */ struct ip_conntrack_expect * -ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) { struct ip_conntrack_expect *i; diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index a2af5e0c7f99..a5c057bcecf4 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -142,7 +142,7 @@ static void pptp_expectfn(struct ip_conntrack *ct, DEBUGP("trying to unexpect other dir: "); DUMP_TUPLE(&inv_t); - exp_other = ip_conntrack_expect_find(&inv_t); + exp_other = ip_conntrack_expect_find_get(&inv_t); if (exp_other) { /* delete other expectation. */ DEBUGP("found\n"); @@ -176,7 +176,7 @@ static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) ip_conntrack_put(sibling); return 1; } else { - exp = ip_conntrack_expect_find(t); + exp = ip_conntrack_expect_find_get(t); if (exp) { DEBUGP("unexpect_related of expect %p\n", exp); ip_conntrack_unexpect_related(exp); diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 1bb8ed33c5bc..3d277aa869dd 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -1256,7 +1256,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = ip_conntrack_expect_find(&tuple); + exp = ip_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; @@ -1309,7 +1309,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = ip_conntrack_expect_find(&tuple); + exp = ip_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 02135756562e..2df67538ffb0 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -926,7 +926,7 @@ EXPORT_SYMBOL(__ip_ct_refresh_acct); EXPORT_SYMBOL(ip_conntrack_expect_alloc); EXPORT_SYMBOL(ip_conntrack_expect_put); EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); -EXPORT_SYMBOL_GPL(ip_conntrack_expect_find); +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); EXPORT_SYMBOL(ip_conntrack_expect_related); EXPORT_SYMBOL(ip_conntrack_unexpect_related); EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index 329fdcd7d702..acf55d863100 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c @@ -101,7 +101,7 @@ static void pptp_nat_expected(struct ip_conntrack *ct, DEBUGP("trying to unexpect other dir: "); DUMP_TUPLE(&t); - other_exp = ip_conntrack_expect_find(&t); + other_exp = ip_conntrack_expect_find_get(&t); if (other_exp) { ip_conntrack_unexpect_related(other_exp); ip_conntrack_expect_put(other_exp); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 79cfd79a42f0..aa5903e4da11 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -68,7 +68,7 @@ __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) /* Just find a expectation corresponding to a tuple. */ struct nf_conntrack_expect * -nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) +nf_conntrack_expect_find_get(const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_expect *i; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index dc0830220130..7357b8f47acd 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1284,7 +1284,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = nf_conntrack_expect_find(&tuple); + exp = nf_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; @@ -1339,7 +1339,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = nf_conntrack_expect_find(&tuple); + exp = nf_conntrack_expect_find_get(&tuple); if (!exp) return -ENOENT; diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 3db24f4f0f5b..be94b6359725 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -549,7 +549,7 @@ EXPORT_SYMBOL(__nf_conntrack_find); EXPORT_SYMBOL(nf_ct_unlink_expect); EXPORT_SYMBOL(nf_conntrack_hash_insert); EXPORT_SYMBOL(__nf_conntrack_expect_find); -EXPORT_SYMBOL(nf_conntrack_expect_find); +EXPORT_SYMBOL(nf_conntrack_expect_find_get); EXPORT_SYMBOL(nf_conntrack_expect_list); #if defined(CONFIG_NF_CT_NETLINK) || \ defined(CONFIG_NF_CT_NETLINK_MODULE) -- cgit v1.2.3-71-gd317 From 9d5b8baa4e9ace9be113c6151aaeeb3c07a26fc8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:26 +0100 Subject: [NETFILTER]: sip conntrack: minor cleanup - Use enum for header field enumeration - Use numerical value instead of pointer to header info structure to identify headers, unexport ct_sip_hdrs - group SIP and SDP entries in header info structure - remove double forward declaration of ct_sip_get_info Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack_sip.h | 28 +++++------- net/ipv4/netfilter/ip_conntrack_sip.c | 60 +++++++++++++------------ net/ipv4/netfilter/ip_nat_sip.c | 30 ++++++------- 3 files changed, 55 insertions(+), 63 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h index 913dad66c0fb..2a15eb51fd6b 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h @@ -5,23 +5,15 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 -#define POS_VIA 0 -#define POS_CONTACT 1 -#define POS_CONTENT 2 -#define POS_MEDIA 3 -#define POS_OWNER 4 -#define POS_CONNECTION 5 -#define POS_REQ_HEADER 6 -#define POS_SDP_HEADER 7 - -struct sip_header_nfo { - const char *lname; - const char *sname; - const char *ln_str; - size_t lnlen; - size_t snlen; - size_t ln_strlen; - int (*match_len)(const char *, const char *, int *); +enum sip_header_pos { + POS_REQ_HEADER, + POS_VIA, + POS_CONTACT, + POS_CONTENT, + POS_MEDIA, + POS_OWNER, + POS_CONNECTION, + POS_SDP_HEADER, }; extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, @@ -36,7 +28,7 @@ extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, extern int ct_sip_get_info(const char *dptr, size_t dlen, unsigned int *matchoff, unsigned int *matchlen, - struct sip_header_nfo *hnfo); + enum sip_header_pos pos); extern int ct_sip_lnlen(const char *line, const char *limit); extern const char *ct_sip_search(const char *needle, const char *haystack, size_t needle_len, size_t haystack_len); diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index bf423db4ed46..cc3176581667 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -52,20 +52,32 @@ unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, const char *dptr); EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); -int ct_sip_get_info(const char *dptr, size_t dlen, - unsigned int *matchoff, - unsigned int *matchlen, - struct sip_header_nfo *hnfo); -EXPORT_SYMBOL_GPL(ct_sip_get_info); - - static int digits_len(const char *dptr, const char *limit, int *shift); static int epaddr_len(const char *dptr, const char *limit, int *shift); static int skp_digits_len(const char *dptr, const char *limit, int *shift); static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); -struct sip_header_nfo ct_sip_hdrs[] = { - { /* Via header */ +struct sip_header_nfo { + const char *lname; + const char *sname; + const char *ln_str; + size_t lnlen; + size_t snlen; + size_t ln_strlen; + int (*match_len)(const char *, const char *, int *); +}; + +static struct sip_header_nfo ct_sip_hdrs[] = { + [POS_REQ_HEADER] = { /* SIP Requests headers */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .sname = "sip:", + .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ + .ln_str = "@", + .ln_strlen = sizeof("@") - 1, + .match_len = epaddr_len + }, + [POS_VIA] = { /* SIP Via header */ .lname = "Via:", .lnlen = sizeof("Via:") - 1, .sname = "\r\nv:", @@ -74,7 +86,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("UDP ") - 1, .match_len = epaddr_len, }, - { /* Contact header */ + [POS_CONTACT] = { /* SIP Contact header */ .lname = "Contact:", .lnlen = sizeof("Contact:") - 1, .sname = "\r\nm:", @@ -83,7 +95,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("sip:") - 1, .match_len = skp_epaddr_len }, - { /* Content length header */ + [POS_CONTENT] = { /* SIP Content length header */ .lname = "Content-Length:", .lnlen = sizeof("Content-Length:") - 1, .sname = "\r\nl:", @@ -92,7 +104,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof(":") - 1, .match_len = skp_digits_len }, - { /* SDP media info */ + [POS_MEDIA] = { /* SDP media info */ .lname = "\nm=", .lnlen = sizeof("\nm=") - 1, .sname = "\rm=", @@ -101,7 +113,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("audio ") - 1, .match_len = digits_len }, - { /* SDP owner address*/ + [POS_OWNER] = { /* SDP owner address*/ .lname = "\no=", .lnlen = sizeof("\no=") - 1, .sname = "\ro=", @@ -110,7 +122,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("IN IP4 ") - 1, .match_len = epaddr_len }, - { /* SDP connection info */ + [POS_CONNECTION] = { /* SDP connection info */ .lname = "\nc=", .lnlen = sizeof("\nc=") - 1, .sname = "\rc=", @@ -119,16 +131,7 @@ struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof("IN IP4 ") - 1, .match_len = epaddr_len }, - { /* Requests headers */ - .lname = "sip:", - .lnlen = sizeof("sip:") - 1, - .sname = "sip:", - .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */ - .ln_str = "@", - .ln_strlen = sizeof("@") - 1, - .match_len = epaddr_len - }, - { /* SDP version header */ + [POS_SDP_HEADER] = { /* SDP version header */ .lname = "\nv=", .lnlen = sizeof("\nv=") - 1, .sname = "\rv=", @@ -138,7 +141,6 @@ struct sip_header_nfo ct_sip_hdrs[] = { .match_len = digits_len } }; -EXPORT_SYMBOL_GPL(ct_sip_hdrs); /* get line lenght until first CR or LF seen. */ int ct_sip_lnlen(const char *line, const char *limit) @@ -263,8 +265,9 @@ static int skp_epaddr_len(const char *dptr, const char *limit, int *shift) int ct_sip_get_info(const char *dptr, size_t dlen, unsigned int *matchoff, unsigned int *matchlen, - struct sip_header_nfo *hnfo) + enum sip_header_pos pos) { + struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; const char *limit, *aux, *k = dptr; int shift = 0; @@ -298,6 +301,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, DEBUGP("%s header not found.\n", hnfo->lname); return 0; } +EXPORT_SYMBOL_GPL(ct_sip_get_info); static int set_expected_rtp(struct sk_buff **pskb, struct ip_conntrack *ct, @@ -393,7 +397,7 @@ static int sip_help(struct sk_buff **pskb, } /* Get ip and port address from SDP packet. */ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, - &ct_sip_hdrs[POS_CONNECTION]) > 0) { + POS_CONNECTION) > 0) { /* We'll drop only if there are parse problems. */ if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, @@ -402,7 +406,7 @@ static int sip_help(struct sk_buff **pskb, goto out; } if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, - &ct_sip_hdrs[POS_MEDIA]) > 0) { + POS_MEDIA) > 0) { port = simple_strtoul(dptr + matchoff, NULL, 10); if (port < 1024) { diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 9fad98099532..47097aac63d8 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -29,18 +29,16 @@ MODULE_DESCRIPTION("SIP NAT helper"); #define DEBUGP(format, args...) #endif -extern struct sip_header_nfo ct_sip_hdrs[]; - static unsigned int mangle_sip_packet(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack *ct, const char **dptr, size_t dlen, char *buffer, int bufflen, - struct sip_header_nfo *hnfo) + enum sip_header_pos pos) { unsigned int matchlen, matchoff; - if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0) + if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 0; if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, @@ -80,14 +78,13 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, if ((ctinfo) < IP_CT_IS_REPLY) { mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, - &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); return 1; } if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + buffer, bufflen, POS_VIA)) return 0; /* This search should ignore case, but later.. */ @@ -102,25 +99,24 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, return mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, - &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); } if ((ctinfo) < IP_CT_IS_REPLY) { if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_VIA])) + buffer, bufflen, POS_VIA)) return 0; /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]); + buffer, bufflen, POS_CONTACT); return 1; } /* This mangle requests headers. */ return mangle_sip_packet(pskb, ctinfo, ct, dptr, ct_sip_lnlen(*dptr, *dptr + (*pskb)->len - dataoff), - buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]); + buffer, bufflen, POS_REQ_HEADER); } static int mangle_content_len(struct sk_buff **pskb, @@ -136,7 +132,7 @@ static int mangle_content_len(struct sk_buff **pskb, /* Get actual SDP lenght */ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, - &matchlen, &ct_sip_hdrs[POS_SDP_HEADER]) > 0) { + &matchlen, POS_SDP_HEADER) > 0) { /* since ct_sip_get_info() give us a pointer passing 'v=' we need to add 2 bytes in this count. */ @@ -144,7 +140,7 @@ static int mangle_content_len(struct sk_buff **pskb, /* Now, update SDP lenght */ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, - &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) { + &matchlen, POS_CONTENT) > 0) { bufflen = sprintf(buffer, "%u", c_len); @@ -170,17 +166,17 @@ static unsigned int mangle_sdp(struct sk_buff **pskb, /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_OWNER])) + buffer, bufflen, POS_OWNER)) return 0; if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_CONNECTION])) + buffer, bufflen, POS_CONNECTION)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, - buffer, bufflen, &ct_sip_hdrs[POS_MEDIA])) + buffer, bufflen, POS_MEDIA)) return 0; return mangle_content_len(pskb, ctinfo, ct, dptr); -- cgit v1.2.3-71-gd317 From 40883e8184947879f135605a05c0764c60656cc5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:27 +0100 Subject: [NETFILTER]: sip conntrack: do case insensitive SIP header search SIP headers are generally case-insensitive, only SDP headers are case sensitive. Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack_sip.h | 3 ++- net/ipv4/netfilter/ip_conntrack_sip.c | 20 ++++++++++++++++---- net/ipv4/netfilter/ip_nat_sip.c | 7 ++++--- 3 files changed, 22 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h index 2a15eb51fd6b..51c65ac18c57 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h @@ -31,6 +31,7 @@ extern int ct_sip_get_info(const char *dptr, size_t dlen, enum sip_header_pos pos); extern int ct_sip_lnlen(const char *line, const char *limit); extern const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len); + size_t needle_len, size_t haystack_len, + int case_sensitive); #endif /* __KERNEL__ */ #endif /* __IP_CONNTRACK_SIP_H__ */ diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index cc3176581667..a9c0d1d3e56f 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -64,6 +64,7 @@ struct sip_header_nfo { size_t lnlen; size_t snlen; size_t ln_strlen; + int case_sensitive; int (*match_len)(const char *, const char *, int *); }; @@ -105,6 +106,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = skp_digits_len }, [POS_MEDIA] = { /* SDP media info */ + .case_sensitive = 1, .lname = "\nm=", .lnlen = sizeof("\nm=") - 1, .sname = "\rm=", @@ -114,6 +116,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = digits_len }, [POS_OWNER] = { /* SDP owner address*/ + .case_sensitive = 1, .lname = "\no=", .lnlen = sizeof("\no=") - 1, .sname = "\ro=", @@ -123,6 +126,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = epaddr_len }, [POS_CONNECTION] = { /* SDP connection info */ + .case_sensitive = 1, .lname = "\nc=", .lnlen = sizeof("\nc=") - 1, .sname = "\rc=", @@ -132,6 +136,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = { .match_len = epaddr_len }, [POS_SDP_HEADER] = { /* SDP version header */ + .case_sensitive = 1, .lname = "\nv=", .lnlen = sizeof("\nv=") - 1, .sname = "\rv=", @@ -161,13 +166,19 @@ EXPORT_SYMBOL_GPL(ct_sip_lnlen); /* Linear string search, case sensitive. */ const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len) + size_t needle_len, size_t haystack_len, + int case_sensitive) { const char *limit = haystack + (haystack_len - needle_len); while (haystack <= limit) { - if (memcmp(haystack, needle, needle_len) == 0) - return haystack; + if (case_sensitive) { + if (strncmp(haystack, needle, needle_len) == 0) + return haystack; + } else { + if (strnicmp(haystack, needle, needle_len) == 0) + return haystack; + } haystack++; } return NULL; @@ -280,7 +291,8 @@ int ct_sip_get_info(const char *dptr, size_t dlen, continue; } aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, - ct_sip_lnlen(dptr, limit)); + ct_sip_lnlen(dptr, limit), + hnfo->case_sensitive); if (!aux) { DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, hnfo->lname); diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index 47097aac63d8..e16604c4339d 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -87,14 +87,15 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, buffer, bufflen, POS_VIA)) return 0; - /* This search should ignore case, but later.. */ aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, - (*pskb)->len - dataoff); + (*pskb)->len - dataoff, 0); if (!aux) return 0; if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), - ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff))) + ct_sip_lnlen(aux, + *dptr + (*pskb)->len - dataoff), + 1)) return 1; return mangle_sip_packet(pskb, ctinfo, ct, dptr, -- cgit v1.2.3-71-gd317 From 1b683b551209ca46ae59b29572018001db5af078 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:30 +0100 Subject: [NETFILTER]: sip conntrack: better NAT handling The NAT handling of the SIP helper has a few problems: - Request headers are only mangled in the reply direction, From/To headers not at all, which can lead to authentication failures with DNAT in case the authentication domain is the IP address - Contact headers in responses are only mangled for REGISTER responses - Headers may be mangled even though they contain addresses not participating in the connection, like alternative addresses - Packets are droppen when domain names are used where the helper expects IP addresses This patch takes a different approach, instead of fixed rules what field to mangle to what content, it adds symetric mapping of From/To/Via/Contact headers, which allows to deal properly with echoed addresses in responses and foreign addresses not belonging to the connection. Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4/ip_conntrack_sip.h | 5 +- net/ipv4/netfilter/ip_conntrack_sip.c | 29 +++- net/ipv4/netfilter/ip_nat_sip.c | 171 ++++++++++++++---------- 3 files changed, 135 insertions(+), 70 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h index 51c65ac18c57..bef6c646defa 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h @@ -6,7 +6,10 @@ #define SIP_TIMEOUT 3600 enum sip_header_pos { - POS_REQ_HEADER, + POS_REG_REQ_URI, + POS_REQ_URI, + POS_FROM, + POS_TO, POS_VIA, POS_CONTACT, POS_CONTENT, diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index 0a6a13c45b07..3a26d63eed88 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -69,13 +69,38 @@ struct sip_header_nfo { }; static struct sip_header_nfo ct_sip_hdrs[] = { - [POS_REQ_HEADER] = { /* SIP Requests headers */ + [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .ln_str = ":", + .ln_strlen = sizeof(":") - 1, + .match_len = epaddr_len + }, + [POS_REQ_URI] = { /* SIP request URI */ .lname = "sip:", .lnlen = sizeof("sip:") - 1, .ln_str = "@", .ln_strlen = sizeof("@") - 1, .match_len = epaddr_len }, + [POS_FROM] = { /* SIP From header */ + .lname = "From:", + .lnlen = sizeof("From:") - 1, + .sname = "\r\nf:", + .snlen = sizeof("\r\nf:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, + [POS_TO] = { /* SIP To header */ + .lname = "To:", + .lnlen = sizeof("To:") - 1, + .sname = "\r\nt:", + .snlen = sizeof("\r\nt:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, [POS_VIA] = { /* SIP Via header */ .lname = "Via:", .lnlen = sizeof("Via:") - 1, @@ -284,7 +309,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen, while (dptr <= limit) { if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && - (hinfo->sname == NULL || + (hnfo->sname == NULL || strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { dptr++; continue; diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c index e16604c4339d..6223abc924ff 100644 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ b/net/ipv4/netfilter/ip_nat_sip.c @@ -29,25 +29,70 @@ MODULE_DESCRIPTION("SIP NAT helper"); #define DEBUGP(format, args...) #endif -static unsigned int mangle_sip_packet(struct sk_buff **pskb, - enum ip_conntrack_info ctinfo, - struct ip_conntrack *ct, - const char **dptr, size_t dlen, - char *buffer, int bufflen, - enum sip_header_pos pos) +struct addr_map { + struct { + char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int srclen, srciplen; + unsigned int dstlen, dstiplen; + } addr[IP_CT_DIR_MAX]; +}; + +static void addr_map_init(struct ip_conntrack *ct, struct addr_map *map) { - unsigned int matchlen, matchoff; + struct ip_conntrack_tuple *t; + enum ip_conntrack_dir dir; + unsigned int n; + + for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { + t = &ct->tuplehash[dir].tuple; + + n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", + NIPQUAD(t->src.ip)); + map->addr[dir].srciplen = n; + n += sprintf(map->addr[dir].src + n, ":%u", + ntohs(t->src.u.udp.port)); + map->addr[dir].srclen = n; + + n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", + NIPQUAD(t->dst.ip)); + map->addr[dir].dstiplen = n; + n += sprintf(map->addr[dir].dst + n, ":%u", + ntohs(t->dst.u.udp.port)); + map->addr[dir].dstlen = n; + } +} + +static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, const char **dptr, size_t dlen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned int matchlen, matchoff, addrlen; + char *addr; if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) - return 0; + return 1; + + if ((matchlen == map->addr[dir].srciplen || + matchlen == map->addr[dir].srclen) && + memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { + addr = map->addr[!dir].dst; + addrlen = map->addr[!dir].dstlen; + } else if ((matchlen == map->addr[dir].dstiplen || + matchlen == map->addr[dir].dstlen) && + memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { + addr = map->addr[!dir].src; + addrlen = map->addr[!dir].srclen; + } else + return 1; if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, - matchoff, matchlen, buffer, bufflen)) + matchoff, matchlen, addr, addrlen)) return 0; - - /* We need to reload this. Thanks Patrick. */ *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); return 1; + } static unsigned int ip_nat_sip(struct sk_buff **pskb, @@ -55,69 +100,61 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb, struct ip_conntrack *ct, const char **dptr) { - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; - unsigned int bufflen, dataoff; - __be32 ip; - __be16 port; + enum sip_header_pos pos; + struct addr_map map; + int dataoff, datalen; dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0") - 1) + return NF_DROP; + + addr_map_init(ct, &map); + + /* Basic rules: requests and responses. */ + if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { + /* 10.2: Constructing the REGISTER Request: + * + * The "userinfo" and "@" components of the SIP URI MUST NOT + * be present. + */ + if (datalen >= sizeof("REGISTER") - 1 && + strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) + pos = POS_REG_REQ_URI; + else + pos = POS_REQ_URI; + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) + return NF_DROP; + } - ip = ct->tuplehash[!dir].tuple.dst.ip; - port = ct->tuplehash[!dir].tuple.dst.u.udp.port; - bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port)); + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + return NF_DROP; + return NF_ACCEPT; +} + +static unsigned int mangle_sip_packet(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack *ct, + const char **dptr, size_t dlen, + char *buffer, int bufflen, + enum sip_header_pos pos) +{ + unsigned int matchlen, matchoff; - /* short packet ? */ - if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1)) + if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 0; - /* Basic rules: requests and responses. */ - if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) { - const char *aux; - - if ((ctinfo) < IP_CT_IS_REPLY) { - mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - return 1; - } + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, buffer, bufflen)) + return 0; - if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_VIA)) - return 0; - - aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, - (*pskb)->len - dataoff, 0); - if (!aux) - return 0; - - if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), - ct_sip_lnlen(aux, - *dptr + (*pskb)->len - dataoff), - 1)) - return 1; - - return mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - } - if ((ctinfo) < IP_CT_IS_REPLY) { - if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, - (*pskb)->len - dataoff, - buffer, bufflen, POS_VIA)) - return 0; - - /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ - mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, - buffer, bufflen, POS_CONTACT); - return 1; - } - /* This mangle requests headers. */ - return mangle_sip_packet(pskb, ctinfo, ct, dptr, - ct_sip_lnlen(*dptr, - *dptr + (*pskb)->len - dataoff), - buffer, bufflen, POS_REQ_HEADER); + /* We need to reload this. Thanks Patrick. */ + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; } static int mangle_content_len(struct sk_buff **pskb, -- cgit v1.2.3-71-gd317 From 829e17a1a602572ffa3beefe582dc103ee9fb9c7 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 29 Nov 2006 02:35:33 +0100 Subject: [NETFILTER]: nfnetlink_queue: allow changing queue length through netlink Signed-off-by: Eric Leblond Signed-off-by: Patrick McHardy --- include/linux/netfilter/nfnetlink_queue.h | 1 + net/netfilter/nfnetlink_queue.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h index 4beea3d6fda8..83e789633e35 100644 --- a/include/linux/netfilter/nfnetlink_queue.h +++ b/include/linux/netfilter/nfnetlink_queue.h @@ -82,6 +82,7 @@ enum nfqnl_attr_config { NFQA_CFG_UNSPEC, NFQA_CFG_CMD, /* nfqnl_msg_config_cmd */ NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */ + NFQA_CFG_QUEUE_MAXLEN, /* u_int32_t */ __NFQA_CFG_MAX }; #define NFQA_CFG_MAX (__NFQA_CFG_MAX-1) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 82e4454659bf..a88a017da22c 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -947,6 +947,14 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ntohl(params->copy_range)); } + if (nfqa[NFQA_CFG_QUEUE_MAXLEN-1]) { + __be32 *queue_maxlen; + queue_maxlen = NFA_DATA(nfqa[NFQA_CFG_QUEUE_MAXLEN-1]); + spin_lock_bh(&queue->lock); + queue->queue_maxlen = ntohl(*queue_maxlen); + spin_unlock_bh(&queue->lock); + } + out_put: instance_put(queue); return ret; -- cgit v1.2.3-71-gd317 From d7a5c32442ed3d528b9ddfd3d5b837bad0ffa9da Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:34 +0100 Subject: [NETFILTER]: nfnetlink_log: remove useless prefix length limitation There is no reason for limiting netlink attributes in size. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nfnetlink_log.h | 2 -- net/netfilter/nfnetlink_log.c | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h index 55a2a2b814ed..5966afa026e9 100644 --- a/include/linux/netfilter/nfnetlink_log.h +++ b/include/linux/netfilter/nfnetlink_log.h @@ -32,8 +32,6 @@ struct nfulnl_msg_packet_timestamp { aligned_be64 usec; }; -#define NFULNL_PREFIXLEN 30 /* just like old log target */ - enum nfulnl_attr_type { NFULA_UNSPEC, NFULA_PACKET_HDR, diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index bd3ffa6f1a6d..d1505dd25c66 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -408,7 +408,7 @@ __build_packet_message(struct nfulnl_instance *inst, const struct net_device *indev, const struct net_device *outdev, const struct nf_loginfo *li, - const char *prefix) + const char *prefix, unsigned int plen) { unsigned char *old_tail; struct nfulnl_msg_packet_hdr pmsg; @@ -432,12 +432,8 @@ __build_packet_message(struct nfulnl_instance *inst, NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); - if (prefix) { - int slen = strlen(prefix); - if (slen > NFULNL_PREFIXLEN) - slen = NFULNL_PREFIXLEN; - NFA_PUT(inst->skb, NFULA_PREFIX, slen, prefix); - } + if (prefix) + NFA_PUT(inst->skb, NFULA_PREFIX, plen, prefix); if (indev) { tmp_uint = htonl(indev->ifindex); @@ -601,6 +597,7 @@ nfulnl_log_packet(unsigned int pf, const struct nf_loginfo *li; unsigned int qthreshold; unsigned int nlbufsiz; + unsigned int plen; if (li_user && li_user->type == NF_LOG_TYPE_ULOG) li = li_user; @@ -616,6 +613,10 @@ nfulnl_log_packet(unsigned int pf, return; } + plen = 0; + if (prefix) + plen = strlen(prefix); + /* all macros expand to constant values at compile time */ /* FIXME: do we want to make the size calculation conditional based on * what is actually present? way more branches and checks, but more @@ -630,7 +631,7 @@ nfulnl_log_packet(unsigned int pf, #endif + NFA_SPACE(sizeof(u_int32_t)) /* mark */ + NFA_SPACE(sizeof(u_int32_t)) /* uid */ - + NFA_SPACE(NFULNL_PREFIXLEN) /* prefix */ + + NFA_SPACE(plen) /* prefix */ + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hw)) + NFA_SPACE(sizeof(struct nfulnl_msg_packet_timestamp)); @@ -701,7 +702,7 @@ nfulnl_log_packet(unsigned int pf, inst->qlen++; __build_packet_message(inst, skb, data_len, pf, - hooknum, in, out, li, prefix); + hooknum, in, out, li, prefix, plen); /* timer_pending always called within inst->lock, so there * is no chance of a race here */ -- cgit v1.2.3-71-gd317 From 39b46fc6f0d1161a5585cd8af7b3a05e8118ab7e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:36 +0100 Subject: [NETFILTER]: x_tables: add port of hashlimit match for IPv4 and IPv6 Signed-off-by: Patrick McHardy --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/xt_hashlimit.h | 40 ++ include/linux/netfilter_ipv4/ipt_hashlimit.h | 42 +- net/ipv4/netfilter/Kconfig | 14 - net/ipv4/netfilter/Makefile | 1 - net/ipv4/netfilter/ipt_hashlimit.c | 733 ------------------------- net/netfilter/Kconfig | 14 + net/netfilter/Makefile | 1 + net/netfilter/xt_hashlimit.c | 772 +++++++++++++++++++++++++++ 9 files changed, 836 insertions(+), 782 deletions(-) create mode 100644 include/linux/netfilter/xt_hashlimit.h delete mode 100644 net/ipv4/netfilter/ipt_hashlimit.c create mode 100644 net/netfilter/xt_hashlimit.c (limited to 'include/linux') diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 312bd2ffee33..e379a2d89ea0 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -14,6 +14,7 @@ header-y += xt_dscp.h header-y += xt_DSCP.h header-y += xt_esp.h header-y += xt_helper.h +header-y += xt_hashlimit.h header-y += xt_length.h header-y += xt_limit.h header-y += xt_mac.h diff --git a/include/linux/netfilter/xt_hashlimit.h b/include/linux/netfilter/xt_hashlimit.h new file mode 100644 index 000000000000..b4556b8edbfd --- /dev/null +++ b/include/linux/netfilter/xt_hashlimit.h @@ -0,0 +1,40 @@ +#ifndef _XT_HASHLIMIT_H +#define _XT_HASHLIMIT_H + +/* timings are in milliseconds. */ +#define XT_HASHLIMIT_SCALE 10000 +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 + seconds, or one every 59 hours. */ + +/* details of this structure hidden by the implementation */ +struct xt_hashlimit_htable; + +#define XT_HASHLIMIT_HASH_DIP 0x0001 +#define XT_HASHLIMIT_HASH_DPT 0x0002 +#define XT_HASHLIMIT_HASH_SIP 0x0004 +#define XT_HASHLIMIT_HASH_SPT 0x0008 + +struct hashlimit_cfg { + u_int32_t mode; /* bitmask of IPT_HASHLIMIT_HASH_* */ + u_int32_t avg; /* Average secs between packets * scale */ + u_int32_t burst; /* Period multiplier for upper limit. */ + + /* user specified */ + u_int32_t size; /* how many buckets */ + u_int32_t max; /* max number of entries */ + u_int32_t gc_interval; /* gc interval */ + u_int32_t expire; /* when do entries expire? */ +}; + +struct xt_hashlimit_info { + char name [IFNAMSIZ]; /* name */ + struct hashlimit_cfg cfg; + struct xt_hashlimit_htable *hinfo; + + /* Used internally by the kernel */ + union { + void *ptr; + struct xt_hashlimit_info *master; + } u; +}; +#endif /*_XT_HASHLIMIT_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_hashlimit.h b/include/linux/netfilter_ipv4/ipt_hashlimit.h index ac2cb64ecd76..5662120a3d7b 100644 --- a/include/linux/netfilter_ipv4/ipt_hashlimit.h +++ b/include/linux/netfilter_ipv4/ipt_hashlimit.h @@ -1,40 +1,14 @@ #ifndef _IPT_HASHLIMIT_H #define _IPT_HASHLIMIT_H -/* timings are in milliseconds. */ -#define IPT_HASHLIMIT_SCALE 10000 -/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 - seconds, or one every 59 hours. */ +#include -/* details of this structure hidden by the implementation */ -struct ipt_hashlimit_htable; +#define IPT_HASHLIMIT_SCALE XT_HASHLIMIT_SCALE +#define IPT_HASHLIMIT_HASH_DIP XT_HASHLIMIT_HASH_DIP +#define IPT_HASHLIMIT_HASH_DPT XT_HASHLIMIT_HASH_DPT +#define IPT_HASHLIMIT_HASH_SIP XT_HASHLIMIT_HASH_SIP +#define IPT_HASHLIMIT_HASH_SPT XT_HASHLIMIT_HASH_SPT -#define IPT_HASHLIMIT_HASH_DIP 0x0001 -#define IPT_HASHLIMIT_HASH_DPT 0x0002 -#define IPT_HASHLIMIT_HASH_SIP 0x0004 -#define IPT_HASHLIMIT_HASH_SPT 0x0008 +#define ipt_hashlimit_info xt_hashlimit_info -struct hashlimit_cfg { - u_int32_t mode; /* bitmask of IPT_HASHLIMIT_HASH_* */ - u_int32_t avg; /* Average secs between packets * scale */ - u_int32_t burst; /* Period multiplier for upper limit. */ - - /* user specified */ - u_int32_t size; /* how many buckets */ - u_int32_t max; /* max number of entries */ - u_int32_t gc_interval; /* gc interval */ - u_int32_t expire; /* when do entries expire? */ -}; - -struct ipt_hashlimit_info { - char name [IFNAMSIZ]; /* name */ - struct hashlimit_cfg cfg; - struct ipt_hashlimit_htable *hinfo; - - /* Used internally by the kernel */ - union { - void *ptr; - struct ipt_hashlimit_info *master; - } u; -}; -#endif /*_IPT_HASHLIMIT_H*/ +#endif /* _IPT_HASHLIMIT_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 4ac5b5c4678d..bc298a3f236f 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -326,20 +326,6 @@ config IP_NF_MATCH_ADDRTYPE If you want to compile it as a module, say M here and read . If unsure, say `N'. -config IP_NF_MATCH_HASHLIMIT - tristate 'hashlimit match support' - depends on IP_NF_IPTABLES - help - This option adds a new iptables `hashlimit' match. - - As opposed to `limit', this match dynamically creates a hash table - of limit buckets, based on your selection of source/destination - ip addresses and/or ports. - - It enables you to express policies like `10kpps for any given - destination IP' or `500pps from any given source IP' with a single - IPtables rule. - # `filter', generic and specific targets config IP_NF_FILTER tristate "Packet filtering" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 4ce20ebc4d6c..21359d83f0c7 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -53,7 +53,6 @@ obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o # matches -obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c deleted file mode 100644 index 33ccdbf8e794..000000000000 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ /dev/null @@ -1,733 +0,0 @@ -/* iptables match extension to limit the number of packets per second - * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) - * - * (C) 2003-2004 by Harald Welte - * - * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $ - * - * Development of this code was funded by Astaro AG, http://www.astaro.com/ - * - * based on ipt_limit.c by: - * Jérôme de Vivie - * Hervé Eychenne - * Rusty Russell - * - * The general idea is to create a hash table for every dstip and have a - * seperate limit counter per tuple. This way you can do something like 'limit - * the number of syn packets for each of my internal addresses. - * - * Ideally this would just be implemented as a general 'hash' match, which would - * allow us to attach any iptables target to it's hash buckets. But this is - * not possible in the current iptables architecture. As always, pkttables for - * 2.7.x will help ;) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* FIXME: this is just for IP_NF_ASSERRT */ -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Harald Welte "); -MODULE_DESCRIPTION("iptables match for limiting per hash-bucket"); - -/* need to declare this at the top */ -static struct proc_dir_entry *hashlimit_procdir; -static struct file_operations dl_file_ops; - -/* hash table crap */ - -struct dsthash_dst { - __be32 src_ip; - __be32 dst_ip; - /* ports have to be consecutive !!! */ - __be16 src_port; - __be16 dst_port; -}; - -struct dsthash_ent { - /* static / read-only parts in the beginning */ - struct hlist_node node; - struct dsthash_dst dst; - - /* modified structure members in the end */ - unsigned long expires; /* precalculated expiry time */ - struct { - unsigned long prev; /* last modification */ - u_int32_t credit; - u_int32_t credit_cap, cost; - } rateinfo; -}; - -struct ipt_hashlimit_htable { - struct hlist_node node; /* global list of all htables */ - atomic_t use; - - struct hashlimit_cfg cfg; /* config */ - - /* used internally */ - spinlock_t lock; /* lock for list_head */ - u_int32_t rnd; /* random seed for hash */ - int rnd_initialized; - struct timer_list timer; /* timer for gc */ - atomic_t count; /* number entries in table */ - - /* seq_file stuff */ - struct proc_dir_entry *pde; - - struct hlist_head hash[0]; /* hashtable itself */ -}; - -static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ -static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ -static HLIST_HEAD(hashlimit_htables); -static kmem_cache_t *hashlimit_cachep __read_mostly; - -static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) -{ - return (ent->dst.dst_ip == b->dst_ip - && ent->dst.dst_port == b->dst_port - && ent->dst.src_port == b->src_port - && ent->dst.src_ip == b->src_ip); -} - -static inline u_int32_t -hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst) -{ - return (jhash_3words((__force u32)dst->dst_ip, - ((__force u32)dst->dst_port<<16 | - (__force u32)dst->src_port), - (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size); -} - -static inline struct dsthash_ent * -__dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) -{ - struct dsthash_ent *ent; - struct hlist_node *pos; - u_int32_t hash = hash_dst(ht, dst); - - if (!hlist_empty(&ht->hash[hash])) - hlist_for_each_entry(ent, pos, &ht->hash[hash], node) { - if (dst_cmp(ent, dst)) { - return ent; - } - } - - return NULL; -} - -/* allocate dsthash_ent, initialize dst, put in htable and lock it */ -static struct dsthash_ent * -__dsthash_alloc_init(struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst) -{ - struct dsthash_ent *ent; - - /* initialize hash with random val at the time we allocate - * the first hashtable entry */ - if (!ht->rnd_initialized) { - get_random_bytes(&ht->rnd, 4); - ht->rnd_initialized = 1; - } - - if (ht->cfg.max && - atomic_read(&ht->count) >= ht->cfg.max) { - /* FIXME: do something. question is what.. */ - if (net_ratelimit()) - printk(KERN_WARNING - "ipt_hashlimit: max count of %u reached\n", - ht->cfg.max); - return NULL; - } - - ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); - if (!ent) { - if (net_ratelimit()) - printk(KERN_ERR - "ipt_hashlimit: can't allocate dsthash_ent\n"); - return NULL; - } - - atomic_inc(&ht->count); - - ent->dst.dst_ip = dst->dst_ip; - ent->dst.dst_port = dst->dst_port; - ent->dst.src_ip = dst->src_ip; - ent->dst.src_port = dst->src_port; - - hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]); - - return ent; -} - -static inline void -__dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent) -{ - hlist_del(&ent->node); - kmem_cache_free(hashlimit_cachep, ent); - atomic_dec(&ht->count); -} -static void htable_gc(unsigned long htlong); - -static int htable_create(struct ipt_hashlimit_info *minfo) -{ - int i; - unsigned int size; - struct ipt_hashlimit_htable *hinfo; - - if (minfo->cfg.size) - size = minfo->cfg.size; - else { - size = (((num_physpages << PAGE_SHIFT) / 16384) - / sizeof(struct list_head)); - if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) - size = 8192; - if (size < 16) - size = 16; - } - /* FIXME: don't use vmalloc() here or anywhere else -HW */ - hinfo = vmalloc(sizeof(struct ipt_hashlimit_htable) - + (sizeof(struct list_head) * size)); - if (!hinfo) { - printk(KERN_ERR "ipt_hashlimit: Unable to create hashtable\n"); - return -1; - } - minfo->hinfo = hinfo; - - /* copy match config into hashtable config */ - memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); - hinfo->cfg.size = size; - if (!hinfo->cfg.max) - hinfo->cfg.max = 8 * hinfo->cfg.size; - else if (hinfo->cfg.max < hinfo->cfg.size) - hinfo->cfg.max = hinfo->cfg.size; - - for (i = 0; i < hinfo->cfg.size; i++) - INIT_HLIST_HEAD(&hinfo->hash[i]); - - atomic_set(&hinfo->count, 0); - atomic_set(&hinfo->use, 1); - hinfo->rnd_initialized = 0; - spin_lock_init(&hinfo->lock); - hinfo->pde = create_proc_entry(minfo->name, 0, hashlimit_procdir); - if (!hinfo->pde) { - vfree(hinfo); - return -1; - } - hinfo->pde->proc_fops = &dl_file_ops; - hinfo->pde->data = hinfo; - - init_timer(&hinfo->timer); - hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); - hinfo->timer.data = (unsigned long )hinfo; - hinfo->timer.function = htable_gc; - add_timer(&hinfo->timer); - - spin_lock_bh(&hashlimit_lock); - hlist_add_head(&hinfo->node, &hashlimit_htables); - spin_unlock_bh(&hashlimit_lock); - - return 0; -} - -static int select_all(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) -{ - return 1; -} - -static int select_gc(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he) -{ - return (jiffies >= he->expires); -} - -static void htable_selective_cleanup(struct ipt_hashlimit_htable *ht, - int (*select)(struct ipt_hashlimit_htable *ht, - struct dsthash_ent *he)) -{ - int i; - - IP_NF_ASSERT(ht->cfg.size && ht->cfg.max); - - /* lock hash table and iterate over it */ - spin_lock_bh(&ht->lock); - for (i = 0; i < ht->cfg.size; i++) { - struct dsthash_ent *dh; - struct hlist_node *pos, *n; - hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) { - if ((*select)(ht, dh)) - __dsthash_free(ht, dh); - } - } - spin_unlock_bh(&ht->lock); -} - -/* hash table garbage collector, run by timer */ -static void htable_gc(unsigned long htlong) -{ - struct ipt_hashlimit_htable *ht = (struct ipt_hashlimit_htable *)htlong; - - htable_selective_cleanup(ht, select_gc); - - /* re-add the timer accordingly */ - ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); - add_timer(&ht->timer); -} - -static void htable_destroy(struct ipt_hashlimit_htable *hinfo) -{ - /* remove timer, if it is pending */ - if (timer_pending(&hinfo->timer)) - del_timer(&hinfo->timer); - - /* remove proc entry */ - remove_proc_entry(hinfo->pde->name, hashlimit_procdir); - - htable_selective_cleanup(hinfo, select_all); - vfree(hinfo); -} - -static struct ipt_hashlimit_htable *htable_find_get(char *name) -{ - struct ipt_hashlimit_htable *hinfo; - struct hlist_node *pos; - - spin_lock_bh(&hashlimit_lock); - hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { - if (!strcmp(name, hinfo->pde->name)) { - atomic_inc(&hinfo->use); - spin_unlock_bh(&hashlimit_lock); - return hinfo; - } - } - spin_unlock_bh(&hashlimit_lock); - - return NULL; -} - -static void htable_put(struct ipt_hashlimit_htable *hinfo) -{ - if (atomic_dec_and_test(&hinfo->use)) { - spin_lock_bh(&hashlimit_lock); - hlist_del(&hinfo->node); - spin_unlock_bh(&hashlimit_lock); - htable_destroy(hinfo); - } -} - - -/* The algorithm used is the Simple Token Bucket Filter (TBF) - * see net/sched/sch_tbf.c in the linux source tree - */ - -/* Rusty: This is my (non-mathematically-inclined) understanding of - this algorithm. The `average rate' in jiffies becomes your initial - amount of credit `credit' and the most credit you can ever have - `credit_cap'. The `peak rate' becomes the cost of passing the - test, `cost'. - - `prev' tracks the last packet hit: you gain one credit per jiffy. - If you get credit balance more than this, the extra credit is - discarded. Every time the match passes, you lose `cost' credits; - if you don't have that many, the test fails. - - See Alexey's formal explanation in net/sched/sch_tbf.c. - - To get the maximum range, we multiply by this factor (ie. you get N - credits per jiffy). We want to allow a rate as low as 1 per day - (slowest userspace tool allows), which means - CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. -*/ -#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) - -/* Repeated shift and or gives us all 1s, final shift and add 1 gives - * us the power of 2 below the theoretical max, so GCC simply does a - * shift. */ -#define _POW2_BELOW2(x) ((x)|((x)>>1)) -#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) -#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) -#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) -#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) -#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) - -#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) - -/* Precision saver. */ -static inline u_int32_t -user2credits(u_int32_t user) -{ - /* If multiplying would overflow... */ - if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) - /* Divide first. */ - return (user / IPT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; - - return (user * HZ * CREDITS_PER_JIFFY) / IPT_HASHLIMIT_SCALE; -} - -static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) -{ - dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) - * CREDITS_PER_JIFFY; - if (dh->rateinfo.credit > dh->rateinfo.credit_cap) - dh->rateinfo.credit = dh->rateinfo.credit_cap; -} - -static int -hashlimit_match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct xt_match *match, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - struct ipt_hashlimit_info *r = - ((struct ipt_hashlimit_info *)matchinfo)->u.master; - struct ipt_hashlimit_htable *hinfo = r->hinfo; - unsigned long now = jiffies; - struct dsthash_ent *dh; - struct dsthash_dst dst; - - /* build 'dst' according to hinfo->cfg and current packet */ - memset(&dst, 0, sizeof(dst)); - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DIP) - dst.dst_ip = skb->nh.iph->daddr; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SIP) - dst.src_ip = skb->nh.iph->saddr; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT - ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) { - __be16 _ports[2], *ports; - - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_SCTP: - case IPPROTO_DCCP: - ports = skb_header_pointer(skb, skb->nh.iph->ihl*4, - sizeof(_ports), &_ports); - break; - default: - _ports[0] = _ports[1] = 0; - ports = _ports; - break; - } - if (!ports) { - /* We've been asked to examine this packet, and we - can't. Hence, no choice but to drop. */ - *hotdrop = 1; - return 0; - } - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) - dst.src_port = ports[0]; - if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT) - dst.dst_port = ports[1]; - } - - spin_lock_bh(&hinfo->lock); - dh = __dsthash_find(hinfo, &dst); - if (!dh) { - dh = __dsthash_alloc_init(hinfo, &dst); - - if (!dh) { - /* enomem... don't match == DROP */ - if (net_ratelimit()) - printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__); - spin_unlock_bh(&hinfo->lock); - return 0; - } - - dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); - - dh->rateinfo.prev = jiffies; - dh->rateinfo.credit = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.cost = user2credits(hinfo->cfg.avg); - } else { - /* update expiration timeout */ - dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); - rateinfo_recalc(dh, now); - } - - if (dh->rateinfo.credit >= dh->rateinfo.cost) { - /* We're underlimit. */ - dh->rateinfo.credit -= dh->rateinfo.cost; - spin_unlock_bh(&hinfo->lock); - return 1; - } - - spin_unlock_bh(&hinfo->lock); - - /* default case: we're overlimit, thus don't match */ - return 0; -} - -static int -hashlimit_checkentry(const char *tablename, - const void *inf, - const struct xt_match *match, - void *matchinfo, - unsigned int hook_mask) -{ - struct ipt_hashlimit_info *r = matchinfo; - - /* Check for overflow. */ - if (r->cfg.burst == 0 - || user2credits(r->cfg.avg * r->cfg.burst) < - user2credits(r->cfg.avg)) { - printk(KERN_ERR "ipt_hashlimit: Overflow, try lower: %u/%u\n", - r->cfg.avg, r->cfg.burst); - return 0; - } - - if (r->cfg.mode == 0 - || r->cfg.mode > (IPT_HASHLIMIT_HASH_DPT - |IPT_HASHLIMIT_HASH_DIP - |IPT_HASHLIMIT_HASH_SIP - |IPT_HASHLIMIT_HASH_SPT)) - return 0; - - if (!r->cfg.gc_interval) - return 0; - - if (!r->cfg.expire) - return 0; - - if (r->name[sizeof(r->name) - 1] != '\0') - return 0; - - /* This is the best we've got: We cannot release and re-grab lock, - * since checkentry() is called before ip_tables.c grabs ipt_mutex. - * We also cannot grab the hashtable spinlock, since htable_create will - * call vmalloc, and that can sleep. And we cannot just re-search - * the list of htable's in htable_create(), since then we would - * create duplicate proc files. -HW */ - mutex_lock(&hlimit_mutex); - r->hinfo = htable_find_get(r->name); - if (!r->hinfo && (htable_create(r) != 0)) { - mutex_unlock(&hlimit_mutex); - return 0; - } - mutex_unlock(&hlimit_mutex); - - /* Ugly hack: For SMP, we only want to use one set */ - r->u.master = r; - - return 1; -} - -static void -hashlimit_destroy(const struct xt_match *match, void *matchinfo) -{ - struct ipt_hashlimit_info *r = matchinfo; - - htable_put(r->hinfo); -} - -#ifdef CONFIG_COMPAT -struct compat_ipt_hashlimit_info { - char name[IFNAMSIZ]; - struct hashlimit_cfg cfg; - compat_uptr_t hinfo; - compat_uptr_t master; -}; - -static void compat_from_user(void *dst, void *src) -{ - int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); - - memcpy(dst, src, off); - memset(dst + off, 0, sizeof(struct compat_ipt_hashlimit_info) - off); -} - -static int compat_to_user(void __user *dst, void *src) -{ - int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); - - return copy_to_user(dst, src, off) ? -EFAULT : 0; -} -#endif - -static struct ipt_match ipt_hashlimit = { - .name = "hashlimit", - .match = hashlimit_match, - .matchsize = sizeof(struct ipt_hashlimit_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_ipt_hashlimit_info), - .compat_from_user = compat_from_user, - .compat_to_user = compat_to_user, -#endif - .checkentry = hashlimit_checkentry, - .destroy = hashlimit_destroy, - .me = THIS_MODULE -}; - -/* PROC stuff */ - -static void *dl_seq_start(struct seq_file *s, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket; - - spin_lock_bh(&htable->lock); - if (*pos >= htable->cfg.size) - return NULL; - - bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC); - if (!bucket) - return ERR_PTR(-ENOMEM); - - *bucket = *pos; - return bucket; -} - -static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - - *pos = ++(*bucket); - if (*pos >= htable->cfg.size) { - kfree(v); - return NULL; - } - return bucket; -} - -static void dl_seq_stop(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - - kfree(bucket); - - spin_unlock_bh(&htable->lock); -} - -static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s) -{ - /* recalculate to show accurate numbers */ - rateinfo_recalc(ent, jiffies); - - return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n", - (long)(ent->expires - jiffies)/HZ, - NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port), - NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port), - ent->rateinfo.credit, ent->rateinfo.credit_cap, - ent->rateinfo.cost); -} - -static int dl_seq_show(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct ipt_hashlimit_htable *htable = pde->data; - unsigned int *bucket = (unsigned int *)v; - struct dsthash_ent *ent; - struct hlist_node *pos; - - if (!hlist_empty(&htable->hash[*bucket])) - hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) { - if (dl_seq_real_show(ent, s)) { - /* buffer was filled and unable to print that tuple */ - return 1; - } - } - - return 0; -} - -static struct seq_operations dl_seq_ops = { - .start = dl_seq_start, - .next = dl_seq_next, - .stop = dl_seq_stop, - .show = dl_seq_show -}; - -static int dl_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &dl_seq_ops); - - if (!ret) { - struct seq_file *sf = file->private_data; - sf->private = PDE(inode); - } - return ret; -} - -static struct file_operations dl_file_ops = { - .owner = THIS_MODULE, - .open = dl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release -}; - -static int init_or_fini(int fini) -{ - int ret = 0; - - if (fini) - goto cleanup; - - if (ipt_register_match(&ipt_hashlimit)) { - ret = -EINVAL; - goto cleanup_nothing; - } - - hashlimit_cachep = kmem_cache_create("ipt_hashlimit", - sizeof(struct dsthash_ent), 0, - 0, NULL, NULL); - if (!hashlimit_cachep) { - printk(KERN_ERR "Unable to create ipt_hashlimit slab cache\n"); - ret = -ENOMEM; - goto cleanup_unreg_match; - } - - hashlimit_procdir = proc_mkdir("ipt_hashlimit", proc_net); - if (!hashlimit_procdir) { - printk(KERN_ERR "Unable to create proc dir entry\n"); - ret = -ENOMEM; - goto cleanup_free_slab; - } - - return ret; - -cleanup: - remove_proc_entry("ipt_hashlimit", proc_net); -cleanup_free_slab: - kmem_cache_destroy(hashlimit_cachep); -cleanup_unreg_match: - ipt_unregister_match(&ipt_hashlimit); -cleanup_nothing: - return ret; - -} - -static int __init ipt_hashlimit_init(void) -{ - return init_or_fini(0); -} - -static void __exit ipt_hashlimit_fini(void) -{ - init_or_fini(1); -} - -module_init(ipt_hashlimit_init); -module_exit(ipt_hashlimit_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f619c6527266..7e6125467c12 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -464,5 +464,19 @@ config NETFILTER_XT_MATCH_TCPMSS To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_HASHLIMIT + tristate '"hashlimit" match support' + depends on NETFILTER_XTABLES + help + This option adds a `hashlimit' match. + + As opposed to `limit', this match dynamically creates a hash table + of limit buckets, based on your selection of source/destination + addresses and/or ports. + + It enables you to express policies like `10kpps for any given + destination address' or `500pps from any given source address' + with a single rule. + endmenu diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 84d529ded952..f85811bfcfe5 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o +obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c new file mode 100644 index 000000000000..46de566d3721 --- /dev/null +++ b/net/netfilter/xt_hashlimit.c @@ -0,0 +1,772 @@ +/* iptables match extension to limit the number of packets per second + * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) + * + * (C) 2003-2004 by Harald Welte + * + * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $ + * + * Development of this code was funded by Astaro AG, http://www.astaro.com/ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("iptables match for limiting per hash-bucket"); +MODULE_ALIAS("ipt_hashlimit"); +MODULE_ALIAS("ip6t_hashlimit"); + +/* need to declare this at the top */ +static struct proc_dir_entry *hashlimit_procdir4; +static struct proc_dir_entry *hashlimit_procdir6; +static struct file_operations dl_file_ops; + +/* hash table crap */ +struct dsthash_dst { + union { + struct { + __be32 src; + __be32 dst; + } ip; + struct { + __be32 src[4]; + __be32 dst[4]; + } ip6; + } addr; + __be16 src_port; + __be16 dst_port; +}; + +struct dsthash_ent { + /* static / read-only parts in the beginning */ + struct hlist_node node; + struct dsthash_dst dst; + + /* modified structure members in the end */ + unsigned long expires; /* precalculated expiry time */ + struct { + unsigned long prev; /* last modification */ + u_int32_t credit; + u_int32_t credit_cap, cost; + } rateinfo; +}; + +struct xt_hashlimit_htable { + struct hlist_node node; /* global list of all htables */ + atomic_t use; + int family; + + struct hashlimit_cfg cfg; /* config */ + + /* used internally */ + spinlock_t lock; /* lock for list_head */ + u_int32_t rnd; /* random seed for hash */ + int rnd_initialized; + unsigned int count; /* number entries in table */ + struct timer_list timer; /* timer for gc */ + + /* seq_file stuff */ + struct proc_dir_entry *pde; + + struct hlist_head hash[0]; /* hashtable itself */ +}; + +static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ +static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ +static HLIST_HEAD(hashlimit_htables); +static kmem_cache_t *hashlimit_cachep __read_mostly; + +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) +{ + return !memcmp(&ent->dst, b, sizeof(ent->dst)); +} + +static u_int32_t +hash_dst(const struct xt_hashlimit_htable *ht, const struct dsthash_dst *dst) +{ + return jhash(dst, sizeof(*dst), ht->rnd) % ht->cfg.size; +} + +static struct dsthash_ent * +dsthash_find(const struct xt_hashlimit_htable *ht, struct dsthash_dst *dst) +{ + struct dsthash_ent *ent; + struct hlist_node *pos; + u_int32_t hash = hash_dst(ht, dst); + + if (!hlist_empty(&ht->hash[hash])) { + hlist_for_each_entry(ent, pos, &ht->hash[hash], node) + if (dst_cmp(ent, dst)) + return ent; + } + return NULL; +} + +/* allocate dsthash_ent, initialize dst, put in htable and lock it */ +static struct dsthash_ent * +dsthash_alloc_init(struct xt_hashlimit_htable *ht, struct dsthash_dst *dst) +{ + struct dsthash_ent *ent; + + /* initialize hash with random val at the time we allocate + * the first hashtable entry */ + if (!ht->rnd_initialized) { + get_random_bytes(&ht->rnd, 4); + ht->rnd_initialized = 1; + } + + if (ht->cfg.max && ht->count >= ht->cfg.max) { + /* FIXME: do something. question is what.. */ + if (net_ratelimit()) + printk(KERN_WARNING + "xt_hashlimit: max count of %u reached\n", + ht->cfg.max); + return NULL; + } + + ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); + if (!ent) { + if (net_ratelimit()) + printk(KERN_ERR + "xt_hashlimit: can't allocate dsthash_ent\n"); + return NULL; + } + memcpy(&ent->dst, dst, sizeof(ent->dst)); + + hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]); + ht->count++; + return ent; +} + +static inline void +dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) +{ + hlist_del(&ent->node); + kmem_cache_free(hashlimit_cachep, ent); + ht->count--; +} +static void htable_gc(unsigned long htlong); + +static int htable_create(struct xt_hashlimit_info *minfo, int family) +{ + struct xt_hashlimit_htable *hinfo; + unsigned int size; + unsigned int i; + + if (minfo->cfg.size) + size = minfo->cfg.size; + else { + size = ((num_physpages << PAGE_SHIFT) / 16384) / + sizeof(struct list_head); + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) + size = 8192; + if (size < 16) + size = 16; + } + /* FIXME: don't use vmalloc() here or anywhere else -HW */ + hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + + sizeof(struct list_head) * size); + if (!hinfo) { + printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n"); + return -1; + } + minfo->hinfo = hinfo; + + /* copy match config into hashtable config */ + memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); + hinfo->cfg.size = size; + if (!hinfo->cfg.max) + hinfo->cfg.max = 8 * hinfo->cfg.size; + else if (hinfo->cfg.max < hinfo->cfg.size) + hinfo->cfg.max = hinfo->cfg.size; + + for (i = 0; i < hinfo->cfg.size; i++) + INIT_HLIST_HEAD(&hinfo->hash[i]); + + atomic_set(&hinfo->use, 1); + hinfo->count = 0; + hinfo->family = family; + hinfo->rnd_initialized = 0; + spin_lock_init(&hinfo->lock); + hinfo->pde = create_proc_entry(minfo->name, 0, + family == AF_INET ? hashlimit_procdir4 : + hashlimit_procdir6); + if (!hinfo->pde) { + vfree(hinfo); + return -1; + } + hinfo->pde->proc_fops = &dl_file_ops; + hinfo->pde->data = hinfo; + + init_timer(&hinfo->timer); + hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); + hinfo->timer.data = (unsigned long )hinfo; + hinfo->timer.function = htable_gc; + add_timer(&hinfo->timer); + + spin_lock_bh(&hashlimit_lock); + hlist_add_head(&hinfo->node, &hashlimit_htables); + spin_unlock_bh(&hashlimit_lock); + + return 0; +} + +static int select_all(struct xt_hashlimit_htable *ht, struct dsthash_ent *he) +{ + return 1; +} + +static int select_gc(struct xt_hashlimit_htable *ht, struct dsthash_ent *he) +{ + return (jiffies >= he->expires); +} + +static void htable_selective_cleanup(struct xt_hashlimit_htable *ht, + int (*select)(struct xt_hashlimit_htable *ht, + struct dsthash_ent *he)) +{ + unsigned int i; + + /* lock hash table and iterate over it */ + spin_lock_bh(&ht->lock); + for (i = 0; i < ht->cfg.size; i++) { + struct dsthash_ent *dh; + struct hlist_node *pos, *n; + hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) { + if ((*select)(ht, dh)) + dsthash_free(ht, dh); + } + } + spin_unlock_bh(&ht->lock); +} + +/* hash table garbage collector, run by timer */ +static void htable_gc(unsigned long htlong) +{ + struct xt_hashlimit_htable *ht = (struct xt_hashlimit_htable *)htlong; + + htable_selective_cleanup(ht, select_gc); + + /* re-add the timer accordingly */ + ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); + add_timer(&ht->timer); +} + +static void htable_destroy(struct xt_hashlimit_htable *hinfo) +{ + /* remove timer, if it is pending */ + if (timer_pending(&hinfo->timer)) + del_timer(&hinfo->timer); + + /* remove proc entry */ + remove_proc_entry(hinfo->pde->name, + hinfo->family == AF_INET ? hashlimit_procdir4 : + hashlimit_procdir6); + htable_selective_cleanup(hinfo, select_all); + vfree(hinfo); +} + +static struct xt_hashlimit_htable *htable_find_get(char *name, int family) +{ + struct xt_hashlimit_htable *hinfo; + struct hlist_node *pos; + + spin_lock_bh(&hashlimit_lock); + hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { + if (!strcmp(name, hinfo->pde->name) && + hinfo->family == family) { + atomic_inc(&hinfo->use); + spin_unlock_bh(&hashlimit_lock); + return hinfo; + } + } + spin_unlock_bh(&hashlimit_lock); + return NULL; +} + +static void htable_put(struct xt_hashlimit_htable *hinfo) +{ + if (atomic_dec_and_test(&hinfo->use)) { + spin_lock_bh(&hashlimit_lock); + hlist_del(&hinfo->node); + spin_unlock_bh(&hashlimit_lock); + htable_destroy(hinfo); + } +} + +/* The algorithm used is the Simple Token Bucket Filter (TBF) + * see net/sched/sch_tbf.c in the linux source tree + */ + +/* Rusty: This is my (non-mathematically-inclined) understanding of + this algorithm. The `average rate' in jiffies becomes your initial + amount of credit `credit' and the most credit you can ever have + `credit_cap'. The `peak rate' becomes the cost of passing the + test, `cost'. + + `prev' tracks the last packet hit: you gain one credit per jiffy. + If you get credit balance more than this, the extra credit is + discarded. Every time the match passes, you lose `cost' credits; + if you don't have that many, the test fails. + + See Alexey's formal explanation in net/sched/sch_tbf.c. + + To get the maximum range, we multiply by this factor (ie. you get N + credits per jiffy). We want to allow a rate as low as 1 per day + (slowest userspace tool allows), which means + CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. +*/ +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) + +/* Repeated shift and or gives us all 1s, final shift and add 1 gives + * us the power of 2 below the theoretical max, so GCC simply does a + * shift. */ +#define _POW2_BELOW2(x) ((x)|((x)>>1)) +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) + +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) + +/* Precision saver. */ +static inline u_int32_t +user2credits(u_int32_t user) +{ + /* If multiplying would overflow... */ + if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) + /* Divide first. */ + return (user / XT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; + + return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE; +} + +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) +{ + dh->rateinfo.credit += (now - dh->rateinfo.prev) * CREDITS_PER_JIFFY; + if (dh->rateinfo.credit > dh->rateinfo.credit_cap) + dh->rateinfo.credit = dh->rateinfo.credit_cap; + dh->rateinfo.prev = now; +} + +static int +hashlimit_init_dst(struct xt_hashlimit_htable *hinfo, struct dsthash_dst *dst, + const struct sk_buff *skb, unsigned int protoff) +{ + __be16 _ports[2], *ports; + int nexthdr; + + memset(dst, 0, sizeof(*dst)); + + switch (hinfo->family) { + case AF_INET: + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) + dst->addr.ip.dst = skb->nh.iph->daddr; + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) + dst->addr.ip.src = skb->nh.iph->saddr; + + if (!(hinfo->cfg.mode & + (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) + return 0; + nexthdr = skb->nh.iph->protocol; + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) + memcpy(&dst->addr.ip6.dst, &skb->nh.ipv6h->daddr, + sizeof(dst->addr.ip6.dst)); + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) + memcpy(&dst->addr.ip6.src, &skb->nh.ipv6h->saddr, + sizeof(dst->addr.ip6.src)); + + if (!(hinfo->cfg.mode & + (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) + return 0; + nexthdr = ipv6_find_hdr(skb, &protoff, -1, NULL); + if (nexthdr < 0) + return -1; + break; +#endif + default: + BUG(); + return 0; + } + + switch (nexthdr) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_SCTP: + case IPPROTO_DCCP: + ports = skb_header_pointer(skb, protoff, sizeof(_ports), + &_ports); + break; + default: + _ports[0] = _ports[1] = 0; + ports = _ports; + break; + } + if (!ports) + return -1; + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SPT) + dst->src_port = ports[0]; + if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DPT) + dst->dst_port = ports[1]; + return 0; +} + +static int +hashlimit_match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct xt_match *match, + const void *matchinfo, + int offset, + unsigned int protoff, + int *hotdrop) +{ + struct xt_hashlimit_info *r = + ((struct xt_hashlimit_info *)matchinfo)->u.master; + struct xt_hashlimit_htable *hinfo = r->hinfo; + unsigned long now = jiffies; + struct dsthash_ent *dh; + struct dsthash_dst dst; + + if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0) + goto hotdrop; + + spin_lock_bh(&hinfo->lock); + dh = dsthash_find(hinfo, &dst); + if (!dh) { + dh = dsthash_alloc_init(hinfo, &dst); + if (!dh) { + spin_unlock_bh(&hinfo->lock); + goto hotdrop; + } + + dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); + dh->rateinfo.prev = jiffies; + dh->rateinfo.credit = user2credits(hinfo->cfg.avg * + hinfo->cfg.burst); + dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * + hinfo->cfg.burst); + dh->rateinfo.cost = user2credits(hinfo->cfg.avg); + } else { + /* update expiration timeout */ + dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); + rateinfo_recalc(dh, now); + } + + if (dh->rateinfo.credit >= dh->rateinfo.cost) { + /* We're underlimit. */ + dh->rateinfo.credit -= dh->rateinfo.cost; + spin_unlock_bh(&hinfo->lock); + return 1; + } + + spin_unlock_bh(&hinfo->lock); + + /* default case: we're overlimit, thus don't match */ + return 0; + +hotdrop: + *hotdrop = 1; + return 0; +} + +static int +hashlimit_checkentry(const char *tablename, + const void *inf, + const struct xt_match *match, + void *matchinfo, + unsigned int hook_mask) +{ + struct xt_hashlimit_info *r = matchinfo; + + /* Check for overflow. */ + if (r->cfg.burst == 0 || + user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) { + printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n", + r->cfg.avg, r->cfg.burst); + return 0; + } + if (r->cfg.mode == 0 || + r->cfg.mode > (XT_HASHLIMIT_HASH_DPT | + XT_HASHLIMIT_HASH_DIP | + XT_HASHLIMIT_HASH_SIP | + XT_HASHLIMIT_HASH_SPT)) + return 0; + if (!r->cfg.gc_interval) + return 0; + if (!r->cfg.expire) + return 0; + if (r->name[sizeof(r->name) - 1] != '\0') + return 0; + + /* This is the best we've got: We cannot release and re-grab lock, + * since checkentry() is called before x_tables.c grabs xt_mutex. + * We also cannot grab the hashtable spinlock, since htable_create will + * call vmalloc, and that can sleep. And we cannot just re-search + * the list of htable's in htable_create(), since then we would + * create duplicate proc files. -HW */ + mutex_lock(&hlimit_mutex); + r->hinfo = htable_find_get(r->name, match->family); + if (!r->hinfo && htable_create(r, match->family) != 0) { + mutex_unlock(&hlimit_mutex); + return 0; + } + mutex_unlock(&hlimit_mutex); + + /* Ugly hack: For SMP, we only want to use one set */ + r->u.master = r; + return 1; +} + +static void +hashlimit_destroy(const struct xt_match *match, void *matchinfo) +{ + struct xt_hashlimit_info *r = matchinfo; + + htable_put(r->hinfo); +} + +#ifdef CONFIG_COMPAT +struct compat_xt_hashlimit_info { + char name[IFNAMSIZ]; + struct hashlimit_cfg cfg; + compat_uptr_t hinfo; + compat_uptr_t master; +}; + +static void compat_from_user(void *dst, void *src) +{ + int off = offsetof(struct compat_xt_hashlimit_info, hinfo); + + memcpy(dst, src, off); + memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off); +} + +static int compat_to_user(void __user *dst, void *src) +{ + int off = offsetof(struct compat_xt_hashlimit_info, hinfo); + + return copy_to_user(dst, src, off) ? -EFAULT : 0; +} +#endif + +static struct xt_match xt_hashlimit[] = { + { + .name = "hashlimit", + .family = AF_INET, + .match = hashlimit_match, + .matchsize = sizeof(struct xt_hashlimit_info), +#ifdef CONFIG_COMPAT + .compatsize = sizeof(struct compat_xt_hashlimit_info), + .compat_from_user = compat_from_user, + .compat_to_user = compat_to_user, +#endif + .checkentry = hashlimit_checkentry, + .destroy = hashlimit_destroy, + .me = THIS_MODULE + }, + { + .name = "hashlimit", + .family = AF_INET6, + .match = hashlimit_match, + .matchsize = sizeof(struct xt_hashlimit_info), +#ifdef CONFIG_COMPAT + .compatsize = sizeof(struct compat_xt_hashlimit_info), + .compat_from_user = compat_from_user, + .compat_to_user = compat_to_user, +#endif + .checkentry = hashlimit_checkentry, + .destroy = hashlimit_destroy, + .me = THIS_MODULE + }, +}; + +/* PROC stuff */ +static void *dl_seq_start(struct seq_file *s, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket; + + spin_lock_bh(&htable->lock); + if (*pos >= htable->cfg.size) + return NULL; + + bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC); + if (!bucket) + return ERR_PTR(-ENOMEM); + + *bucket = *pos; + return bucket; +} + +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + + *pos = ++(*bucket); + if (*pos >= htable->cfg.size) { + kfree(v); + return NULL; + } + return bucket; +} + +static void dl_seq_stop(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + + kfree(bucket); + spin_unlock_bh(&htable->lock); +} + +static int dl_seq_real_show(struct dsthash_ent *ent, int family, + struct seq_file *s) +{ + /* recalculate to show accurate numbers */ + rateinfo_recalc(ent, jiffies); + + switch (family) { + case AF_INET: + return seq_printf(s, "%ld %u.%u.%u.%u:%u->" + "%u.%u.%u.%u:%u %u %u %u\n", + (long)(ent->expires - jiffies)/HZ, + NIPQUAD(ent->dst.addr.ip.src), + ntohs(ent->dst.src_port), + NIPQUAD(ent->dst.addr.ip.dst), + ntohs(ent->dst.dst_port), + ent->rateinfo.credit, ent->rateinfo.credit_cap, + ent->rateinfo.cost); + case AF_INET6: + return seq_printf(s, "%ld " NIP6_FMT ":%u->" + NIP6_FMT ":%u %u %u %u\n", + (long)(ent->expires - jiffies)/HZ, + NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src), + ntohs(ent->dst.src_port), + NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst), + ntohs(ent->dst.dst_port), + ent->rateinfo.credit, ent->rateinfo.credit_cap, + ent->rateinfo.cost); + default: + BUG(); + return 0; + } +} + +static int dl_seq_show(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct xt_hashlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + struct dsthash_ent *ent; + struct hlist_node *pos; + + if (!hlist_empty(&htable->hash[*bucket])) { + hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) + if (dl_seq_real_show(ent, htable->family, s)) + return 1; + } + return 0; +} + +static struct seq_operations dl_seq_ops = { + .start = dl_seq_start, + .next = dl_seq_next, + .stop = dl_seq_stop, + .show = dl_seq_show +}; + +static int dl_proc_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &dl_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +} + +static struct file_operations dl_file_ops = { + .owner = THIS_MODULE, + .open = dl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +static int __init xt_hashlimit_init(void) +{ + int err; + + err = xt_register_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); + if (err < 0) + goto err1; + + err = -ENOMEM; + hashlimit_cachep = kmem_cache_create("xt_hashlimit", + sizeof(struct dsthash_ent), 0, 0, + NULL, NULL); + if (!hashlimit_cachep) { + printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); + goto err2; + } + hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", proc_net); + if (!hashlimit_procdir4) { + printk(KERN_ERR "xt_hashlimit: unable to create proc dir " + "entry\n"); + goto err3; + } + hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", proc_net); + if (!hashlimit_procdir6) { + printk(KERN_ERR "xt_hashlimit: tnable to create proc dir " + "entry\n"); + goto err4; + } + return 0; +err4: + remove_proc_entry("ipt_hashlimit", proc_net); +err3: + kmem_cache_destroy(hashlimit_cachep); +err2: + xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); +err1: + return err; + +} + +static void __exit xt_hashlimit_fini(void) +{ + remove_proc_entry("ipt_hashlimit", proc_net); + remove_proc_entry("ip6t_hashlimit", proc_net); + kmem_cache_destroy(hashlimit_cachep); + xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); +} + +module_init(xt_hashlimit_init); +module_exit(xt_hashlimit_fini); -- cgit v1.2.3-71-gd317 From baf7b1e11282127e068d149825cccec002091d61 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 29 Nov 2006 02:35:38 +0100 Subject: [NETFILTER]: x_tables: add NFLOG target Add new NFLOG target to allow use of nfnetlink_log for both IPv4 and IPv6. Currently we have two (unsupported by userspace) hacks in the LOG and ULOG targets to optionally call to the nflog API. They lack a few features, namely the IPv4 and IPv6 LOG targets can not specify a number of arguments related to nfnetlink_log, while the ULOG target is only available for IPv4. Remove those hacks and add a clean way to use nfnetlink_log. Signed-off-by: Patrick McHardy --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/xt_NFLOG.h | 18 +++++++ include/linux/netfilter_ipv4/ipt_LOG.h | 2 +- include/linux/netfilter_ipv6/ip6t_LOG.h | 2 +- net/ipv4/netfilter/ipt_LOG.c | 9 +--- net/ipv6/netfilter/ip6t_LOG.c | 9 +--- net/netfilter/Kconfig | 11 +++++ net/netfilter/Makefile | 1 + net/netfilter/xt_NFLOG.c | 86 +++++++++++++++++++++++++++++++++ 9 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 include/linux/netfilter/xt_NFLOG.h create mode 100644 net/netfilter/xt_NFLOG.c (limited to 'include/linux') diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index e379a2d89ea0..6328175a1c3a 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -22,6 +22,7 @@ header-y += xt_mark.h header-y += xt_MARK.h header-y += xt_multiport.h header-y += xt_NFQUEUE.h +header-y += xt_NFLOG.h header-y += xt_pkttype.h header-y += xt_policy.h header-y += xt_realm.h diff --git a/include/linux/netfilter/xt_NFLOG.h b/include/linux/netfilter/xt_NFLOG.h new file mode 100644 index 000000000000..cdcd0ed58f7a --- /dev/null +++ b/include/linux/netfilter/xt_NFLOG.h @@ -0,0 +1,18 @@ +#ifndef _XT_NFLOG_TARGET +#define _XT_NFLOG_TARGET + +#define XT_NFLOG_DEFAULT_GROUP 0x1 +#define XT_NFLOG_DEFAULT_THRESHOLD 1 + +#define XT_NFLOG_MASK 0x0 + +struct xt_nflog_info { + u_int32_t len; + u_int16_t group; + u_int16_t threshold; + u_int16_t flags; + u_int16_t pad; + char prefix[64]; +}; + +#endif /* _XT_NFLOG_TARGET */ diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h index 892f9a33fea8..90fa6525ef9c 100644 --- a/include/linux/netfilter_ipv4/ipt_LOG.h +++ b/include/linux/netfilter_ipv4/ipt_LOG.h @@ -6,7 +6,7 @@ #define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ #define IPT_LOG_IPOPT 0x04 /* Log IP options */ #define IPT_LOG_UID 0x08 /* Log UID owning local socket */ -#define IPT_LOG_NFLOG 0x10 /* Log using nf_log backend */ +#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ #define IPT_LOG_MASK 0x1f struct ipt_log_info { diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h index 060c1a1c6c60..0d0119b0458c 100644 --- a/include/linux/netfilter_ipv6/ip6t_LOG.h +++ b/include/linux/netfilter_ipv6/ip6t_LOG.h @@ -6,7 +6,7 @@ #define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ #define IP6T_LOG_IPOPT 0x04 /* Log IP options */ #define IP6T_LOG_UID 0x08 /* Log UID owning local socket */ -#define IP6T_LOG_NFLOG 0x10 /* Log using nf_log backend */ +#define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */ #define IP6T_LOG_MASK 0x1f struct ip6t_log_info { diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 46eee64a11f6..c96de16fefae 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -430,13 +430,8 @@ ipt_log_target(struct sk_buff **pskb, li.u.log.level = loginfo->level; li.u.log.logflags = loginfo->logflags; - if (loginfo->logflags & IPT_LOG_NFLOG) - nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - "%s", loginfo->prefix); - else - ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - loginfo->prefix); - + ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, + loginfo->prefix); return IPT_CONTINUE; } diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index f4857cf97f05..33b1faa90d74 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -440,13 +440,8 @@ ip6t_log_target(struct sk_buff **pskb, li.u.log.level = loginfo->level; li.u.log.logflags = loginfo->logflags; - if (loginfo->logflags & IP6T_LOG_NFLOG) - nf_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, - "%s", loginfo->prefix); - else - ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, - loginfo->prefix); - + ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, + loginfo->prefix); return IP6T_CONTINUE; } diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 7e6125467c12..d191dacead5e 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -184,6 +184,17 @@ config NETFILTER_XT_TARGET_NFQUEUE To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_TARGET_NFLOG + tristate '"NFLOG" target support' + depends on NETFILTER_XTABLES + help + This option enables the NFLOG target, which allows to LOG + messages through the netfilter logging API, which can use + either the old LOG target, the old ULOG target or nfnetlink_log + as backend. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_TARGET_NOTRACK tristate '"NOTRACK" target support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index f85811bfcfe5..7f0089c584bf 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o +obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c new file mode 100644 index 000000000000..901ed7abaa1b --- /dev/null +++ b/net/netfilter/xt_NFLOG.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("x_tables NFLOG target"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_NFLOG"); +MODULE_ALIAS("ip6t_NFLOG"); + +static unsigned int +nflog_target(struct sk_buff **pskb, + const struct net_device *in, const struct net_device *out, + unsigned int hooknum, const struct xt_target *target, + const void *targinfo) +{ + const struct xt_nflog_info *info = targinfo; + struct nf_loginfo li; + + li.type = NF_LOG_TYPE_ULOG; + li.u.ulog.copy_len = info->len; + li.u.ulog.group = info->group; + li.u.ulog.qthreshold = info->threshold; + + nf_log_packet(target->family, hooknum, *pskb, in, out, &li, + "%s", info->prefix); + return XT_CONTINUE; +} + +static int +nflog_checkentry(const char *tablename, const void *entry, + const struct xt_target *target, void *targetinfo, + unsigned int hookmask) +{ + struct xt_nflog_info *info = targetinfo; + + if (info->flags & ~XT_NFLOG_MASK) + return 0; + if (info->prefix[sizeof(info->prefix) - 1] != '\0') + return 0; + return 1; +} + +static struct xt_target xt_nflog_target[] = { + { + .name = "NFLOG", + .family = AF_INET, + .checkentry = nflog_checkentry, + .target = nflog_target, + .targetsize = sizeof(struct xt_nflog_info), + .me = THIS_MODULE, + }, + { + .name = "NFLOG", + .family = AF_INET6, + .checkentry = nflog_checkentry, + .target = nflog_target, + .targetsize = sizeof(struct xt_nflog_info), + .me = THIS_MODULE, + }, +}; + +static int __init xt_nflog_init(void) +{ + return xt_register_targets(xt_nflog_target, + ARRAY_SIZE(xt_nflog_target)); +} + +static void __exit xt_nflog_fini(void) +{ + xt_unregister_targets(xt_nflog_target, ARRAY_SIZE(xt_nflog_target)); +} + +module_init(xt_nflog_init); +module_exit(xt_nflog_fini); -- cgit v1.2.3-71-gd317 From d12cdc3ccf140bd2febef1c1be92284571da983f Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Wed, 29 Nov 2006 02:35:40 +0100 Subject: [NETFILTER]: ebtables: add --snap-arp option The attached patch adds --snat-arp support, which makes it possible to change the source mac address in both the mac header and the arp header with one rule. Signed-off-by: Bart De Schuymer Signed-off-by: Patrick McHardy --- include/linux/netfilter_bridge/ebt_nat.h | 1 + include/linux/netfilter_bridge/ebtables.h | 4 ++++ net/bridge/netfilter/ebt_mark.c | 6 +++--- net/bridge/netfilter/ebt_snat.c | 27 ++++++++++++++++++++++++--- 4 files changed, 32 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge/ebt_nat.h b/include/linux/netfilter_bridge/ebt_nat.h index 26fd90da4cd6..435b886a51aa 100644 --- a/include/linux/netfilter_bridge/ebt_nat.h +++ b/include/linux/netfilter_bridge/ebt_nat.h @@ -1,6 +1,7 @@ #ifndef __LINUX_BRIDGE_EBT_NAT_H #define __LINUX_BRIDGE_EBT_NAT_H +#define NAT_ARP_BIT (0x00000010) struct ebt_nat_info { unsigned char mac[ETH_ALEN]; diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index e6ea70de24d5..87775264ff0b 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -26,6 +26,10 @@ #define EBT_CONTINUE -3 #define EBT_RETURN -4 #define NUM_STANDARD_TARGETS 4 +/* ebtables target modules store the verdict inside an int. We can + * reclaim a part of this int for backwards compatible extensions. + * The 4 lsb are more than enough to store the verdict. */ +#define EBT_VERDICT_BITS 0x0000000F struct ebt_counter { diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c index 2458638561cb..62d23c7b25e6 100644 --- a/net/bridge/netfilter/ebt_mark.c +++ b/net/bridge/netfilter/ebt_mark.c @@ -33,7 +33,7 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, else (*pskb)->mark ^= info->mark; - return info->target | -16; + return info->target | ~EBT_VERDICT_BITS; } static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, @@ -44,13 +44,13 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) return -EINVAL; - tmp = info->target | -16; + tmp = info->target | ~EBT_VERDICT_BITS; if (BASE_CHAIN && tmp == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) return -EINVAL; - tmp = info->target & -16; + tmp = info->target & ~EBT_VERDICT_BITS; if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE && tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index cbb33e24ca8a..a50722182bfe 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, const struct net_device *in, const struct net_device *out, @@ -31,24 +33,43 @@ static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, *pskb = nskb; } memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN); - return info->target; + if (!(info->target & NAT_ARP_BIT) && + eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) { + struct arphdr _ah, *ap; + + ap = skb_header_pointer(*pskb, 0, sizeof(_ah), &_ah); + if (ap == NULL) + return EBT_DROP; + if (ap->ar_hln != ETH_ALEN) + goto out; + if (skb_store_bits(*pskb, sizeof(_ah), info->mac,ETH_ALEN)) + return EBT_DROP; + } +out: + return info->target | ~EBT_VERDICT_BITS; } static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_nat_info *info = (struct ebt_nat_info *) data; + int tmp; if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) return -EINVAL; - if (BASE_CHAIN && info->target == EBT_RETURN) + tmp = info->target | ~EBT_VERDICT_BITS; + if (BASE_CHAIN && tmp == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if (strcmp(tablename, "nat")) return -EINVAL; if (hookmask & ~(1 << NF_BR_POST_ROUTING)) return -EINVAL; - if (INVALID_TARGET) + + if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) + return -EINVAL; + tmp = info->target | EBT_VERDICT_BITS; + if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT) return -EINVAL; return 0; } -- cgit v1.2.3-71-gd317 From 1e419cd9953f59d06d7b88d0e2911a68a0044f33 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 30 Nov 2006 19:28:48 -0800 Subject: [EBTABLES]: Split ebt_replace into user and kernel variants, annotate. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- include/linux/netfilter_bridge/ebtables.h | 19 ++++++++++++++++++- net/bridge/netfilter/ebtable_broute.c | 2 +- net/bridge/netfilter/ebtable_filter.c | 2 +- net/bridge/netfilter/ebtable_nat.c | 2 +- net/bridge/netfilter/ebtables.c | 19 ++++++++++--------- 5 files changed, 31 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index 87775264ff0b..94e0a7dc0cb2 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -38,6 +38,23 @@ struct ebt_counter }; struct ebt_replace +{ + char name[EBT_TABLE_MAXNAMELEN]; + unsigned int valid_hooks; + /* nr of rules in the table */ + unsigned int nentries; + /* total size of the entries */ + unsigned int entries_size; + /* start of the chains */ + struct ebt_entries __user *hook_entry[NF_BR_NUMHOOKS]; + /* nr of counters userspace expects back */ + unsigned int num_counters; + /* where the kernel will put the old counters */ + struct ebt_counter __user *counters; + char __user *entries; +}; + +struct ebt_replace_kernel { char name[EBT_TABLE_MAXNAMELEN]; unsigned int valid_hooks; @@ -255,7 +272,7 @@ struct ebt_table { struct list_head list; char name[EBT_TABLE_MAXNAMELEN]; - struct ebt_replace *table; + struct ebt_replace_kernel *table; unsigned int valid_hooks; rwlock_t lock; /* e.g. could be the table explicitly only allows certain diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index 9a6e548e148b..d37ce0478938 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -23,7 +23,7 @@ static struct ebt_entries initial_chain = { .policy = EBT_ACCEPT, }; -static struct ebt_replace initial_table = +static struct ebt_replace_kernel initial_table = { .name = "broute", .valid_hooks = 1 << NF_BR_BROUTING, diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index 3d5bd44f2395..127135ead2d5 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -30,7 +30,7 @@ static struct ebt_entries initial_chains[] = }, }; -static struct ebt_replace initial_table = +static struct ebt_replace_kernel initial_table = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index 04dd42efda1d..9c50488b62eb 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -30,7 +30,7 @@ static struct ebt_entries initial_chains[] = } }; -static struct ebt_replace initial_table = +static struct ebt_replace_kernel initial_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 00a89705c1c4..bee558a41800 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -417,7 +417,8 @@ static int ebt_verify_pointers(struct ebt_replace *repl, for (i = 0; i < NF_BR_NUMHOOKS; i++) { if ((valid_hooks & (1 << i)) == 0) continue; - if ((char *)repl->hook_entry[i] == repl->entries + offset) + if ((char __user *)repl->hook_entry[i] == + repl->entries + offset) break; } @@ -1156,7 +1157,7 @@ int ebt_register_table(struct ebt_table *table) { struct ebt_table_info *newinfo; struct ebt_table *t; - struct ebt_replace *repl; + struct ebt_replace_kernel *repl; int ret, i, countersize; void *p; @@ -1320,33 +1321,33 @@ free_tmp: } static inline int ebt_make_matchname(struct ebt_entry_match *m, - char *base, char *ubase) + char *base, char __user *ubase) { - char *hlp = ubase - base + (char *)m; + char __user *hlp = ubase + ((char *)m - base); if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; } static inline int ebt_make_watchername(struct ebt_entry_watcher *w, - char *base, char *ubase) + char *base, char __user *ubase) { - char *hlp = ubase - base + (char *)w; + char __user *hlp = ubase + ((char *)w - base); if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; } -static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase) +static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase) { int ret; - char *hlp; + char __user *hlp; struct ebt_entry_target *t; if (e->bitmask == 0) return 0; - hlp = ubase - base + (char *)e + e->target_offset; + hlp = ubase + (((char *)e + e->target_offset) - base); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase); -- cgit v1.2.3-71-gd317 From 9a7c9337a09b1ef07e55f95a4309957a2328a01f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:04:04 -0800 Subject: [NET]: Accept wildcard delimiters in in[46]_pton Accept -1 as delimiter to abort parsing without an error at the first unknown character. This is needed by the upcoming nf_conntrack SIP helper, where addresses are delimited by either '\r' or '\n' characters. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/inet.h | 4 ++-- net/core/utils.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inet.h b/include/linux/inet.h index b7c6da7d6d32..675a7dbe86f8 100644 --- a/include/linux/inet.h +++ b/include/linux/inet.h @@ -46,7 +46,7 @@ #include extern __be32 in_aton(const char *str); -extern int in4_pton(const char *src, int srclen, u8 *dst, char delim, const char **end); -extern int in6_pton(const char *src, int srclen, u8 *dst, char delim, const char **end); +extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); +extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); #endif #endif /* _LINUX_INET_H */ diff --git a/net/core/utils.c b/net/core/utils.c index d93fe64f6693..61556065f07e 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -88,7 +88,7 @@ EXPORT_SYMBOL(in_aton); #define IN6PTON_NULL 0x20000000 /* first/tail */ #define IN6PTON_UNKNOWN 0x40000000 -static inline int digit2bin(char c, char delim) +static inline int digit2bin(char c, int delim) { if (c == delim || c == '\0') return IN6PTON_DELIM; @@ -99,7 +99,7 @@ static inline int digit2bin(char c, char delim) return IN6PTON_UNKNOWN; } -static inline int xdigit2bin(char c, char delim) +static inline int xdigit2bin(char c, int delim) { if (c == delim || c == '\0') return IN6PTON_DELIM; @@ -113,12 +113,14 @@ static inline int xdigit2bin(char c, char delim) return (IN6PTON_XDIGIT | (c - 'a' + 10)); if (c >= 'A' && c <= 'F') return (IN6PTON_XDIGIT | (c - 'A' + 10)); + if (delim == -1) + return IN6PTON_DELIM; return IN6PTON_UNKNOWN; } int in4_pton(const char *src, int srclen, u8 *dst, - char delim, const char **end) + int delim, const char **end) { const char *s; u8 *d; @@ -173,7 +175,7 @@ EXPORT_SYMBOL(in4_pton); int in6_pton(const char *src, int srclen, u8 *dst, - char delim, const char **end) + int delim, const char **end) { const char *s, *tok = NULL; u8 *d, *dc = NULL; -- cgit v1.2.3-71-gd317 From 5b1158e909ecbe1a052203e0d8df15633f829930 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 2 Dec 2006 22:07:13 -0800 Subject: [NETFILTER]: Add NAT support for nf_conntrack Add NAT support for nf_conntrack. Joint work of Jozsef Kadlecsik, Yasuyuki Kozakai, Martin Josefsson and myself. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter.h | 2 +- include/net/netfilter/ipv4/nf_conntrack_ipv4.h | 20 +- include/net/netfilter/nf_conntrack.h | 29 +- include/net/netfilter/nf_conntrack_expect.h | 2 +- include/net/netfilter/nf_nat.h | 77 +++ include/net/netfilter/nf_nat_core.h | 27 ++ include/net/netfilter/nf_nat_helper.h | 32 ++ include/net/netfilter/nf_nat_protocol.h | 70 +++ include/net/netfilter/nf_nat_rule.h | 35 ++ net/ipv4/netfilter/Kconfig | 30 +- net/ipv4/netfilter/Makefile | 7 + net/ipv4/netfilter/ip_nat_standalone.c | 6 - net/ipv4/netfilter/ipt_MASQUERADE.c | 29 +- net/ipv4/netfilter/ipt_NETMAP.c | 4 + net/ipv4/netfilter/ipt_REDIRECT.c | 6 +- net/ipv4/netfilter/ipt_SAME.c | 12 +- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 7 +- net/ipv4/netfilter/nf_nat_core.c | 647 +++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_helper.c | 433 +++++++++++++++++ net/ipv4/netfilter/nf_nat_proto_icmp.c | 86 ++++ net/ipv4/netfilter/nf_nat_proto_tcp.c | 148 ++++++ net/ipv4/netfilter/nf_nat_proto_udp.c | 138 ++++++ net/ipv4/netfilter/nf_nat_proto_unknown.c | 54 +++ net/ipv4/netfilter/nf_nat_rule.c | 343 +++++++++++++ net/ipv4/netfilter/nf_nat_standalone.c | 406 ++++++++++++++++ net/netfilter/nf_conntrack_core.c | 23 +- net/netfilter/nf_conntrack_netlink.c | 46 +- net/netfilter/nf_conntrack_proto_tcp.c | 2 +- net/netfilter/nf_conntrack_standalone.c | 5 +- 29 files changed, 2667 insertions(+), 59 deletions(-) create mode 100644 include/net/netfilter/nf_nat.h create mode 100644 include/net/netfilter/nf_nat_core.h create mode 100644 include/net/netfilter/nf_nat_helper.h create mode 100644 include/net/netfilter/nf_nat_protocol.h create mode 100644 include/net/netfilter/nf_nat_rule.h create mode 100644 net/ipv4/netfilter/nf_nat_core.c create mode 100644 net/ipv4/netfilter/nf_nat_helper.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_icmp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_tcp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_udp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_unknown.c create mode 100644 net/ipv4/netfilter/nf_nat_rule.c create mode 100644 net/ipv4/netfilter/nf_nat_standalone.c (limited to 'include/linux') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index f6f3fcbd70ed..d4c4c5120bc0 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -357,7 +357,7 @@ extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); static inline void nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) { -#ifdef CONFIG_IP_NF_NAT_NEEDED +#if defined(CONFIG_IP_NF_NAT_NEEDED) || defined(CONFIG_NF_NAT_NEEDED) void (*decodefn)(struct sk_buff *, struct flowi *); if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL) diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h index 34b453a81a63..a1c57ee0a4fa 100644 --- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -9,29 +9,23 @@ #ifndef _NF_CONNTRACK_IPV4_H #define _NF_CONNTRACK_IPV4_H -#ifdef CONFIG_IP_NF_NAT_NEEDED -#include +#ifdef CONFIG_NF_NAT_NEEDED +#include /* per conntrack: nat application helper private data */ -union ip_conntrack_nat_help { +union nf_conntrack_nat_help { /* insert nat helper private data here */ }; -struct nf_conntrack_ipv4_nat { - struct ip_nat_info info; - union ip_conntrack_nat_help help; +struct nf_conn_nat { + struct nf_nat_info info; + union nf_conntrack_nat_help help; #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) int masq_index; #endif }; -#endif /* CONFIG_IP_NF_NAT_NEEDED */ - -struct nf_conntrack_ipv4 { -#ifdef CONFIG_IP_NF_NAT_NEEDED - struct nf_conntrack_ipv4_nat *nat; -#endif -}; +#endif /* CONFIG_NF_NAT_NEEDED */ /* Returns new sk_buff, or NULL */ struct sk_buff * diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b4beb8c799e5..9948af068688 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -264,18 +264,45 @@ nf_conntrack_unregister_cache(u_int32_t features); /* valid combinations: * basic: nf_conn, nf_conn .. nf_conn_help - * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help + * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat .. nf_conn help */ +#ifdef CONFIG_NF_NAT_NEEDED +static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) +{ + unsigned int offset = sizeof(struct nf_conn); + + if (!(ct->features & NF_CT_F_NAT)) + return NULL; + + offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); + return (struct nf_conn_nat *) ((void *)ct + offset); +} + static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) { unsigned int offset = sizeof(struct nf_conn); if (!(ct->features & NF_CT_F_HELP)) return NULL; + if (ct->features & NF_CT_F_NAT) { + offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); + offset += sizeof(struct nf_conn_nat); + } offset = ALIGN(offset, __alignof__(struct nf_conn_help)); return (struct nf_conn_help *) ((void *)ct + offset); } +#else /* No NAT */ +static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) +{ + unsigned int offset = sizeof(struct nf_conn); + + if (!(ct->features & NF_CT_F_HELP)) + return NULL; + offset = ALIGN(offset, __alignof__(struct nf_conn_help)); + return (struct nf_conn_help *) ((void *)ct + offset); +} +#endif /* CONFIG_NF_NAT_NEEDED */ #endif /* __KERNEL__ */ #endif /* _NF_CONNTRACK_H */ diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 5d853e826d1d..b969c430b36a 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -43,7 +43,7 @@ struct nf_conntrack_expect #ifdef CONFIG_NF_NAT_NEEDED /* This is the original per-proto part, used to map the * expected connection the way the recipient expects. */ - union nf_conntrack_manip_proto saved_proto; + union nf_conntrack_man_proto saved_proto; /* Direction relative to the master connection. */ enum ip_conntrack_dir dir; #endif diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h new file mode 100644 index 000000000000..61c62068ca6b --- /dev/null +++ b/include/net/netfilter/nf_nat.h @@ -0,0 +1,77 @@ +#ifndef _NF_NAT_H +#define _NF_NAT_H +#include +#include + +#define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16 + +enum nf_nat_manip_type +{ + IP_NAT_MANIP_SRC, + IP_NAT_MANIP_DST +}; + +/* SRC manip occurs POST_ROUTING or LOCAL_IN */ +#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN) + +#define IP_NAT_RANGE_MAP_IPS 1 +#define IP_NAT_RANGE_PROTO_SPECIFIED 2 + +/* NAT sequence number modifications */ +struct nf_nat_seq { + /* position of the last TCP sequence number modification (if any) */ + u_int32_t correction_pos; + + /* sequence number offset before and after last modification */ + int16_t offset_before, offset_after; +}; + +/* Single range specification. */ +struct nf_nat_range +{ + /* Set to OR of flags above. */ + unsigned int flags; + + /* Inclusive: network order. */ + __be32 min_ip, max_ip; + + /* Inclusive: network order */ + union nf_conntrack_man_proto min, max; +}; + +/* For backwards compat: don't use in modern code. */ +struct nf_nat_multi_range_compat +{ + unsigned int rangesize; /* Must be 1. */ + + /* hangs off end. */ + struct nf_nat_range range[1]; +}; + +#ifdef __KERNEL__ +#include + +/* The structure embedded in the conntrack structure. */ +struct nf_nat_info +{ + struct list_head bysource; + struct nf_nat_seq seq[IP_CT_DIR_MAX]; +}; + +struct nf_conn; + +/* Set up the info structure to map into this range. */ +extern unsigned int nf_nat_setup_info(struct nf_conn *ct, + const struct nf_nat_range *range, + unsigned int hooknum); + +/* Is this tuple already taken? (not by us)*/ +extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack); + +extern int nf_nat_module_is_loaded; + +#else /* !__KERNEL__: iptables wants this to compile. */ +#define nf_nat_multi_range nf_nat_multi_range_compat +#endif /*__KERNEL__*/ +#endif diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h new file mode 100644 index 000000000000..9778ffa93440 --- /dev/null +++ b/include/net/netfilter/nf_nat_core.h @@ -0,0 +1,27 @@ +#ifndef _NF_NAT_CORE_H +#define _NF_NAT_CORE_H +#include +#include + +/* This header used to share core functionality between the standalone + NAT module, and the compatibility layer's use of NAT for masquerading. */ + +extern unsigned int nf_nat_packet(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb); + +extern int nf_nat_icmp_reply_translation(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb); + +static inline int nf_nat_initialized(struct nf_conn *ct, + enum nf_nat_manip_type manip) +{ + if (manip == IP_NAT_MANIP_SRC) + return test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); + else + return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status); +} +#endif /* _NF_NAT_CORE_H */ diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h new file mode 100644 index 000000000000..ec98ecf95fc8 --- /dev/null +++ b/include/net/netfilter/nf_nat_helper.h @@ -0,0 +1,32 @@ +#ifndef _NF_NAT_HELPER_H +#define _NF_NAT_HELPER_H +/* NAT protocol helper routines. */ + +#include + +struct sk_buff; + +/* These return true or false. */ +extern int nf_nat_mangle_tcp_packet(struct sk_buff **skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len); +extern int nf_nat_mangle_udp_packet(struct sk_buff **skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len); +extern int nf_nat_seq_adjust(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); + +/* Setup NAT on this expected conntrack so it follows master, but goes + * to port ct->master->saved_proto. */ +extern void nf_nat_follow_master(struct nf_conn *ct, + struct nf_conntrack_expect *this); +#endif diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h new file mode 100644 index 000000000000..a9ec5ef61468 --- /dev/null +++ b/include/net/netfilter/nf_nat_protocol.h @@ -0,0 +1,70 @@ +/* Header for use in defining a given protocol. */ +#ifndef _NF_NAT_PROTOCOL_H +#define _NF_NAT_PROTOCOL_H +#include +#include + +struct nf_nat_range; + +struct nf_nat_protocol +{ + /* Protocol name */ + const char *name; + + /* Protocol number. */ + unsigned int protonum; + + struct module *me; + + /* Translate a packet to the target according to manip type. + Return true if succeeded. */ + int (*manip_pkt)(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype); + + /* Is the manipable part of the tuple between min and max incl? */ + int (*in_range)(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); + + /* Alter the per-proto part of the tuple (depending on + maniptype), to give a unique tuple in the given range if + possible; return false if not. Per-protocol part of tuple + is initialized to the incoming packet. */ + int (*unique_tuple)(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct); + + int (*range_to_nfattr)(struct sk_buff *skb, + const struct nf_nat_range *range); + + int (*nfattr_to_range)(struct nfattr *tb[], + struct nf_nat_range *range); +}; + +/* Protocol registration. */ +extern int nf_nat_protocol_register(struct nf_nat_protocol *proto); +extern void nf_nat_protocol_unregister(struct nf_nat_protocol *proto); + +extern struct nf_nat_protocol *nf_nat_proto_find_get(u_int8_t protocol); +extern void nf_nat_proto_put(struct nf_nat_protocol *proto); + +/* Built-in protocols. */ +extern struct nf_nat_protocol nf_nat_protocol_tcp; +extern struct nf_nat_protocol nf_nat_protocol_udp; +extern struct nf_nat_protocol nf_nat_protocol_icmp; +extern struct nf_nat_protocol nf_nat_unknown_protocol; + +extern int init_protocols(void) __init; +extern void cleanup_protocols(void); +extern struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); + +extern int nf_nat_port_range_to_nfattr(struct sk_buff *skb, + const struct nf_nat_range *range); +extern int nf_nat_port_nfattr_to_range(struct nfattr *tb[], + struct nf_nat_range *range); + +#endif /*_NF_NAT_PROTO_H*/ diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h new file mode 100644 index 000000000000..f191c672bcc6 --- /dev/null +++ b/include/net/netfilter/nf_nat_rule.h @@ -0,0 +1,35 @@ +#ifndef _NF_NAT_RULE_H +#define _NF_NAT_RULE_H +#include +#include +#include + +/* Compatibility definitions for ipt_FOO modules */ +#define ip_nat_range nf_nat_range +#define ip_conntrack_tuple nf_conntrack_tuple +#define ip_conntrack_get nf_ct_get +#define ip_conntrack nf_conn +#define ip_nat_setup_info nf_nat_setup_info +#define ip_nat_multi_range_compat nf_nat_multi_range_compat +#define ip_ct_iterate_cleanup nf_ct_iterate_cleanup +#define IP_NF_ASSERT NF_CT_ASSERT + +extern int nf_nat_rule_init(void) __init; +extern void nf_nat_rule_cleanup(void); +extern int nf_nat_rule_find(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct nf_conn *ct, + struct nf_nat_info *info); + +extern unsigned int +alloc_null_binding(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum); + +extern unsigned int +alloc_null_binding_confirmed(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum); +#endif /* _NF_NAT_RULE_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 71485276b819..01789aeaeb5f 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration" depends on INET && NETFILTER config NF_CONNTRACK_IPV4 - tristate "IPv4 support for new connection tracking (EXPERIMENTAL)" + tristate "IPv4 support for new connection tracking (required for NAT) (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK ---help--- Connection tracking keeps a record of what packets have passed @@ -387,7 +387,7 @@ config IP_NF_TARGET_TCPMSS To compile it as a module, choose M here. If unsure, say N. -# NAT + specific targets +# NAT + specific targets: ip_conntrack config IP_NF_NAT tristate "Full NAT" depends on IP_NF_IPTABLES && IP_NF_CONNTRACK @@ -398,14 +398,30 @@ config IP_NF_NAT To compile it as a module, choose M here. If unsure, say N. +# NAT + specific targets: nf_conntrack +config NF_NAT + tristate "Full NAT" + depends on IP_NF_IPTABLES && NF_CONNTRACK + help + The Full NAT option allows masquerading, port forwarding and other + forms of full Network Address Port Translation. It is controlled by + the `nat' table in iptables: see the man page for iptables(8). + + To compile it as a module, choose M here. If unsure, say N. + config IP_NF_NAT_NEEDED bool - depends on IP_NF_NAT != n + depends on IP_NF_NAT + default y + +config NF_NAT_NEEDED + bool + depends on NF_NAT default y config IP_NF_TARGET_MASQUERADE tristate "MASQUERADE target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help Masquerading is a special case of NAT: all outgoing connections are changed to seem to come from a particular interface's address, and @@ -417,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE config IP_NF_TARGET_REDIRECT tristate "REDIRECT target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help REDIRECT is a special case of NAT: all incoming connections are mapped onto the incoming interface's address, causing the packets to @@ -428,7 +444,7 @@ config IP_NF_TARGET_REDIRECT config IP_NF_TARGET_NETMAP tristate "NETMAP target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help NETMAP is an implementation of static 1:1 NAT mapping of network addresses. It maps the network address part, while keeping the host @@ -439,7 +455,7 @@ config IP_NF_TARGET_NETMAP config IP_NF_TARGET_SAME tristate "SAME target support" - depends on IP_NF_NAT + depends on (NF_NAT || IP_NF_NAT) help This option adds a `SAME' target, which works like the standard SNAT target, but attempts to give clients the same IP for all connections. diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 21359d83f0c7..ec31690764ac 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -5,7 +5,12 @@ # objects for the standalone - connection tracking / NAT ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o +nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o +ifneq ($(CONFIG_NF_NAT),) +iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o +else iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o +endif ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o @@ -16,6 +21,7 @@ ip_nat_h323-objs := ip_nat_helper_h323.o # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o obj-$(CONFIG_IP_NF_NAT) += ip_nat.o +obj-$(CONFIG_NF_NAT) += nf_nat.o # conntrack netlink interface obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o @@ -50,6 +56,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o +obj-$(CONFIG_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o # matches diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index d85d2de50449..ad66328baa5d 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -44,12 +44,6 @@ #define DEBUGP(format, args...) #endif -#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ - : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ - : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ - : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ - : "*ERROR*"))) - #ifdef CONFIG_XFRM static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) { diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 3dbfcfac8a84..28b9233956b5 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -2,7 +2,7 @@ (depending on route). */ /* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team + * (C) 2002-2006 Netfilter Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -20,7 +20,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #include MODULE_LICENSE("GPL"); @@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb, const struct xt_target *target, const void *targinfo) { +#ifdef CONFIG_NF_NAT_NEEDED + struct nf_conn_nat *nat; +#endif struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; - const struct ip_nat_multi_range_compat *mr; struct ip_nat_range newrange; + const struct ip_nat_multi_range_compat *mr; struct rtable *rt; __be32 newsrc; IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); ct = ip_conntrack_get(*pskb, &ctinfo); +#ifdef CONFIG_NF_NAT_NEEDED + nat = nfct_nat(ct); +#endif IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); /* Source address is 0.0.0.0 - locally generated packet that is * probably not supposed to be masqueraded. */ +#ifdef CONFIG_NF_NAT_NEEDED + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) +#else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) +#endif return NF_ACCEPT; mr = targinfo; @@ -93,7 +107,11 @@ masquerade_target(struct sk_buff **pskb, } write_lock_bh(&masq_lock); +#ifdef CONFIG_NF_NAT_NEEDED + nat->masq_index = out->ifindex; +#else ct->nat.masq_index = out->ifindex; +#endif write_unlock_bh(&masq_lock); /* Transfer from original range. */ @@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb, static inline int device_cmp(struct ip_conntrack *i, void *ifindex) { +#ifdef CONFIG_NF_NAT_NEEDED + struct nf_conn_nat *nat = nfct_nat(i); +#endif int ret; read_lock_bh(&masq_lock); +#ifdef CONFIG_NF_NAT_NEEDED + ret = (nat->masq_index == (int)(long)ifindex); +#else ret = (i->nat.masq_index == (int)(long)ifindex); +#endif read_unlock_bh(&masq_lock); return ret; diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index 58a88f227108..9390e90f2b25 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c @@ -15,7 +15,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #define MODULENAME "NETMAP" MODULE_LICENSE("GPL"); diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index c0dcfe9d610c..462eceb3a1b1 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c @@ -1,6 +1,6 @@ /* Redirect. Simple mapping which alters dst to a local IP address. */ /* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team + * (C) 2002-2006 Netfilter Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,7 +18,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index b38b13328d73..3dcf29411337 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c @@ -34,7 +34,11 @@ #include #include #include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#else #include +#endif #include MODULE_LICENSE("GPL"); @@ -152,11 +156,17 @@ same_target(struct sk_buff **pskb, Here we calculate the index in same->iparray which holds the ipaddress we should use */ +#ifdef CONFIG_NF_NAT_NEEDED + tmpip = ntohl(t->src.u3.ip); + + if (!(same->info & IPT_SAME_NODST)) + tmpip += ntohl(t->dst.u3.ip); +#else tmpip = ntohl(t->src.ip); if (!(same->info & IPT_SAME_NODST)) tmpip += ntohl(t->dst.ip); - +#endif aindex = tmpip % same->ipnum; new_ip = htonl(same->iparray[aindex]); diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 653f57b8a107..5655109dcaff 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -111,10 +111,10 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, return NF_ACCEPT; } -int nat_module_is_loaded = 0; +int nf_nat_module_is_loaded = 0; static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) { - if (nat_module_is_loaded) + if (nf_nat_module_is_loaded) return NF_CT_F_NAT; return NF_CT_F_BASIC; @@ -532,3 +532,6 @@ module_init(nf_conntrack_l3proto_ipv4_init); module_exit(nf_conntrack_l3proto_ipv4_fini); EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); +#ifdef CONFIG_NF_NAT_NEEDED +EXPORT_SYMBOL(nf_nat_module_is_loaded); +#endif diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c new file mode 100644 index 000000000000..86a92272b053 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -0,0 +1,647 @@ +/* NAT for netfilter; shared with compatibility layer. */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For tcp_prot in getorigdst */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static DEFINE_RWLOCK(nf_nat_lock); + +static struct nf_conntrack_l3proto *l3proto = NULL; + +/* Calculated at init based on memory size */ +static unsigned int nf_nat_htable_size; + +static struct list_head *bysource; + +#define MAX_IP_NAT_PROTO 256 +static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; + +static inline struct nf_nat_protocol * +__nf_nat_proto_find(u_int8_t protonum) +{ + return nf_nat_protos[protonum]; +} + +struct nf_nat_protocol * +nf_nat_proto_find_get(u_int8_t protonum) +{ + struct nf_nat_protocol *p; + + /* we need to disable preemption to make sure 'p' doesn't get + * removed until we've grabbed the reference */ + preempt_disable(); + p = __nf_nat_proto_find(protonum); + if (!try_module_get(p->me)) + p = &nf_nat_unknown_protocol; + preempt_enable(); + + return p; +} +EXPORT_SYMBOL_GPL(nf_nat_proto_find_get); + +void +nf_nat_proto_put(struct nf_nat_protocol *p) +{ + module_put(p->me); +} +EXPORT_SYMBOL_GPL(nf_nat_proto_put); + +/* We keep an extra hash for each conntrack, for fast searching. */ +static inline unsigned int +hash_by_src(const struct nf_conntrack_tuple *tuple) +{ + /* Original src, to ensure we map it consistently if poss. */ + return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all, + tuple->dst.protonum, 0) % nf_nat_htable_size; +} + +/* Noone using conntrack by the time this called. */ +static void nf_nat_cleanup_conntrack(struct nf_conn *conn) +{ + struct nf_conn_nat *nat; + if (!(conn->status & IPS_NAT_DONE_MASK)) + return; + + nat = nfct_nat(conn); + write_lock_bh(&nf_nat_lock); + list_del(&nat->info.bysource); + write_unlock_bh(&nf_nat_lock); +} + +/* Is this tuple already taken? (not by us) */ +int +nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack) +{ + /* Conntrack tracking doesn't keep track of outgoing tuples; only + incoming ones. NAT means they don't have a fixed mapping, + so we invert the tuple and look for the incoming reply. + + We could keep a separate hash if this proves too slow. */ + struct nf_conntrack_tuple reply; + + nf_ct_invert_tuplepr(&reply, tuple); + return nf_conntrack_tuple_taken(&reply, ignored_conntrack); +} +EXPORT_SYMBOL(nf_nat_used_tuple); + +/* If we source map this tuple so reply looks like reply_tuple, will + * that meet the constraints of range. */ +static int +in_range(const struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range) +{ + struct nf_nat_protocol *proto; + + proto = __nf_nat_proto_find(tuple->dst.protonum); + /* If we are supposed to map IPs, then we must be in the + range specified, otherwise let this drag us onto a new src IP. */ + if (range->flags & IP_NAT_RANGE_MAP_IPS) { + if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) || + ntohl(tuple->src.u3.ip) > ntohl(range->max_ip)) + return 0; + } + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || + proto->in_range(tuple, IP_NAT_MANIP_SRC, + &range->min, &range->max)) + return 1; + + return 0; +} + +static inline int +same_src(const struct nf_conn *ct, + const struct nf_conntrack_tuple *tuple) +{ + const struct nf_conntrack_tuple *t; + + t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + return (t->dst.protonum == tuple->dst.protonum && + t->src.u3.ip == tuple->src.u3.ip && + t->src.u.all == tuple->src.u.all); +} + +/* Only called for SRC manip */ +static int +find_appropriate_src(const struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *result, + const struct nf_nat_range *range) +{ + unsigned int h = hash_by_src(tuple); + struct nf_conn_nat *nat; + struct nf_conn *ct; + + read_lock_bh(&nf_nat_lock); + list_for_each_entry(nat, &bysource[h], info.bysource) { + ct = (struct nf_conn *)((char *)nat - offsetof(struct nf_conn, data)); + if (same_src(ct, tuple)) { + /* Copy source part from reply tuple. */ + nf_ct_invert_tuplepr(result, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + result->dst = tuple->dst; + + if (in_range(result, range)) { + read_unlock_bh(&nf_nat_lock); + return 1; + } + } + } + read_unlock_bh(&nf_nat_lock); + return 0; +} + +/* For [FUTURE] fragmentation handling, we want the least-used + src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus + if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports + 1-65535, we don't do pro-rata allocation based on ports; we choose + the ip with the lowest src-ip/dst-ip/proto usage. +*/ +static void +find_best_ips_proto(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + const struct nf_conn *ct, + enum nf_nat_manip_type maniptype) +{ + __be32 *var_ipp; + /* Host order */ + u_int32_t minip, maxip, j; + + /* No IP mapping? Do nothing. */ + if (!(range->flags & IP_NAT_RANGE_MAP_IPS)) + return; + + if (maniptype == IP_NAT_MANIP_SRC) + var_ipp = &tuple->src.u3.ip; + else + var_ipp = &tuple->dst.u3.ip; + + /* Fast path: only one choice. */ + if (range->min_ip == range->max_ip) { + *var_ipp = range->min_ip; + return; + } + + /* Hashing source and destination IPs gives a fairly even + * spread in practice (if there are a small number of IPs + * involved, there usually aren't that many connections + * anyway). The consistency means that servers see the same + * client coming from the same IP (some Internet Banking sites + * like this), even across reboots. */ + minip = ntohl(range->min_ip); + maxip = ntohl(range->max_ip); + j = jhash_2words((__force u32)tuple->src.u3.ip, + (__force u32)tuple->dst.u3.ip, 0); + *var_ipp = htonl(minip + j % (maxip - minip + 1)); +} + +/* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING, + * we change the source to map into the range. For NF_IP_PRE_ROUTING + * and NF_IP_LOCAL_OUT, we change the destination to map into the + * range. It might not be possible to get a unique tuple, but we try. + * At worst (or if we race), we will end up with a final duplicate in + * __ip_conntrack_confirm and drop the packet. */ +static void +get_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig_tuple, + const struct nf_nat_range *range, + struct nf_conn *ct, + enum nf_nat_manip_type maniptype) +{ + struct nf_nat_protocol *proto; + + /* 1) If this srcip/proto/src-proto-part is currently mapped, + and that same mapping gives a unique tuple within the given + range, use that. + + This is only required for source (ie. NAT/masq) mappings. + So far, we don't do local source mappings, so multiple + manips not an issue. */ + if (maniptype == IP_NAT_MANIP_SRC) { + if (find_appropriate_src(orig_tuple, tuple, range)) { + DEBUGP("get_unique_tuple: Found current src map\n"); + if (!nf_nat_used_tuple(tuple, ct)) + return; + } + } + + /* 2) Select the least-used IP/proto combination in the given + range. */ + *tuple = *orig_tuple; + find_best_ips_proto(tuple, range, ct, maniptype); + + /* 3) The per-protocol part of the manip is made to map into + the range to make a unique tuple. */ + + proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); + + /* Only bother mapping if it's not already in range and unique */ + if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || + proto->in_range(tuple, maniptype, &range->min, &range->max)) && + !nf_nat_used_tuple(tuple, ct)) { + nf_nat_proto_put(proto); + return; + } + + /* Last change: get protocol to try to obtain unique tuple. */ + proto->unique_tuple(tuple, range, maniptype, ct); + + nf_nat_proto_put(proto); +} + +unsigned int +nf_nat_setup_info(struct nf_conn *ct, + const struct nf_nat_range *range, + unsigned int hooknum) +{ + struct nf_conntrack_tuple curr_tuple, new_tuple; + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_info *info = &nat->info; + int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); + + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_POST_ROUTING || + hooknum == NF_IP_LOCAL_IN || + hooknum == NF_IP_LOCAL_OUT); + BUG_ON(nf_nat_initialized(ct, maniptype)); + + /* What we've got will look like inverse of reply. Normally + this is what is in the conntrack, except for prior + manipulations (future optimization: if num_manips == 0, + orig_tp = + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ + nf_ct_invert_tuplepr(&curr_tuple, + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype); + + if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) { + struct nf_conntrack_tuple reply; + + /* Alter conntrack table so will recognize replies. */ + nf_ct_invert_tuplepr(&reply, &new_tuple); + nf_conntrack_alter_reply(ct, &reply); + + /* Non-atomic: we own this at the moment. */ + if (maniptype == IP_NAT_MANIP_SRC) + ct->status |= IPS_SRC_NAT; + else + ct->status |= IPS_DST_NAT; + } + + /* Place in source hash if this is the first time. */ + if (have_to_hash) { + unsigned int srchash; + + srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + write_lock_bh(&nf_nat_lock); + list_add(&info->bysource, &bysource[srchash]); + write_unlock_bh(&nf_nat_lock); + } + + /* It's done. */ + if (maniptype == IP_NAT_MANIP_DST) + set_bit(IPS_DST_NAT_DONE_BIT, &ct->status); + else + set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); + + return NF_ACCEPT; +} +EXPORT_SYMBOL(nf_nat_setup_info); + +/* Returns true if succeeded. */ +static int +manip_pkt(u_int16_t proto, + struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *target, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph; + struct nf_nat_protocol *p; + + if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) + return 0; + + iph = (void *)(*pskb)->data + iphdroff; + + /* Manipulate protcol part. */ + p = nf_nat_proto_find_get(proto); + if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { + nf_nat_proto_put(p); + return 0; + } + nf_nat_proto_put(p); + + iph = (void *)(*pskb)->data + iphdroff; + + if (maniptype == IP_NAT_MANIP_SRC) { + nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip); + iph->saddr = target->src.u3.ip; + } else { + nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); + iph->daddr = target->dst.u3.ip; + } + return 1; +} + +/* Do packet manipulations according to nf_nat_setup_info. */ +unsigned int nf_nat_packet(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned long statusbit; + enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); + + if (mtype == IP_NAT_MANIP_SRC) + statusbit = IPS_SRC_NAT; + else + statusbit = IPS_DST_NAT; + + /* Invert if this is reply dir. */ + if (dir == IP_CT_DIR_REPLY) + statusbit ^= IPS_NAT_MASK; + + /* Non-atomic: these bits don't change. */ + if (ct->status & statusbit) { + struct nf_conntrack_tuple target; + + /* We are aiming to look like inverse of other direction. */ + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + + if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype)) + return NF_DROP; + } + return NF_ACCEPT; +} +EXPORT_SYMBOL_GPL(nf_nat_packet); + +/* Dir is direction ICMP is coming from (opposite to packet it contains) */ +int nf_nat_icmp_reply_translation(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct { + struct icmphdr icmp; + struct iphdr ip; + } *inside; + struct nf_conntrack_tuple inner, target; + int hdrlen = (*pskb)->nh.iph->ihl * 4; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned long statusbit; + enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); + + if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) + return 0; + + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + + /* We're actually going to mangle it beyond trivial checksum + adjustment, so make sure the current checksum is correct. */ + if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) + return 0; + + /* Must be RELATED */ + NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || + (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY); + + /* Redirects on non-null nats must be dropped, else they'll + start talking to each other without our translation, and be + confused... --RR */ + if (inside->icmp.type == ICMP_REDIRECT) { + /* If NAT isn't finished, assume it and drop. */ + if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) + return 0; + + if (ct->status & IPS_NAT_MASK) + return 0; + } + + DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", + *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); + + if (!nf_ct_get_tuple(*pskb, + (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr), + (*pskb)->nh.iph->ihl*4 + + sizeof(struct icmphdr) + inside->ip.ihl*4, + (u_int16_t)AF_INET, + inside->ip.protocol, + &inner, + l3proto, + __nf_ct_l4proto_find((u_int16_t)PF_INET, + inside->ip.protocol))) + return 0; + + /* Change inner back to look like incoming packet. We do the + opposite manip on this hook to normal, because it might not + pass all hooks (locally-generated ICMP). Consider incoming + packet: PREROUTING (DST manip), routing produces ICMP, goes + through POSTROUTING (which must correct the DST manip). */ + if (!manip_pkt(inside->ip.protocol, pskb, + (*pskb)->nh.iph->ihl*4 + sizeof(inside->icmp), + &ct->tuplehash[!dir].tuple, + !manip)) + return 0; + + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + /* Reloading "inside" here since manip_pkt inner. */ + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + inside->icmp.checksum = 0; + inside->icmp.checksum = + csum_fold(skb_checksum(*pskb, hdrlen, + (*pskb)->len - hdrlen, 0)); + } + + /* Change outer to look the reply to an incoming packet + * (proto 0 means don't invert per-proto part). */ + if (manip == IP_NAT_MANIP_SRC) + statusbit = IPS_SRC_NAT; + else + statusbit = IPS_DST_NAT; + + /* Invert if this is reply dir. */ + if (dir == IP_CT_DIR_REPLY) + statusbit ^= IPS_NAT_MASK; + + if (ct->status & statusbit) { + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + if (!manip_pkt(0, pskb, 0, &target, manip)) + return 0; + } + + return 1; +} +EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); + +/* Protocol registration. */ +int nf_nat_protocol_register(struct nf_nat_protocol *proto) +{ + int ret = 0; + + write_lock_bh(&nf_nat_lock); + if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { + ret = -EBUSY; + goto out; + } + nf_nat_protos[proto->protonum] = proto; + out: + write_unlock_bh(&nf_nat_lock); + return ret; +} +EXPORT_SYMBOL(nf_nat_protocol_register); + +/* Noone stores the protocol anywhere; simply delete it. */ +void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) +{ + write_lock_bh(&nf_nat_lock); + nf_nat_protos[proto->protonum] = &nf_nat_unknown_protocol; + write_unlock_bh(&nf_nat_lock); + + /* Someone could be still looking at the proto in a bh. */ + synchronize_net(); +} +EXPORT_SYMBOL(nf_nat_protocol_unregister); + +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) +int +nf_nat_port_range_to_nfattr(struct sk_buff *skb, + const struct nf_nat_range *range) +{ + NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), + &range->min.tcp.port); + NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), + &range->max.tcp.port); + + return 0; + +nfattr_failure: + return -1; +} +EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); + +int +nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) +{ + int ret = 0; + + /* we have to return whether we actually parsed something or not */ + + if (tb[CTA_PROTONAT_PORT_MIN-1]) { + ret = 1; + range->min.tcp.port = + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); + } + + if (!tb[CTA_PROTONAT_PORT_MAX-1]) { + if (ret) + range->max.tcp.port = range->min.tcp.port; + } else { + ret = 1; + range->max.tcp.port = + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); + } + + return ret; +} +EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); +#endif + +static int __init nf_nat_init(void) +{ + size_t i; + + /* Leave them the same for the moment. */ + nf_nat_htable_size = nf_conntrack_htable_size; + + /* One vmalloc for both hash tables */ + bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); + if (!bysource) + return -ENOMEM; + + /* Sew in builtin protocols. */ + write_lock_bh(&nf_nat_lock); + for (i = 0; i < MAX_IP_NAT_PROTO; i++) + nf_nat_protos[i] = &nf_nat_unknown_protocol; + nf_nat_protos[IPPROTO_TCP] = &nf_nat_protocol_tcp; + nf_nat_protos[IPPROTO_UDP] = &nf_nat_protocol_udp; + nf_nat_protos[IPPROTO_ICMP] = &nf_nat_protocol_icmp; + write_unlock_bh(&nf_nat_lock); + + for (i = 0; i < nf_nat_htable_size; i++) { + INIT_LIST_HEAD(&bysource[i]); + } + + /* FIXME: Man, this is a hack. */ + NF_CT_ASSERT(nf_conntrack_destroyed == NULL); + nf_conntrack_destroyed = &nf_nat_cleanup_conntrack; + + /* Initialize fake conntrack so that NAT will skip it */ + nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; + + l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + return 0; +} + +/* Clear NAT section of all conntracks, in case we're loaded again. */ +static int clean_nat(struct nf_conn *i, void *data) +{ + struct nf_conn_nat *nat = nfct_nat(i); + + if (!nat) + return 0; + memset(nat, 0, sizeof(nat)); + i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); + return 0; +} + +static void __exit nf_nat_cleanup(void) +{ + nf_ct_iterate_cleanup(&clean_nat, NULL); + nf_conntrack_destroyed = NULL; + vfree(bysource); + nf_ct_l3proto_put(l3proto); +} + +MODULE_LICENSE("GPL"); + +module_init(nf_nat_init); +module_exit(nf_nat_cleanup); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c new file mode 100644 index 000000000000..98fbfc84d183 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -0,0 +1,433 @@ +/* ip_nat_helper.c - generic support functions for NAT helpers + * + * (C) 2000-2002 Harald Welte + * (C) 2003-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); +#else +#define DEBUGP(format, args...) +#define DUMP_OFFSET(x) +#endif + +static DEFINE_SPINLOCK(nf_nat_seqofs_lock); + +/* Setup TCP sequence correction given this change at this sequence */ +static inline void +adjust_tcp_sequence(u32 seq, + int sizediff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + int dir; + struct nf_nat_seq *this_way, *other_way; + struct nf_conn_nat *nat = nfct_nat(ct); + + DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n", + (*skb)->len, new_size); + + dir = CTINFO2DIR(ctinfo); + + this_way = &nat->info.seq[dir]; + other_way = &nat->info.seq[!dir]; + + DEBUGP("nf_nat_resize_packet: Seq_offset before: "); + DUMP_OFFSET(this_way); + + spin_lock_bh(&nf_nat_seqofs_lock); + + /* SYN adjust. If it's uninitialized, or this is after last + * correction, record it: we don't handle more than one + * adjustment in the window, but do deal with common case of a + * retransmit */ + if (this_way->offset_before == this_way->offset_after || + before(this_way->correction_pos, seq)) { + this_way->correction_pos = seq; + this_way->offset_before = this_way->offset_after; + this_way->offset_after += sizediff; + } + spin_unlock_bh(&nf_nat_seqofs_lock); + + DEBUGP("nf_nat_resize_packet: Seq_offset after: "); + DUMP_OFFSET(this_way); +} + +/* Frobs data inside this packet, which is linear. */ +static void mangle_contents(struct sk_buff *skb, + unsigned int dataoff, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + unsigned char *data; + + BUG_ON(skb_is_nonlinear(skb)); + data = (unsigned char *)skb->nh.iph + dataoff; + + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, + skb->tail - (data + match_offset + match_len)); + + /* insert data from buffer */ + memcpy(data + match_offset, rep_buffer, rep_len); + + /* update skb info */ + if (rep_len > match_len) { + DEBUGP("nf_nat_mangle_packet: Extending packet by " + "%u from %u bytes\n", rep_len - match_len, + skb->len); + skb_put(skb, rep_len - match_len); + } else { + DEBUGP("nf_nat_mangle_packet: Shrinking packet from " + "%u from %u bytes\n", match_len - rep_len, + skb->len); + __skb_trim(skb, skb->len + rep_len - match_len); + } + + /* fix IP hdr checksum information */ + skb->nh.iph->tot_len = htons(skb->len); + ip_send_check(skb->nh.iph); +} + +/* Unusual, but possible case. */ +static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) +{ + struct sk_buff *nskb; + + if ((*pskb)->len + extra > 65535) + return 0; + + nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); + if (!nskb) + return 0; + + /* Transfer socket to new skb. */ + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); + kfree_skb(*pskb); + *pskb = nskb; + return 1; +} + +/* Generic function for mangling variable-length address changes inside + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX + * command in FTP). + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... + * + * */ +int +nf_nat_mangle_tcp_packet(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + struct iphdr *iph; + struct tcphdr *tcph; + int oldlen, datalen; + + if (!skb_make_writable(pskb, (*pskb)->len)) + return 0; + + if (rep_len > match_len && + rep_len - match_len > skb_tailroom(*pskb) && + !enlarge_skb(pskb, rep_len - match_len)) + return 0; + + SKB_LINEAR_ASSERT(*pskb); + + iph = (*pskb)->nh.iph; + tcph = (void *)iph + iph->ihl*4; + + oldlen = (*pskb)->len - iph->ihl*4; + mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, + match_offset, match_len, rep_buffer, rep_len); + + datalen = (*pskb)->len - iph->ihl*4; + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, datalen, + iph->saddr, iph->daddr, + csum_partial((char *)tcph, + datalen, 0)); + } else + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldlen), htons(datalen), 1); + + if (rep_len != match_len) { + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); + adjust_tcp_sequence(ntohl(tcph->seq), + (int)rep_len - (int)match_len, + ct, ctinfo); + /* Tell TCP window tracking about seq change */ + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, + ct, CTINFO2DIR(ctinfo)); + } + return 1; +} +EXPORT_SYMBOL(nf_nat_mangle_tcp_packet); + +/* Generic function for mangling variable-length address changes inside + * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX + * command in the Amanda protocol) + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... + * + * XXX - This function could be merged with nf_nat_mangle_tcp_packet which + * should be fairly easy to do. + */ +int +nf_nat_mangle_udp_packet(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + struct iphdr *iph; + struct udphdr *udph; + int datalen, oldlen; + + /* UDP helpers might accidentally mangle the wrong packet */ + iph = (*pskb)->nh.iph; + if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + + match_offset + match_len) + return 0; + + if (!skb_make_writable(pskb, (*pskb)->len)) + return 0; + + if (rep_len > match_len && + rep_len - match_len > skb_tailroom(*pskb) && + !enlarge_skb(pskb, rep_len - match_len)) + return 0; + + iph = (*pskb)->nh.iph; + udph = (void *)iph + iph->ihl*4; + + oldlen = (*pskb)->len - iph->ihl*4; + mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), + match_offset, match_len, rep_buffer, rep_len); + + /* update the length of the UDP packet */ + datalen = (*pskb)->len - iph->ihl*4; + udph->len = htons(datalen); + + /* fix udp checksum if udp checksum was previously calculated */ + if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) + return 1; + + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { + udph->check = 0; + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, + datalen, IPPROTO_UDP, + csum_partial((char *)udph, + datalen, 0)); + if (!udph->check) + udph->check = CSUM_MANGLED_0; + } else + nf_proto_csum_replace2(&udph->check, *pskb, + htons(oldlen), htons(datalen), 1); + + return 1; +} +EXPORT_SYMBOL(nf_nat_mangle_udp_packet); + +/* Adjust one found SACK option including checksum correction */ +static void +sack_adjust(struct sk_buff *skb, + struct tcphdr *tcph, + unsigned int sackoff, + unsigned int sackend, + struct nf_nat_seq *natseq) +{ + while (sackoff < sackend) { + struct tcp_sack_block_wire *sack; + __be32 new_start_seq, new_end_seq; + + sack = (void *)skb->data + sackoff; + if (after(ntohl(sack->start_seq) - natseq->offset_before, + natseq->correction_pos)) + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_after); + else + new_start_seq = htonl(ntohl(sack->start_seq) + - natseq->offset_before); + + if (after(ntohl(sack->end_seq) - natseq->offset_before, + natseq->correction_pos)) + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_after); + else + new_end_seq = htonl(ntohl(sack->end_seq) + - natseq->offset_before); + + DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", + ntohl(sack->start_seq), new_start_seq, + ntohl(sack->end_seq), new_end_seq); + + nf_proto_csum_replace4(&tcph->check, skb, + sack->start_seq, new_start_seq, 0); + nf_proto_csum_replace4(&tcph->check, skb, + sack->end_seq, new_end_seq, 0); + sack->start_seq = new_start_seq; + sack->end_seq = new_end_seq; + sackoff += sizeof(*sack); + } +} + +/* TCP SACK sequence number adjustment */ +static inline unsigned int +nf_nat_sack_adjust(struct sk_buff **pskb, + struct tcphdr *tcph, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + unsigned int dir, optoff, optend; + struct nf_conn_nat *nat = nfct_nat(ct); + + optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr); + optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4; + + if (!skb_make_writable(pskb, optend)) + return 0; + + dir = CTINFO2DIR(ctinfo); + + while (optoff < optend) { + /* Usually: option, length. */ + unsigned char *op = (*pskb)->data + optoff; + + switch (op[0]) { + case TCPOPT_EOL: + return 1; + case TCPOPT_NOP: + optoff++; + continue; + default: + /* no partial options */ + if (optoff + 1 == optend || + optoff + op[1] > optend || + op[1] < 2) + return 0; + if (op[0] == TCPOPT_SACK && + op[1] >= 2+TCPOLEN_SACK_PERBLOCK && + ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) + sack_adjust(*pskb, tcph, optoff+2, + optoff+op[1], + &nat->info.seq[!dir]); + optoff += op[1]; + } + } + return 1; +} + +/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ +int +nf_nat_seq_adjust(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct tcphdr *tcph; + int dir; + __be32 newseq, newack; + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_seq *this_way, *other_way; + + dir = CTINFO2DIR(ctinfo); + + this_way = &nat->info.seq[dir]; + other_way = &nat->info.seq[!dir]; + + if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) + return 0; + + tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + if (after(ntohl(tcph->seq), this_way->correction_pos)) + newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); + else + newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); + + if (after(ntohl(tcph->ack_seq) - other_way->offset_before, + other_way->correction_pos)) + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); + else + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); + + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); + + DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", + ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), + ntohl(newack)); + + tcph->seq = newseq; + tcph->ack_seq = newack; + + if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo)) + return 0; + + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir); + + return 1; +} +EXPORT_SYMBOL(nf_nat_seq_adjust); + +/* Setup NAT on this expected conntrack so it follows master. */ +/* If we fail to get a free NAT slot, we'll get dropped on confirm */ +void nf_nat_follow_master(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = exp->saved_proto; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); +} +EXPORT_SYMBOL(nf_nat_follow_master); diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c new file mode 100644 index 000000000000..dcfd772972d7 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -0,0 +1,86 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +icmp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && + ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); +} + +static int +icmp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t id; + unsigned int range_size; + unsigned int i; + + range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) + range_size = 0xFFFF; + + for (i = 0; i < range_size; i++, id++) { + tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + + (id % range_size)); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +icmp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct icmphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + return 0; + + hdr = (struct icmphdr *)((*pskb)->data + hdroff); + nf_proto_csum_replace2(&hdr->checksum, *pskb, + hdr->un.echo.id, tuple->src.u.icmp.id, 0); + hdr->un.echo.id = tuple->src.u.icmp.id; + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_icmp = { + .name = "ICMP", + .protonum = IPPROTO_ICMP, + .me = THIS_MODULE, + .manip_pkt = icmp_manip_pkt, + .in_range = icmp_in_range, + .unique_tuple = icmp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c new file mode 100644 index 000000000000..7e26a7e9bee1 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -0,0 +1,148 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int +tcp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 port; + + if (maniptype == IP_NAT_MANIP_SRC) + port = tuple->src.u.tcp.port; + else + port = tuple->dst.u.tcp.port; + + return ntohs(port) >= ntohs(min->tcp.port) && + ntohs(port) <= ntohs(max->tcp.port); +} + +static int +tcp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t port; + __be16 *portptr; + unsigned int range_size, min, i; + + if (maniptype == IP_NAT_MANIP_SRC) + portptr = &tuple->src.u.tcp.port; + else + portptr = &tuple->dst.u.tcp.port; + + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + /* If it's dst rewrite, can't change port */ + if (maniptype == IP_NAT_MANIP_DST) + return 0; + + /* Map privileged onto privileged. */ + if (ntohs(*portptr) < 1024) { + /* Loose convention: >> 512 is credential passing */ + if (ntohs(*portptr)<512) { + min = 1; + range_size = 511 - min + 1; + } else { + min = 600; + range_size = 1023 - min + 1; + } + } else { + min = 1024; + range_size = 65535 - 1024 + 1; + } + } else { + min = ntohs(range->min.tcp.port); + range_size = ntohs(range->max.tcp.port) - min + 1; + } + + for (i = 0; i < range_size; i++, port++) { + *portptr = htons(min + port % range_size); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +tcp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct tcphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + __be16 *portptr, newport, oldport; + int hdrsize = 8; /* TCP connection tracking guarantees this much */ + + /* this could be a inner header returned in icmp packet; in such + cases we cannot update the checksum field since it is outside of + the 8 bytes of transport layer headers we are guaranteed */ + if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) + hdrsize = sizeof(struct tcphdr); + + if (!skb_make_writable(pskb, hdroff + hdrsize)) + return 0; + + iph = (struct iphdr *)((*pskb)->data + iphdroff); + hdr = (struct tcphdr *)((*pskb)->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.tcp.port; + portptr = &hdr->source; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.tcp.port; + portptr = &hdr->dest; + } + + oldport = *portptr; + *portptr = newport; + + if (hdrsize < sizeof(*hdr)) + return 1; + + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_tcp = { + .name = "TCP", + .protonum = IPPROTO_TCP, + .me = THIS_MODULE, + .manip_pkt = tcp_manip_pkt, + .in_range = tcp_in_range, + .unique_tuple = tcp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c new file mode 100644 index 000000000000..ab0ce4c8699f --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -0,0 +1,138 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +udp_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 port; + + if (maniptype == IP_NAT_MANIP_SRC) + port = tuple->src.u.udp.port; + else + port = tuple->dst.u.udp.port; + + return ntohs(port) >= ntohs(min->udp.port) && + ntohs(port) <= ntohs(max->udp.port); +} + +static int +udp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + static u_int16_t port; + __be16 *portptr; + unsigned int range_size, min, i; + + if (maniptype == IP_NAT_MANIP_SRC) + portptr = &tuple->src.u.udp.port; + else + portptr = &tuple->dst.u.udp.port; + + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + /* If it's dst rewrite, can't change port */ + if (maniptype == IP_NAT_MANIP_DST) + return 0; + + if (ntohs(*portptr) < 1024) { + /* Loose convention: >> 512 is credential passing */ + if (ntohs(*portptr)<512) { + min = 1; + range_size = 511 - min + 1; + } else { + min = 600; + range_size = 1023 - min + 1; + } + } else { + min = 1024; + range_size = 65535 - 1024 + 1; + } + } else { + min = ntohs(range->min.udp.port); + range_size = ntohs(range->max.udp.port) - min + 1; + } + + for (i = 0; i < range_size; i++, port++) { + *portptr = htons(min + port % range_size); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} + +static int +udp_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + struct udphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + __be16 *portptr, newport; + + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + return 0; + + iph = (struct iphdr *)((*pskb)->data + iphdroff); + hdr = (struct udphdr *)((*pskb)->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.udp.port; + portptr = &hdr->source; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.udp.port; + portptr = &hdr->dest; + } + if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, + 0); + if (!hdr->check) + hdr->check = CSUM_MANGLED_0; + } + *portptr = newport; + return 1; +} + +struct nf_nat_protocol nf_nat_protocol_udp = { + .name = "UDP", + .protonum = IPPROTO_UDP, + .me = THIS_MODULE, + .manip_pkt = udp_manip_pkt, + .in_range = udp_in_range, + .unique_tuple = udp_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c new file mode 100644 index 000000000000..f50d0203f9c0 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c @@ -0,0 +1,54 @@ +/* The "unknown" protocol. This is what is used for protocols we + * don't understand. It's returned by ip_ct_find_proto(). + */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include + +static int unknown_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type manip_type, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + return 1; +} + +static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + /* Sorry: we can't help you; if it's not unique, we can't frob + anything. */ + return 0; +} + +static int +unknown_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + return 1; +} + +struct nf_nat_protocol nf_nat_unknown_protocol = { + .name = "unknown", + /* .me isn't set: getting a ref to this cannot fail. */ + .manip_pkt = unknown_manip_pkt, + .in_range = unknown_in_range, + .unique_tuple = unknown_unique_tuple, +}; diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c new file mode 100644 index 000000000000..b868ee0195d4 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -0,0 +1,343 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Everything about the rules for NAT. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define NAT_VALID_HOOKS ((1<range[0], hooknum); +} + +/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ +static void warn_if_extra_mangle(__be32 dstip, __be32 srcip) +{ + static int warned = 0; + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; + struct rtable *rt; + + if (ip_route_output_key(&rt, &fl) != 0) + return; + + if (rt->rt_src != srcip && !warned) { + printk("NAT: no longer support implicit source local NAT\n"); + printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n", + NIPQUAD(srcip), NIPQUAD(dstip)); + warned = 1; + } + ip_rt_put(rt); +} + +static unsigned int ipt_dnat_target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const struct xt_target *target, + const void *targinfo) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + const struct nf_nat_multi_range_compat *mr = targinfo; + + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_LOCAL_OUT); + + ct = nf_ct_get(*pskb, &ctinfo); + + /* Connection must be valid and new. */ + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); + + if (hooknum == NF_IP_LOCAL_OUT && + mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) + warn_if_extra_mangle((*pskb)->nh.iph->daddr, + mr->range[0].min_ip); + + return nf_nat_setup_info(ct, &mr->range[0], hooknum); +} + +static int ipt_snat_checkentry(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + struct nf_nat_multi_range_compat *mr = targinfo; + + /* Must be a valid range */ + if (mr->rangesize != 1) { + printk("SNAT: multiple ranges no longer supported\n"); + return 0; + } + return 1; +} + +static int ipt_dnat_checkentry(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + struct nf_nat_multi_range_compat *mr = targinfo; + + /* Must be a valid range */ + if (mr->rangesize != 1) { + printk("DNAT: multiple ranges no longer supported\n"); + return 0; + } + return 1; +} + +inline unsigned int +alloc_null_binding(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum) +{ + /* Force range to this IP; let proto decide mapping for + per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). + Use reply in case it's already been mangled (eg local packet). + */ + __be32 ip + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); + struct nf_nat_range range + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; + + DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", + ct, NIPQUAD(ip)); + return nf_nat_setup_info(ct, &range, hooknum); +} + +unsigned int +alloc_null_binding_confirmed(struct nf_conn *ct, + struct nf_nat_info *info, + unsigned int hooknum) +{ + __be32 ip + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); + u_int16_t all + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + struct nf_nat_range range + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; + + DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", + ct, NIPQUAD(ip)); + return nf_nat_setup_info(ct, &range, hooknum); +} + +int nf_nat_rule_find(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct nf_conn *ct, + struct nf_nat_info *info) +{ + int ret; + + ret = ipt_do_table(pskb, hooknum, in, out, &nat_table); + + if (ret == NF_ACCEPT) { + if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) + /* NUL mapping */ + ret = alloc_null_binding(ct, info, hooknum); + } + return ret; +} + +static struct ipt_target ipt_snat_reg = { + .name = "SNAT", + .target = ipt_snat_target, + .targetsize = sizeof(struct nf_nat_multi_range_compat), + .table = "nat", + .hooks = 1 << NF_IP_POST_ROUTING, + .checkentry = ipt_snat_checkentry, + .family = AF_INET, +}; + +static struct xt_target ipt_dnat_reg = { + .name = "DNAT", + .target = ipt_dnat_target, + .targetsize = sizeof(struct nf_nat_multi_range_compat), + .table = "nat", + .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), + .checkentry = ipt_dnat_checkentry, + .family = AF_INET, +}; + +int __init nf_nat_rule_init(void) +{ + int ret; + + ret = ipt_register_table(&nat_table, &nat_initial_table.repl); + if (ret != 0) + return ret; + ret = xt_register_target(&ipt_snat_reg); + if (ret != 0) + goto unregister_table; + + ret = xt_register_target(&ipt_dnat_reg); + if (ret != 0) + goto unregister_snat; + + return ret; + + unregister_snat: + xt_unregister_target(&ipt_snat_reg); + unregister_table: + ipt_unregister_table(&nat_table); + + return ret; +} + +void nf_nat_rule_cleanup(void) +{ + xt_unregister_target(&ipt_dnat_reg); + xt_unregister_target(&ipt_snat_reg); + ipt_unregister_table(&nat_table); +} diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c new file mode 100644 index 000000000000..730a7a44c883 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -0,0 +1,406 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ + : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ + : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ + : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ + : "*ERROR*"))) + +#ifdef CONFIG_XFRM +static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) +{ + struct nf_conn *ct; + struct nf_conntrack_tuple *t; + enum ip_conntrack_info ctinfo; + enum ip_conntrack_dir dir; + unsigned long statusbit; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) + return; + dir = CTINFO2DIR(ctinfo); + t = &ct->tuplehash[dir].tuple; + + if (dir == IP_CT_DIR_ORIGINAL) + statusbit = IPS_DST_NAT; + else + statusbit = IPS_SRC_NAT; + + if (ct->status & statusbit) { + fl->fl4_dst = t->dst.u3.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_dport = t->dst.u.tcp.port; + } + + statusbit ^= IPS_NAT_MASK; + + if (ct->status & statusbit) { + fl->fl4_src = t->src.u3.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_sport = t->src.u.tcp.port; + } +} +#endif + +static unsigned int +nf_nat_fn(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct nf_conn_nat *nat; + struct nf_nat_info *info; + /* maniptype == SRC for postrouting. */ + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); + + /* We never see fragments: conntrack defrags on pre-routing + and local-out, and nf_nat_out protects post-routing. */ + NF_CT_ASSERT(!((*pskb)->nh.iph->frag_off + & htons(IP_MF|IP_OFFSET))); + + ct = nf_ct_get(*pskb, &ctinfo); + /* Can't track? It's not due to stress, or conntrack would + have dropped it. Hence it's the user's responsibilty to + packet filter it out, or implement conntrack/NAT for that + protocol. 8) --RR */ + if (!ct) { + /* Exception: ICMP redirect to new connection (not in + hash table yet). We must not let this through, in + case we're doing NAT to the same network. */ + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { + struct icmphdr _hdr, *hp; + + hp = skb_header_pointer(*pskb, + (*pskb)->nh.iph->ihl*4, + sizeof(_hdr), &_hdr); + if (hp != NULL && + hp->type == ICMP_REDIRECT) + return NF_DROP; + } + return NF_ACCEPT; + } + + /* Don't try to NAT if this packet is not conntracked */ + if (ct == &nf_conntrack_untracked) + return NF_ACCEPT; + + nat = nfct_nat(ct); + if (!nat) + return NF_DROP; + + switch (ctinfo) { + case IP_CT_RELATED: + case IP_CT_RELATED+IP_CT_IS_REPLY: + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { + if (!nf_nat_icmp_reply_translation(ct, ctinfo, + hooknum, pskb)) + return NF_DROP; + else + return NF_ACCEPT; + } + /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ + case IP_CT_NEW: + info = &nat->info; + + /* Seen it before? This can happen for loopback, retrans, + or local packets.. */ + if (!nf_nat_initialized(ct, maniptype)) { + unsigned int ret; + + if (unlikely(nf_ct_is_confirmed(ct))) + /* NAT module was loaded late */ + ret = alloc_null_binding_confirmed(ct, info, + hooknum); + else if (hooknum == NF_IP_LOCAL_IN) + /* LOCAL_IN hook doesn't have a chain! */ + ret = alloc_null_binding(ct, info, hooknum); + else + ret = nf_nat_rule_find(pskb, hooknum, in, out, + ct, info); + + if (ret != NF_ACCEPT) { + return ret; + } + } else + DEBUGP("Already setup manip %s for ct %p\n", + maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", + ct); + break; + + default: + /* ESTABLISHED */ + NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || + ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); + info = &nat->info; + } + + NF_CT_ASSERT(info); + return nf_nat_packet(ct, ctinfo, hooknum, pskb); +} + +static unsigned int +nf_nat_in(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + unsigned int ret; + __be32 daddr = (*pskb)->nh.iph->daddr; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN && + daddr != (*pskb)->nh.iph->daddr) { + dst_release((*pskb)->dst); + (*pskb)->dst = NULL; + } + return ret; +} + +static unsigned int +nf_nat_out(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ +#ifdef CONFIG_XFRM + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; +#endif + unsigned int ret; + + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) || + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); +#ifdef CONFIG_XFRM + if (ret != NF_DROP && ret != NF_STOLEN && + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.src.u3.ip != + ct->tuplehash[!dir].tuple.dst.u3.ip + || ct->tuplehash[dir].tuple.src.u.all != + ct->tuplehash[!dir].tuple.dst.u.all + ) + return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP; + } +#endif + return ret; +} + +static unsigned int +nf_nat_local_fn(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + unsigned int ret; + + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) || + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN && + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.dst.u3.ip != + ct->tuplehash[!dir].tuple.src.u3.ip +#ifdef CONFIG_XFRM + || ct->tuplehash[dir].tuple.dst.u.all != + ct->tuplehash[!dir].tuple.src.u.all +#endif + ) + if (ip_route_me_harder(pskb, RTN_UNSPEC)) + ret = NF_DROP; + } + return ret; +} + +static unsigned int +nf_nat_adjust(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(*pskb, &ctinfo); + if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { + DEBUGP("nf_nat_standalone: adjusting sequence number\n"); + if (!nf_nat_seq_adjust(pskb, ct, ctinfo)) + return NF_DROP; + } + return NF_ACCEPT; +} + +/* We must be after connection tracking and before packet filtering. */ + +static struct nf_hook_ops nf_nat_ops[] = { + /* Before packet filtering, change destination */ + { + .hook = nf_nat_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = nf_nat_out, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = nf_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, + /* Before packet filtering, change destination */ + { + .hook = nf_nat_local_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = nf_nat_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = nf_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, +}; + +static int __init nf_nat_standalone_init(void) +{ + int size, ret = 0; + + need_conntrack(); + + size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + + sizeof(struct nf_conn_nat); + ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); + if (ret < 0) { + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); + return ret; + } + + size = ALIGN(size, __alignof__(struct nf_conn_help)) + + sizeof(struct nf_conn_help); + ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP, + "nf_nat:help", size); + if (ret < 0) { + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); + goto cleanup_register_cache; + } +#ifdef CONFIG_XFRM + BUG_ON(ip_nat_decode_session != NULL); + ip_nat_decode_session = nat_decode_session; +#endif + ret = nf_nat_rule_init(); + if (ret < 0) { + printk("nf_nat_init: can't setup rules.\n"); + goto cleanup_decode_session; + } + ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + if (ret < 0) { + printk("nf_nat_init: can't register hooks.\n"); + goto cleanup_rule_init; + } + nf_nat_module_is_loaded = 1; + return ret; + + cleanup_rule_init: + nf_nat_rule_cleanup(); + cleanup_decode_session: +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif + nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP); + cleanup_register_cache: + nf_conntrack_unregister_cache(NF_CT_F_NAT); + return ret; +} + +static void __exit nf_nat_standalone_fini(void) +{ + nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + nf_nat_rule_cleanup(); + nf_nat_module_is_loaded = 0; +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif + /* Conntrack caches are unregistered in nf_conntrack_cleanup */ +} + +module_init(nf_nat_standalone_init); +module_exit(nf_nat_standalone_fini); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat"); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f952a7fb6ae3..aa8beabfeebb 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -579,7 +579,8 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, /* FIXME: protect helper list per RCU */ read_lock_bh(&nf_conntrack_lock); helper = __nf_ct_helper_find(repl); - if (helper) + /* NAT might want to assign a helper later */ + if (helper || features & NF_CT_F_NAT) features |= NF_CT_F_HELP; read_unlock_bh(&nf_conntrack_lock); @@ -850,6 +851,26 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, orig->dst.protonum)); } +/* Alter reply tuple (maybe alter helper). This is for NAT, and is + implicitly racy: see __nf_conntrack_confirm */ +void nf_conntrack_alter_reply(struct nf_conn *ct, + const struct nf_conntrack_tuple *newreply) +{ + struct nf_conn_help *help = nfct_help(ct); + + write_lock_bh(&nf_conntrack_lock); + /* Should be unconfirmed, so not in hash table yet */ + NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); + + DEBUGP("Altering reply tuple of %p to ", ct); + NF_CT_DUMP_TUPLE(newreply); + + ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; + if (!ct->master && help && help->expecting == 0) + help->helper = __nf_ct_helper_find(newreply); + write_unlock_bh(&nf_conntrack_lock); +} + /* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */ void __nf_ct_refresh_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo, diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index f9c8ddd5973c..bd1d2de75e45 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -39,7 +39,11 @@ #include #include #include -#include +#include +#ifdef CONFIG_NF_NAT_NEEDED +#include +#include +#endif #include #include @@ -430,7 +434,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) restart: list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { h = (struct nf_conntrack_tuple_hash *) i; - if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) + if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) continue; ct = nf_ct_tuplehash_to_ctrack(h); /* Dump entries of a given L3 protocol number. @@ -556,28 +560,28 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, return 0; } -#ifdef CONFIG_IP_NF_NAT_NEEDED +#ifdef CONFIG_NF_NAT_NEEDED static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), }; -static int ctnetlink_parse_nat_proto(struct nfattr *attr, +static int nfnetlink_parse_nat_proto(struct nfattr *attr, const struct nf_conn *ct, - struct ip_nat_range *range) + struct nf_nat_range *range) { struct nfattr *tb[CTA_PROTONAT_MAX]; - struct ip_nat_protocol *npt; + struct nf_nat_protocol *npt; nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) return -EINVAL; - npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); + npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); if (!npt->nfattr_to_range) { - ip_nat_proto_put(npt); + nf_nat_proto_put(npt); return 0; } @@ -585,7 +589,7 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, if (npt->nfattr_to_range(tb, range) > 0) range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; - ip_nat_proto_put(npt); + nf_nat_proto_put(npt); return 0; } @@ -596,8 +600,8 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = { }; static inline int -ctnetlink_parse_nat(struct nfattr *nat, - const struct nf_conn *ct, struct ip_nat_range *range) +nfnetlink_parse_nat(struct nfattr *nat, + const struct nf_conn *ct, struct nf_nat_range *range) { struct nfattr *tb[CTA_NAT_MAX]; int err; @@ -623,7 +627,7 @@ ctnetlink_parse_nat(struct nfattr *nat, if (!tb[CTA_NAT_PROTO-1]) return 0; - err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); + err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); if (err < 0) return err; @@ -798,35 +802,35 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) return -EINVAL; if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { -#ifndef CONFIG_IP_NF_NAT_NEEDED +#ifndef CONFIG_NF_NAT_NEEDED return -EINVAL; #else - struct ip_nat_range range; + struct nf_nat_range range; if (cda[CTA_NAT_DST-1]) { - if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, + if (nfnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, &range) < 0) return -EINVAL; - if (ip_nat_initialized(ct, + if (nf_nat_initialized(ct, HOOK2MANIP(NF_IP_PRE_ROUTING))) return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); } if (cda[CTA_NAT_SRC-1]) { - if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, + if (nfnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, &range) < 0) return -EINVAL; - if (ip_nat_initialized(ct, + if (nf_nat_initialized(ct, HOOK2MANIP(NF_IP_POST_ROUTING))) return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); } #endif } /* Be careful here, modifying NAT bits can screw up things, * so don't let users modify them directly if they don't pass - * ip_nat_range. */ + * nf_nat_range. */ ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); return 0; } diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 71f492fc6413..8156e429b885 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -730,7 +730,7 @@ static int tcp_in_window(struct ip_ct_tcp *state, return res; } -#ifdef CONFIG_IP_NF_NAT_NEEDED +#ifdef CONFIG_NF_NAT_NEEDED /* Update sender->td_end after NAT successfully mangled the packet */ /* Caller must linearize skb at tcp header. */ void nf_conntrack_tcp_update(struct sk_buff *skb, diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index be94b6359725..3f56a3a6c399 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -530,8 +530,11 @@ EXPORT_SYMBOL(nf_conntrack_lock); EXPORT_SYMBOL(nf_conntrack_hash); EXPORT_SYMBOL(nf_conntrack_untracked); EXPORT_SYMBOL_GPL(nf_conntrack_find_get); -#ifdef CONFIG_IP_NF_NAT_NEEDED +#ifdef CONFIG_NF_NAT_NEEDED EXPORT_SYMBOL(nf_conntrack_tcp_update); +EXPORT_SYMBOL(nf_conntrack_register_cache); +EXPORT_SYMBOL(nf_conntrack_unregister_cache); +EXPORT_SYMBOL(nf_conntrack_alter_reply); #endif EXPORT_SYMBOL(__nf_conntrack_confirm); EXPORT_SYMBOL(nf_ct_get_tuple); -- cgit v1.2.3-71-gd317 From 55a733247d6d2883d9bb77825fafac3dfca13fc2 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 2 Dec 2006 22:07:44 -0800 Subject: [NETFILTER]: nf_nat: add FTP NAT helper port Add FTP NAT helper. Split out from Jozsef's big nf_nat patch with a few small fixes by myself. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_ftp.h | 20 +-- include/linux/netfilter_ipv4/ip_conntrack_ftp.h | 40 +++++- include/net/netfilter/nf_conntrack.h | 2 +- net/ipv4/netfilter/Kconfig | 25 ++-- net/ipv4/netfilter/Makefile | 5 +- net/ipv4/netfilter/nf_nat_ftp.c | 179 ++++++++++++++++++++++++ net/netfilter/nf_conntrack_ftp.c | 20 +-- 7 files changed, 260 insertions(+), 31 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_ftp.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h index ad4a41c9ce93..81453ea7e4c2 100644 --- a/include/linux/netfilter/nf_conntrack_ftp.h +++ b/include/linux/netfilter/nf_conntrack_ftp.h @@ -3,16 +3,16 @@ /* FTP tracking. */ /* This enum is exposed to userspace */ -enum ip_ct_ftp_type +enum nf_ct_ftp_type { /* PORT command from client */ - IP_CT_FTP_PORT, + NF_CT_FTP_PORT, /* PASV response from server */ - IP_CT_FTP_PASV, + NF_CT_FTP_PASV, /* EPRT command from client */ - IP_CT_FTP_EPRT, + NF_CT_FTP_EPRT, /* EPSV response from server */ - IP_CT_FTP_EPSV, + NF_CT_FTP_EPSV, }; #ifdef __KERNEL__ @@ -21,23 +21,23 @@ enum ip_ct_ftp_type #define NUM_SEQ_TO_REMEMBER 2 /* This structure exists only once per master */ -struct ip_ct_ftp_master { +struct nf_ct_ftp_master { /* Valid seq positions for cmd matching after newline */ u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; /* 0 means seq_match_aft_nl not set */ int seq_aft_nl_num[IP_CT_DIR_MAX]; }; -struct ip_conntrack_expect; +struct nf_conntrack_expect; /* For NAT to hook in when we find a packet which describes what other * connection we should expect. */ -extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, +extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, - enum ip_ct_ftp_type type, + enum nf_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, - struct ip_conntrack_expect *exp, + struct nf_conntrack_expect *exp, u32 *seq); #endif /* __KERNEL__ */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h index 63811934de4d..2129fc3972ac 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h @@ -1,6 +1,44 @@ #ifndef _IP_CONNTRACK_FTP_H #define _IP_CONNTRACK_FTP_H +/* FTP tracking. */ -#include +/* This enum is exposed to userspace */ +enum ip_ct_ftp_type +{ + /* PORT command from client */ + IP_CT_FTP_PORT, + /* PASV response from server */ + IP_CT_FTP_PASV, + /* EPRT command from client */ + IP_CT_FTP_EPRT, + /* EPSV response from server */ + IP_CT_FTP_EPSV, +}; + +#ifdef __KERNEL__ + +#define FTP_PORT 21 + +#define NUM_SEQ_TO_REMEMBER 2 +/* This structure exists only once per master */ +struct ip_ct_ftp_master { + /* Valid seq positions for cmd matching after newline */ + u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; + /* 0 means seq_match_aft_nl not set */ + int seq_aft_nl_num[IP_CT_DIR_MAX]; +}; + +struct ip_conntrack_expect; + +/* For NAT to hook in when we find a packet which describes what other + * connection we should expect. */ +extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + enum ip_ct_ftp_type type, + unsigned int matchoff, + unsigned int matchlen, + struct ip_conntrack_expect *exp, + u32 *seq); +#endif /* __KERNEL__ */ #endif /* _IP_CONNTRACK_FTP_H */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 9948af068688..83694cfdfa8f 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -45,7 +45,7 @@ union nf_conntrack_expect_proto { /* per conntrack: application helper private data */ union nf_conntrack_help { /* insert conntrack helper private data (master) here */ - struct ip_ct_ftp_master ct_ftp_info; + struct nf_ct_ftp_master ct_ftp_info; }; #include diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 01789aeaeb5f..52f876db68f4 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -477,20 +477,29 @@ config IP_NF_NAT_SNMP_BASIC To compile it as a module, choose M here. If unsure, say N. +# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), +# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. +# From kconfig-language.txt: +# +# '&&' (6) +# +# (6) Returns the result of min(/expr/, /expr/). +config IP_NF_NAT_FTP + tristate + depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT + default IP_NF_NAT && IP_NF_FTP + +config NF_NAT_FTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_FTP + config IP_NF_NAT_IRC tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n default IP_NF_NAT if IP_NF_IRC=y default m if IP_NF_IRC=m -# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), -# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh. -config IP_NF_NAT_FTP - tristate - depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n - default IP_NF_NAT if IP_NF_FTP=y - default m if IP_NF_FTP=m - config IP_NF_NAT_TFTP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index ec31690764ac..c0c6194bb275 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o -# NAT helpers +# NAT helpers (ip_conntrack) obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o @@ -49,6 +49,9 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o +# NAT helpers (nf_conntrack) +obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o + # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c new file mode 100644 index 000000000000..751b59801755 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_ftp.c @@ -0,0 +1,179 @@ +/* FTP extension for TCP NAT alteration. */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rusty Russell "); +MODULE_DESCRIPTION("ftp NAT helper"); +MODULE_ALIAS("ip_nat_ftp"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: Time out? --RR */ + +static int +mangle_rfc959_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; + + sprintf(buffer, "%u,%u,%u,%u,%u,%u", + NIPQUAD(newip), port>>8, port&0xFF); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +/* |1|132.235.1.2|6275| */ +static int +mangle_eprt_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("|1|255.255.255.255|65535|")]; + + sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +/* |1|132.235.1.2|6275| */ +static int +mangle_epsv_packet(struct sk_buff **pskb, + __be32 newip, + u_int16_t port, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + u32 *seq) +{ + char buffer[sizeof("|||65535|")]; + + sprintf(buffer, "|||%u|", port); + + DEBUGP("calling nf_nat_mangle_tcp_packet\n"); + + *seq += strlen(buffer) - matchlen; + return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, + matchlen, buffer, strlen(buffer)); +} + +static int (*mangle[])(struct sk_buff **, __be32, u_int16_t, + unsigned int, unsigned int, struct nf_conn *, + enum ip_conntrack_info, u32 *seq) += { + [NF_CT_FTP_PORT] = mangle_rfc959_packet, + [NF_CT_FTP_PASV] = mangle_rfc959_packet, + [NF_CT_FTP_EPRT] = mangle_eprt_packet, + [NF_CT_FTP_EPSV] = mangle_epsv_packet +}; + +/* So, this packet has hit the connection tracking matching code. + Mangle it, and change the expectation to match the new version. */ +static unsigned int nf_nat_ftp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + enum nf_ct_ftp_type type, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp, + u32 *seq) +{ + __be32 newip; + u_int16_t port; + int dir = CTINFO2DIR(ctinfo); + struct nf_conn *ct = exp->master; + + DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); + + /* Connection will come from wherever this packet goes, hence !dir */ + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = !dir; + + /* When you see the packet, we need to NAT it the same as the + * this one. */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo, + seq)) { + nf_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static void __exit nf_nat_ftp_fini(void) +{ + rcu_assign_pointer(nf_nat_ftp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_ftp_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_ftp_hook)); + rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp); + return 0; +} + +/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ +static int warn_set(const char *val, struct kernel_param *kp) +{ + printk(KERN_INFO KBUILD_MODNAME + ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + return 0; +} +module_param_call(ports, warn_set, NULL, NULL, 0); + +module_init(nf_nat_ftp_init); +module_exit(nf_nat_ftp_fini); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index e299d657e4fc..92a947168761 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -51,7 +51,7 @@ module_param(loose, bool, 0600); unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, - enum ip_ct_ftp_type type, + enum nf_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, struct nf_conntrack_expect *exp, @@ -74,7 +74,7 @@ static struct ftp_search { size_t plen; char skip; char term; - enum ip_ct_ftp_type ftptype; + enum nf_ct_ftp_type ftptype; int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char); } search[IP_CT_DIR_MAX][2] = { [IP_CT_DIR_ORIGINAL] = { @@ -83,7 +83,7 @@ static struct ftp_search { .plen = sizeof("PORT") - 1, .skip = ' ', .term = '\r', - .ftptype = IP_CT_FTP_PORT, + .ftptype = NF_CT_FTP_PORT, .getnum = try_rfc959, }, { @@ -91,7 +91,7 @@ static struct ftp_search { .plen = sizeof("EPRT") - 1, .skip = ' ', .term = '\r', - .ftptype = IP_CT_FTP_EPRT, + .ftptype = NF_CT_FTP_EPRT, .getnum = try_eprt, }, }, @@ -101,7 +101,7 @@ static struct ftp_search { .plen = sizeof("227 ") - 1, .skip = '(', .term = ')', - .ftptype = IP_CT_FTP_PASV, + .ftptype = NF_CT_FTP_PASV, .getnum = try_rfc959, }, { @@ -109,7 +109,7 @@ static struct ftp_search { .plen = sizeof("229 ") - 1, .skip = '(', .term = ')', - .ftptype = IP_CT_FTP_EPSV, + .ftptype = NF_CT_FTP_EPSV, .getnum = try_epsv_response, }, }, @@ -320,7 +320,7 @@ static int find_pattern(const char *data, size_t dlen, } /* Look up to see if we're just after a \n. */ -static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) +static int find_nl_seq(u32 seq, const struct nf_ct_ftp_master *info, int dir) { unsigned int i; @@ -331,7 +331,7 @@ static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) } /* We don't update if it's older than what we have. */ -static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir, +static void update_nl_seq(u32 nl_seq, struct nf_ct_ftp_master *info, int dir, struct sk_buff *skb) { unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; @@ -367,7 +367,7 @@ static int help(struct sk_buff **pskb, u32 seq; int dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff; - struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; + struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; struct nf_conntrack_expect *exp; struct nf_conntrack_man cmd = {}; unsigned int i; @@ -523,7 +523,7 @@ static int help(struct sk_buff **pskb, /* Now, NAT might want to mangle the packet, and register the * (possibly changed) expectation itself. */ nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook); - if (nf_nat_ftp) + if (nf_nat_ftp && ct->status & IPS_NAT_MASK) ret = nf_nat_ftp(pskb, ctinfo, search[dir][i].ftptype, matchoff, matchlen, exp, &seq); else { -- cgit v1.2.3-71-gd317 From 16958900578b94585c2ab9a2d20d837b4d5e3ba6 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:08:26 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add amanda helper port Add IPv4 and IPv6 capable nf_conntrack port of the Amanda conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_amanda.h | 10 ++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_amanda.c | 78 +++++++++ net/netfilter/Kconfig | 15 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_amanda.c | 237 ++++++++++++++++++++++++++ 7 files changed, 347 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_amanda.h create mode 100644 net/ipv4/netfilter/nf_nat_amanda.c create mode 100644 net/netfilter/nf_conntrack_amanda.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_amanda.h b/include/linux/netfilter/nf_conntrack_amanda.h new file mode 100644 index 000000000000..26c223544ae8 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_amanda.h @@ -0,0 +1,10 @@ +#ifndef _NF_CONNTRACK_AMANDA_H +#define _NF_CONNTRACK_AMANDA_H +/* AMANDA tracking. */ + +extern unsigned int (*nf_nat_amanda_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp); +#endif /* _NF_CONNTRACK_AMANDA_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 52f876db68f4..6993ec53dc06 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -512,6 +512,11 @@ config IP_NF_NAT_AMANDA default IP_NF_NAT if IP_NF_AMANDA=y default m if IP_NF_AMANDA=m +config NF_NAT_AMANDA + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_AMANDA + config IP_NF_NAT_PPTP tristate depends on IP_NF_NAT!=n && IP_NF_PPTP!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index c0c6194bb275..8893249bbe98 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o # NAT helpers (nf_conntrack) +obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o # generic IP tables diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c new file mode 100644 index 000000000000..0f17098917bc --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_amanda.c @@ -0,0 +1,78 @@ +/* Amanda extension for TCP NAT alteration. + * (C) 2002 by Brian J. Murrell + * based on a copy of HW's ip_nat_irc.c as well as other modules + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Brian J. Murrell "); +MODULE_DESCRIPTION("Amanda NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_amanda"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) +{ + char buffer[sizeof("65535")]; + u_int16_t port; + unsigned int ret; + + /* Connection comes from client. */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = IP_CT_DIR_ORIGINAL; + + /* When you see the packet, we need to NAT it the same as the + * this one (ie. same IP: it will be TCP and master is UDP). */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + sprintf(buffer, "%u", port); + ret = nf_nat_mangle_udp_packet(pskb, exp->master, ctinfo, + matchoff, matchlen, + buffer, strlen(buffer)); + if (ret != NF_ACCEPT) + nf_conntrack_unexpect_related(exp); + return ret; +} + +static void __exit nf_nat_amanda_fini(void) +{ + rcu_assign_pointer(nf_nat_amanda_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_amanda_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_amanda_hook)); + rcu_assign_pointer(nf_nat_amanda_hook, help); + return 0; +} + +module_init(nf_nat_amanda_init); +module_exit(nf_nat_amanda_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index efe56f768f34..f85fd43b344b 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -131,6 +131,21 @@ config NF_CT_PROTO_SCTP If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +config NF_CONNTRACK_AMANDA + tristate "Amanda backup protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + select TEXTSEARCH + select TEXTSEARCH_KMP + help + If you are running the Amanda backup package + on this machine or machines that will be MASQUERADED through this + machine, then you may want to enable this feature. This allows the + connection tracking and natting code to allow the sub-channels that + Amanda requires for communication of the backup data, messages and + index. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CONNTRACK_FTP tristate "FTP support on new connection tracking (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 7f0089c584bf..a5ee93817427 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o # connection tracking helpers +obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o # generic X tables diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c new file mode 100644 index 000000000000..5c495dc9d942 --- /dev/null +++ b/net/netfilter/nf_conntrack_amanda.c @@ -0,0 +1,237 @@ +/* Amanda extension for IP connection tracking + * + * (C) 2002 by Brian J. Murrell + * based on HW's ip_conntrack_irc.c as well as other modules + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static unsigned int master_timeout __read_mostly = 300; +static char *ts_algo = "kmp"; + +MODULE_AUTHOR("Brian J. Murrell "); +MODULE_DESCRIPTION("Amanda connection tracking module"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_amanda"); + +module_param(master_timeout, uint, 0600); +MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); +module_param(ts_algo, charp, 0400); +MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)"); + +unsigned int (*nf_nat_amanda_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_amanda_hook); + +enum amanda_strings { + SEARCH_CONNECT, + SEARCH_NEWLINE, + SEARCH_DATA, + SEARCH_MESG, + SEARCH_INDEX, +}; + +static struct { + char *string; + size_t len; + struct ts_config *ts; +} search[] __read_mostly = { + [SEARCH_CONNECT] = { + .string = "CONNECT ", + .len = 8, + }, + [SEARCH_NEWLINE] = { + .string = "\n", + .len = 1, + }, + [SEARCH_DATA] = { + .string = "DATA ", + .len = 5, + }, + [SEARCH_MESG] = { + .string = "MESG ", + .len = 5, + }, + [SEARCH_INDEX] = { + .string = "INDEX ", + .len = 6, + }, +}; + +static int amanda_help(struct sk_buff **pskb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct ts_state ts; + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple *tuple; + unsigned int dataoff, start, stop, off, i; + char pbuf[sizeof("65535")], *tmp; + u_int16_t len; + __be16 port; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int ret = NF_ACCEPT; + typeof(nf_nat_amanda_hook) nf_nat_amanda; + + /* Only look at packets from the Amanda server */ + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) + return NF_ACCEPT; + + /* increase the UDP timeout of the master connection as replies from + * Amanda clients to the server can be quite delayed */ + nf_ct_refresh(ct, *pskb, master_timeout * HZ); + + /* No data? */ + dataoff = protoff + sizeof(struct udphdr); + if (dataoff >= (*pskb)->len) { + if (net_ratelimit()) + printk("amanda_help: skblen = %u\n", (*pskb)->len); + return NF_ACCEPT; + } + + memset(&ts, 0, sizeof(ts)); + start = skb_find_text(*pskb, dataoff, (*pskb)->len, + search[SEARCH_CONNECT].ts, &ts); + if (start == UINT_MAX) + goto out; + start += dataoff + search[SEARCH_CONNECT].len; + + memset(&ts, 0, sizeof(ts)); + stop = skb_find_text(*pskb, start, (*pskb)->len, + search[SEARCH_NEWLINE].ts, &ts); + if (stop == UINT_MAX) + goto out; + stop += start; + + for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) { + memset(&ts, 0, sizeof(ts)); + off = skb_find_text(*pskb, start, stop, search[i].ts, &ts); + if (off == UINT_MAX) + continue; + off += start + search[i].len; + + len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off); + if (skb_copy_bits(*pskb, off, pbuf, len)) + break; + pbuf[len] = '\0'; + + port = htons(simple_strtoul(pbuf, &tmp, 10)); + len = tmp - pbuf; + if (port == 0 || len > 5) + break; + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) { + ret = NF_DROP; + goto out; + } + tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + nf_conntrack_expect_init(exp, family, + &tuple->src.u3, &tuple->dst.u3, + IPPROTO_TCP, NULL, &port); + + nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook); + if (nf_nat_amanda && ct->status & IPS_NAT_MASK) + ret = nf_nat_amanda(pskb, ctinfo, off - dataoff, + len, exp); + else if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + nf_conntrack_expect_put(exp); + } + +out: + return ret; +} + +static struct nf_conntrack_helper amanda_helper[2] __read_mostly = { + { + .name = "amanda", + .max_expected = 3, + .timeout = 180, + .me = THIS_MODULE, + .help = amanda_help, + .tuple.src.l3num = AF_INET, + .tuple.src.u.udp.port = __constant_htons(10080), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + }, + { + .name = "amanda", + .max_expected = 3, + .timeout = 180, + .me = THIS_MODULE, + .help = amanda_help, + .tuple.src.l3num = AF_INET6, + .tuple.src.u.udp.port = __constant_htons(10080), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + }, +}; + +static void __exit nf_conntrack_amanda_fini(void) +{ + int i; + + nf_conntrack_helper_unregister(&amanda_helper[0]); + nf_conntrack_helper_unregister(&amanda_helper[1]); + for (i = 0; i < ARRAY_SIZE(search); i++) + textsearch_destroy(search[i].ts); +} + +static int __init nf_conntrack_amanda_init(void) +{ + int ret, i; + + ret = -ENOMEM; + for (i = 0; i < ARRAY_SIZE(search); i++) { + search[i].ts = textsearch_prepare(ts_algo, search[i].string, + search[i].len, + GFP_KERNEL, TS_AUTOLOAD); + if (search[i].ts == NULL) + goto err1; + } + ret = nf_conntrack_helper_register(&amanda_helper[0]); + if (ret < 0) + goto err1; + ret = nf_conntrack_helper_register(&amanda_helper[1]); + if (ret < 0) + goto err2; + return 0; + +err2: + nf_conntrack_helper_unregister(&amanda_helper[0]); +err1: + for (; i >= 0; i--) { + if (search[i].ts) + textsearch_destroy(search[i].ts); + } + return ret; +} + +module_init(nf_conntrack_amanda_init); +module_exit(nf_conntrack_amanda_fini); -- cgit v1.2.3-71-gd317 From f587de0e2feb9eb9b94f98d0a7b7437e4d6617b4 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:08:46 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port Add IPv4 and IPv6 capable nf_conntrack port of the H.323 conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_h323.h | 92 + include/linux/netfilter/nf_conntrack_h323_asn1.h | 98 + include/linux/netfilter/nf_conntrack_h323_types.h | 951 ++++++++++ include/linux/netfilter_ipv4/Kbuild | 2 - include/linux/netfilter_ipv4/ip_conntrack_h323.h | 2 +- .../netfilter_ipv4/ip_conntrack_helper_h323_asn1.h | 98 - .../ip_conntrack_helper_h323_types.h | 939 ---------- include/net/netfilter/nf_conntrack.h | 2 + include/net/netfilter/nf_conntrack_expect.h | 1 + net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 3 +- net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | 874 --------- .../netfilter/ip_conntrack_helper_h323_types.c | 1926 ------------------- net/ipv4/netfilter/nf_nat_h323.c | 596 ++++++ net/netfilter/Kconfig | 19 + net/netfilter/Makefile | 3 + net/netfilter/nf_conntrack_h323_asn1.c | 874 +++++++++ net/netfilter/nf_conntrack_h323_main.c | 1856 +++++++++++++++++++ net/netfilter/nf_conntrack_h323_types.c | 1927 ++++++++++++++++++++ 19 files changed, 6427 insertions(+), 3841 deletions(-) create mode 100644 include/linux/netfilter/nf_conntrack_h323.h create mode 100644 include/linux/netfilter/nf_conntrack_h323_asn1.h create mode 100644 include/linux/netfilter/nf_conntrack_h323_types.h delete mode 100644 include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h delete mode 100644 include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h delete mode 100644 net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c delete mode 100644 net/ipv4/netfilter/ip_conntrack_helper_h323_types.c create mode 100644 net/ipv4/netfilter/nf_nat_h323.c create mode 100644 net/netfilter/nf_conntrack_h323_asn1.c create mode 100644 net/netfilter/nf_conntrack_h323_main.c create mode 100644 net/netfilter/nf_conntrack_h323_types.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_h323.h b/include/linux/netfilter/nf_conntrack_h323.h new file mode 100644 index 000000000000..08e2f4977c2e --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_h323.h @@ -0,0 +1,92 @@ +#ifndef _NF_CONNTRACK_H323_H +#define _NF_CONNTRACK_H323_H + +#ifdef __KERNEL__ + +#include + +#define RAS_PORT 1719 +#define Q931_PORT 1720 +#define H323_RTP_CHANNEL_MAX 4 /* Audio, video, FAX and other */ + +/* This structure exists only once per master */ +struct nf_ct_h323_master { + + /* Original and NATed Q.931 or H.245 signal ports */ + __be16 sig_port[IP_CT_DIR_MAX]; + + /* Original and NATed RTP ports */ + __be16 rtp_port[H323_RTP_CHANNEL_MAX][IP_CT_DIR_MAX]; + + union { + /* RAS connection timeout */ + u_int32_t timeout; + + /* Next TPKT length (for separate TPKT header and data) */ + u_int16_t tpkt_len[IP_CT_DIR_MAX]; + }; +}; + +struct nf_conn; + +extern int get_h225_addr(struct nf_conn *ct, unsigned char *data, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 *port); +extern void nf_conntrack_h245_expect(struct nf_conn *new, + struct nf_conntrack_expect *this); +extern void nf_conntrack_q931_expect(struct nf_conn *new, + struct nf_conntrack_expect *this); +extern int (*set_h245_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, + __be16 port); +extern int (*set_h225_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + TransportAddress *taddr, + union nf_conntrack_address *addr, + __be16 port); +extern int (*set_sig_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count); +extern int (*set_ras_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count); +extern int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + __be16 port, __be16 rtp_port, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp); +extern int (*nat_t120_hook) (struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp); +extern int (*nat_h245_hook) (struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp); +extern int (*nat_callforwarding_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, + __be16 port, + struct nf_conntrack_expect *exp); +extern int (*nat_q931_hook) (struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress *taddr, + int idx, __be16 port, + struct nf_conntrack_expect *exp); + +#endif + +#endif diff --git a/include/linux/netfilter/nf_conntrack_h323_asn1.h b/include/linux/netfilter/nf_conntrack_h323_asn1.h new file mode 100644 index 000000000000..8dab5968fc7e --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_h323_asn1.h @@ -0,0 +1,98 @@ +/**************************************************************************** + * ip_conntrack_h323_asn1.h - BER and PER decoding library for H.323 + * conntrack/NAT module. + * + * Copyright (c) 2006 by Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * + * This library is based on H.225 version 4, H.235 version 2 and H.245 + * version 7. It is extremely optimized to decode only the absolutely + * necessary objects in a signal for Linux kernel NAT module use, so don't + * expect it to be a full ASN.1 library. + * + * Features: + * + * 1. Small. The total size of code plus data is less than 20 KB (IA32). + * 2. Fast. Decoding Netmeeting's Setup signal 1 million times on a PIII 866 + * takes only 3.9 seconds. + * 3. No memory allocation. It uses a static object. No need to initialize or + * cleanup. + * 4. Thread safe. + * 5. Support embedded architectures that has no misaligned memory access + * support. + * + * Limitations: + * + * 1. At most 30 faststart entries. Actually this is limited by ethernet's MTU. + * If a Setup signal contains more than 30 faststart, the packet size will + * very likely exceed the MTU size, then the TPKT will be fragmented. I + * don't know how to handle this in a Netfilter module. Anybody can help? + * Although I think 30 is enough for most of the cases. + * 2. IPv4 addresses only. + * + ****************************************************************************/ + +#ifndef _NF_CONNTRACK_HELPER_H323_ASN1_H_ +#define _NF_CONNTRACK_HELPER_H323_ASN1_H_ + +/***************************************************************************** + * H.323 Types + ****************************************************************************/ +#include "nf_conntrack_h323_types.h" + +typedef struct { + enum { + Q931_NationalEscape = 0x00, + Q931_Alerting = 0x01, + Q931_CallProceeding = 0x02, + Q931_Connect = 0x07, + Q931_ConnectAck = 0x0F, + Q931_Progress = 0x03, + Q931_Setup = 0x05, + Q931_SetupAck = 0x0D, + Q931_Resume = 0x26, + Q931_ResumeAck = 0x2E, + Q931_ResumeReject = 0x22, + Q931_Suspend = 0x25, + Q931_SuspendAck = 0x2D, + Q931_SuspendReject = 0x21, + Q931_UserInformation = 0x20, + Q931_Disconnect = 0x45, + Q931_Release = 0x4D, + Q931_ReleaseComplete = 0x5A, + Q931_Restart = 0x46, + Q931_RestartAck = 0x4E, + Q931_Segment = 0x60, + Q931_CongestionCtrl = 0x79, + Q931_Information = 0x7B, + Q931_Notify = 0x6E, + Q931_Status = 0x7D, + Q931_StatusEnquiry = 0x75, + Q931_Facility = 0x62 + } MessageType; + H323_UserInformation UUIE; +} Q931; + +/***************************************************************************** + * Decode Functions Return Codes + ****************************************************************************/ + +#define H323_ERROR_NONE 0 /* Decoded successfully */ +#define H323_ERROR_STOP 1 /* Decoding stopped, not really an error */ +#define H323_ERROR_BOUND -1 +#define H323_ERROR_RANGE -2 + + +/***************************************************************************** + * Decode Functions + ****************************************************************************/ + +int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras); +int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931); +int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, + MultimediaSystemControlMessage * + mscm); + +#endif diff --git a/include/linux/netfilter/nf_conntrack_h323_types.h b/include/linux/netfilter/nf_conntrack_h323_types.h new file mode 100644 index 000000000000..38d74d5c9700 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_h323_types.h @@ -0,0 +1,951 @@ +/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + */ + +typedef struct TransportAddress_ipAddress { /* SEQUENCE */ + int options; /* No use */ + unsigned ip; +} TransportAddress_ipAddress; + +typedef struct TransportAddress_ip6Address { /* SEQUENCE */ + int options; /* No use */ + unsigned ip6; +} TransportAddress_ip6Address; + +typedef struct TransportAddress { /* CHOICE */ + enum { + eTransportAddress_ipAddress, + eTransportAddress_ipSourceRoute, + eTransportAddress_ipxAddress, + eTransportAddress_ip6Address, + eTransportAddress_netBios, + eTransportAddress_nsap, + eTransportAddress_nonStandardAddress, + } choice; + union { + TransportAddress_ipAddress ipAddress; + TransportAddress_ip6Address ip6Address; + }; +} TransportAddress; + +typedef struct DataProtocolCapability { /* CHOICE */ + enum { + eDataProtocolCapability_nonStandard, + eDataProtocolCapability_v14buffered, + eDataProtocolCapability_v42lapm, + eDataProtocolCapability_hdlcFrameTunnelling, + eDataProtocolCapability_h310SeparateVCStack, + eDataProtocolCapability_h310SingleVCStack, + eDataProtocolCapability_transparent, + eDataProtocolCapability_segmentationAndReassembly, + eDataProtocolCapability_hdlcFrameTunnelingwSAR, + eDataProtocolCapability_v120, + eDataProtocolCapability_separateLANStack, + eDataProtocolCapability_v76wCompression, + eDataProtocolCapability_tcp, + eDataProtocolCapability_udp, + } choice; +} DataProtocolCapability; + +typedef struct DataApplicationCapability_application { /* CHOICE */ + enum { + eDataApplicationCapability_application_nonStandard, + eDataApplicationCapability_application_t120, + eDataApplicationCapability_application_dsm_cc, + eDataApplicationCapability_application_userData, + eDataApplicationCapability_application_t84, + eDataApplicationCapability_application_t434, + eDataApplicationCapability_application_h224, + eDataApplicationCapability_application_nlpid, + eDataApplicationCapability_application_dsvdControl, + eDataApplicationCapability_application_h222DataPartitioning, + eDataApplicationCapability_application_t30fax, + eDataApplicationCapability_application_t140, + eDataApplicationCapability_application_t38fax, + eDataApplicationCapability_application_genericDataCapability, + } choice; + union { + DataProtocolCapability t120; + }; +} DataApplicationCapability_application; + +typedef struct DataApplicationCapability { /* SEQUENCE */ + int options; /* No use */ + DataApplicationCapability_application application; +} DataApplicationCapability; + +typedef struct DataType { /* CHOICE */ + enum { + eDataType_nonStandard, + eDataType_nullData, + eDataType_videoData, + eDataType_audioData, + eDataType_data, + eDataType_encryptionData, + eDataType_h235Control, + eDataType_h235Media, + eDataType_multiplexedStream, + } choice; + union { + DataApplicationCapability data; + }; +} DataType; + +typedef struct UnicastAddress_iPAddress { /* SEQUENCE */ + int options; /* No use */ + unsigned network; +} UnicastAddress_iPAddress; + +typedef struct UnicastAddress_iP6Address { /* SEQUENCE */ + int options; /* No use */ + unsigned network; +} UnicastAddress_iP6Address; + +typedef struct UnicastAddress { /* CHOICE */ + enum { + eUnicastAddress_iPAddress, + eUnicastAddress_iPXAddress, + eUnicastAddress_iP6Address, + eUnicastAddress_netBios, + eUnicastAddress_iPSourceRouteAddress, + eUnicastAddress_nsap, + eUnicastAddress_nonStandardAddress, + } choice; + union { + UnicastAddress_iPAddress iPAddress; + UnicastAddress_iP6Address iP6Address; + }; +} UnicastAddress; + +typedef struct H245_TransportAddress { /* CHOICE */ + enum { + eH245_TransportAddress_unicastAddress, + eH245_TransportAddress_multicastAddress, + } choice; + union { + UnicastAddress unicastAddress; + }; +} H245_TransportAddress; + +typedef struct H2250LogicalChannelParameters { /* SEQUENCE */ + enum { + eH2250LogicalChannelParameters_nonStandard = (1 << 31), + eH2250LogicalChannelParameters_associatedSessionID = + (1 << 30), + eH2250LogicalChannelParameters_mediaChannel = (1 << 29), + eH2250LogicalChannelParameters_mediaGuaranteedDelivery = + (1 << 28), + eH2250LogicalChannelParameters_mediaControlChannel = + (1 << 27), + eH2250LogicalChannelParameters_mediaControlGuaranteedDelivery + = (1 << 26), + eH2250LogicalChannelParameters_silenceSuppression = (1 << 25), + eH2250LogicalChannelParameters_destination = (1 << 24), + eH2250LogicalChannelParameters_dynamicRTPPayloadType = + (1 << 23), + eH2250LogicalChannelParameters_mediaPacketization = (1 << 22), + eH2250LogicalChannelParameters_transportCapability = + (1 << 21), + eH2250LogicalChannelParameters_redundancyEncoding = (1 << 20), + eH2250LogicalChannelParameters_source = (1 << 19), + } options; + H245_TransportAddress mediaChannel; + H245_TransportAddress mediaControlChannel; +} H2250LogicalChannelParameters; + +typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters { /* CHOICE */ + enum { + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none, + } choice; + union { + H2250LogicalChannelParameters h2250LogicalChannelParameters; + }; +} OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters; + +typedef struct OpenLogicalChannel_forwardLogicalChannelParameters { /* SEQUENCE */ + enum { + eOpenLogicalChannel_forwardLogicalChannelParameters_portNumber + = (1 << 31), + eOpenLogicalChannel_forwardLogicalChannelParameters_forwardLogicalChannelDependency + = (1 << 30), + eOpenLogicalChannel_forwardLogicalChannelParameters_replacementFor + = (1 << 29), + } options; + DataType dataType; + OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters + multiplexParameters; +} OpenLogicalChannel_forwardLogicalChannelParameters; + +typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ + enum { + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, + } choice; + union { + H2250LogicalChannelParameters h2250LogicalChannelParameters; + }; +} OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters; + +typedef struct OpenLogicalChannel_reverseLogicalChannelParameters { /* SEQUENCE */ + enum { + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters + = (1 << 31), + eOpenLogicalChannel_reverseLogicalChannelParameters_reverseLogicalChannelDependency + = (1 << 30), + eOpenLogicalChannel_reverseLogicalChannelParameters_replacementFor + = (1 << 29), + } options; + OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters + multiplexParameters; +} OpenLogicalChannel_reverseLogicalChannelParameters; + +typedef struct NetworkAccessParameters_networkAddress { /* CHOICE */ + enum { + eNetworkAccessParameters_networkAddress_q2931Address, + eNetworkAccessParameters_networkAddress_e164Address, + eNetworkAccessParameters_networkAddress_localAreaAddress, + } choice; + union { + H245_TransportAddress localAreaAddress; + }; +} NetworkAccessParameters_networkAddress; + +typedef struct NetworkAccessParameters { /* SEQUENCE */ + enum { + eNetworkAccessParameters_distribution = (1 << 31), + eNetworkAccessParameters_externalReference = (1 << 30), + eNetworkAccessParameters_t120SetupProcedure = (1 << 29), + } options; + NetworkAccessParameters_networkAddress networkAddress; +} NetworkAccessParameters; + +typedef struct OpenLogicalChannel { /* SEQUENCE */ + enum { + eOpenLogicalChannel_reverseLogicalChannelParameters = + (1 << 31), + eOpenLogicalChannel_separateStack = (1 << 30), + eOpenLogicalChannel_encryptionSync = (1 << 29), + } options; + OpenLogicalChannel_forwardLogicalChannelParameters + forwardLogicalChannelParameters; + OpenLogicalChannel_reverseLogicalChannelParameters + reverseLogicalChannelParameters; + NetworkAccessParameters separateStack; +} OpenLogicalChannel; + +typedef struct Setup_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Setup_UUIE_fastStart; + +typedef struct Setup_UUIE { /* SEQUENCE */ + enum { + eSetup_UUIE_h245Address = (1 << 31), + eSetup_UUIE_sourceAddress = (1 << 30), + eSetup_UUIE_destinationAddress = (1 << 29), + eSetup_UUIE_destCallSignalAddress = (1 << 28), + eSetup_UUIE_destExtraCallInfo = (1 << 27), + eSetup_UUIE_destExtraCRV = (1 << 26), + eSetup_UUIE_callServices = (1 << 25), + eSetup_UUIE_sourceCallSignalAddress = (1 << 24), + eSetup_UUIE_remoteExtensionAddress = (1 << 23), + eSetup_UUIE_callIdentifier = (1 << 22), + eSetup_UUIE_h245SecurityCapability = (1 << 21), + eSetup_UUIE_tokens = (1 << 20), + eSetup_UUIE_cryptoTokens = (1 << 19), + eSetup_UUIE_fastStart = (1 << 18), + eSetup_UUIE_mediaWaitForConnect = (1 << 17), + eSetup_UUIE_canOverlapSend = (1 << 16), + eSetup_UUIE_endpointIdentifier = (1 << 15), + eSetup_UUIE_multipleCalls = (1 << 14), + eSetup_UUIE_maintainConnection = (1 << 13), + eSetup_UUIE_connectionParameters = (1 << 12), + eSetup_UUIE_language = (1 << 11), + eSetup_UUIE_presentationIndicator = (1 << 10), + eSetup_UUIE_screeningIndicator = (1 << 9), + eSetup_UUIE_serviceControl = (1 << 8), + eSetup_UUIE_symmetricOperationRequired = (1 << 7), + eSetup_UUIE_capacity = (1 << 6), + eSetup_UUIE_circuitInfo = (1 << 5), + eSetup_UUIE_desiredProtocols = (1 << 4), + eSetup_UUIE_neededFeatures = (1 << 3), + eSetup_UUIE_desiredFeatures = (1 << 2), + eSetup_UUIE_supportedFeatures = (1 << 1), + eSetup_UUIE_parallelH245Control = (1 << 0), + } options; + TransportAddress h245Address; + TransportAddress destCallSignalAddress; + TransportAddress sourceCallSignalAddress; + Setup_UUIE_fastStart fastStart; +} Setup_UUIE; + +typedef struct CallProceeding_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} CallProceeding_UUIE_fastStart; + +typedef struct CallProceeding_UUIE { /* SEQUENCE */ + enum { + eCallProceeding_UUIE_h245Address = (1 << 31), + eCallProceeding_UUIE_callIdentifier = (1 << 30), + eCallProceeding_UUIE_h245SecurityMode = (1 << 29), + eCallProceeding_UUIE_tokens = (1 << 28), + eCallProceeding_UUIE_cryptoTokens = (1 << 27), + eCallProceeding_UUIE_fastStart = (1 << 26), + eCallProceeding_UUIE_multipleCalls = (1 << 25), + eCallProceeding_UUIE_maintainConnection = (1 << 24), + eCallProceeding_UUIE_fastConnectRefused = (1 << 23), + eCallProceeding_UUIE_featureSet = (1 << 22), + } options; + TransportAddress h245Address; + CallProceeding_UUIE_fastStart fastStart; +} CallProceeding_UUIE; + +typedef struct Connect_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Connect_UUIE_fastStart; + +typedef struct Connect_UUIE { /* SEQUENCE */ + enum { + eConnect_UUIE_h245Address = (1 << 31), + eConnect_UUIE_callIdentifier = (1 << 30), + eConnect_UUIE_h245SecurityMode = (1 << 29), + eConnect_UUIE_tokens = (1 << 28), + eConnect_UUIE_cryptoTokens = (1 << 27), + eConnect_UUIE_fastStart = (1 << 26), + eConnect_UUIE_multipleCalls = (1 << 25), + eConnect_UUIE_maintainConnection = (1 << 24), + eConnect_UUIE_language = (1 << 23), + eConnect_UUIE_connectedAddress = (1 << 22), + eConnect_UUIE_presentationIndicator = (1 << 21), + eConnect_UUIE_screeningIndicator = (1 << 20), + eConnect_UUIE_fastConnectRefused = (1 << 19), + eConnect_UUIE_serviceControl = (1 << 18), + eConnect_UUIE_capacity = (1 << 17), + eConnect_UUIE_featureSet = (1 << 16), + } options; + TransportAddress h245Address; + Connect_UUIE_fastStart fastStart; +} Connect_UUIE; + +typedef struct Alerting_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Alerting_UUIE_fastStart; + +typedef struct Alerting_UUIE { /* SEQUENCE */ + enum { + eAlerting_UUIE_h245Address = (1 << 31), + eAlerting_UUIE_callIdentifier = (1 << 30), + eAlerting_UUIE_h245SecurityMode = (1 << 29), + eAlerting_UUIE_tokens = (1 << 28), + eAlerting_UUIE_cryptoTokens = (1 << 27), + eAlerting_UUIE_fastStart = (1 << 26), + eAlerting_UUIE_multipleCalls = (1 << 25), + eAlerting_UUIE_maintainConnection = (1 << 24), + eAlerting_UUIE_alertingAddress = (1 << 23), + eAlerting_UUIE_presentationIndicator = (1 << 22), + eAlerting_UUIE_screeningIndicator = (1 << 21), + eAlerting_UUIE_fastConnectRefused = (1 << 20), + eAlerting_UUIE_serviceControl = (1 << 19), + eAlerting_UUIE_capacity = (1 << 18), + eAlerting_UUIE_featureSet = (1 << 17), + } options; + TransportAddress h245Address; + Alerting_UUIE_fastStart fastStart; +} Alerting_UUIE; + +typedef struct Information_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Information_UUIE_fastStart; + +typedef struct Information_UUIE { /* SEQUENCE */ + enum { + eInformation_UUIE_callIdentifier = (1 << 31), + eInformation_UUIE_tokens = (1 << 30), + eInformation_UUIE_cryptoTokens = (1 << 29), + eInformation_UUIE_fastStart = (1 << 28), + eInformation_UUIE_fastConnectRefused = (1 << 27), + eInformation_UUIE_circuitInfo = (1 << 26), + } options; + Information_UUIE_fastStart fastStart; +} Information_UUIE; + +typedef struct FacilityReason { /* CHOICE */ + enum { + eFacilityReason_routeCallToGatekeeper, + eFacilityReason_callForwarded, + eFacilityReason_routeCallToMC, + eFacilityReason_undefinedReason, + eFacilityReason_conferenceListChoice, + eFacilityReason_startH245, + eFacilityReason_noH245, + eFacilityReason_newTokens, + eFacilityReason_featureSetUpdate, + eFacilityReason_forwardedElements, + eFacilityReason_transportedInformation, + } choice; +} FacilityReason; + +typedef struct Facility_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Facility_UUIE_fastStart; + +typedef struct Facility_UUIE { /* SEQUENCE */ + enum { + eFacility_UUIE_alternativeAddress = (1 << 31), + eFacility_UUIE_alternativeAliasAddress = (1 << 30), + eFacility_UUIE_conferenceID = (1 << 29), + eFacility_UUIE_callIdentifier = (1 << 28), + eFacility_UUIE_destExtraCallInfo = (1 << 27), + eFacility_UUIE_remoteExtensionAddress = (1 << 26), + eFacility_UUIE_tokens = (1 << 25), + eFacility_UUIE_cryptoTokens = (1 << 24), + eFacility_UUIE_conferences = (1 << 23), + eFacility_UUIE_h245Address = (1 << 22), + eFacility_UUIE_fastStart = (1 << 21), + eFacility_UUIE_multipleCalls = (1 << 20), + eFacility_UUIE_maintainConnection = (1 << 19), + eFacility_UUIE_fastConnectRefused = (1 << 18), + eFacility_UUIE_serviceControl = (1 << 17), + eFacility_UUIE_circuitInfo = (1 << 16), + eFacility_UUIE_featureSet = (1 << 15), + eFacility_UUIE_destinationInfo = (1 << 14), + eFacility_UUIE_h245SecurityMode = (1 << 13), + } options; + TransportAddress alternativeAddress; + FacilityReason reason; + TransportAddress h245Address; + Facility_UUIE_fastStart fastStart; +} Facility_UUIE; + +typedef struct Progress_UUIE_fastStart { /* SEQUENCE OF */ + int count; + OpenLogicalChannel item[30]; +} Progress_UUIE_fastStart; + +typedef struct Progress_UUIE { /* SEQUENCE */ + enum { + eProgress_UUIE_h245Address = (1 << 31), + eProgress_UUIE_h245SecurityMode = (1 << 30), + eProgress_UUIE_tokens = (1 << 29), + eProgress_UUIE_cryptoTokens = (1 << 28), + eProgress_UUIE_fastStart = (1 << 27), + eProgress_UUIE_multipleCalls = (1 << 26), + eProgress_UUIE_maintainConnection = (1 << 25), + eProgress_UUIE_fastConnectRefused = (1 << 24), + } options; + TransportAddress h245Address; + Progress_UUIE_fastStart fastStart; +} Progress_UUIE; + +typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */ + enum { + eH323_UU_PDU_h323_message_body_setup, + eH323_UU_PDU_h323_message_body_callProceeding, + eH323_UU_PDU_h323_message_body_connect, + eH323_UU_PDU_h323_message_body_alerting, + eH323_UU_PDU_h323_message_body_information, + eH323_UU_PDU_h323_message_body_releaseComplete, + eH323_UU_PDU_h323_message_body_facility, + eH323_UU_PDU_h323_message_body_progress, + eH323_UU_PDU_h323_message_body_empty, + eH323_UU_PDU_h323_message_body_status, + eH323_UU_PDU_h323_message_body_statusInquiry, + eH323_UU_PDU_h323_message_body_setupAcknowledge, + eH323_UU_PDU_h323_message_body_notify, + } choice; + union { + Setup_UUIE setup; + CallProceeding_UUIE callProceeding; + Connect_UUIE connect; + Alerting_UUIE alerting; + Information_UUIE information; + Facility_UUIE facility; + Progress_UUIE progress; + }; +} H323_UU_PDU_h323_message_body; + +typedef struct RequestMessage { /* CHOICE */ + enum { + eRequestMessage_nonStandard, + eRequestMessage_masterSlaveDetermination, + eRequestMessage_terminalCapabilitySet, + eRequestMessage_openLogicalChannel, + eRequestMessage_closeLogicalChannel, + eRequestMessage_requestChannelClose, + eRequestMessage_multiplexEntrySend, + eRequestMessage_requestMultiplexEntry, + eRequestMessage_requestMode, + eRequestMessage_roundTripDelayRequest, + eRequestMessage_maintenanceLoopRequest, + eRequestMessage_communicationModeRequest, + eRequestMessage_conferenceRequest, + eRequestMessage_multilinkRequest, + eRequestMessage_logicalChannelRateRequest, + } choice; + union { + OpenLogicalChannel openLogicalChannel; + }; +} RequestMessage; + +typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ + enum { + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, + } choice; + union { + H2250LogicalChannelParameters h2250LogicalChannelParameters; + }; +} OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters; + +typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */ + enum { + eOpenLogicalChannelAck_reverseLogicalChannelParameters_portNumber + = (1 << 31), + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters + = (1 << 30), + eOpenLogicalChannelAck_reverseLogicalChannelParameters_replacementFor + = (1 << 29), + } options; + OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters + multiplexParameters; +} OpenLogicalChannelAck_reverseLogicalChannelParameters; + +typedef struct H2250LogicalChannelAckParameters { /* SEQUENCE */ + enum { + eH2250LogicalChannelAckParameters_nonStandard = (1 << 31), + eH2250LogicalChannelAckParameters_sessionID = (1 << 30), + eH2250LogicalChannelAckParameters_mediaChannel = (1 << 29), + eH2250LogicalChannelAckParameters_mediaControlChannel = + (1 << 28), + eH2250LogicalChannelAckParameters_dynamicRTPPayloadType = + (1 << 27), + eH2250LogicalChannelAckParameters_flowControlToZero = + (1 << 26), + eH2250LogicalChannelAckParameters_portNumber = (1 << 25), + } options; + H245_TransportAddress mediaChannel; + H245_TransportAddress mediaControlChannel; +} H2250LogicalChannelAckParameters; + +typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters { /* CHOICE */ + enum { + eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters, + } choice; + union { + H2250LogicalChannelAckParameters + h2250LogicalChannelAckParameters; + }; +} OpenLogicalChannelAck_forwardMultiplexAckParameters; + +typedef struct OpenLogicalChannelAck { /* SEQUENCE */ + enum { + eOpenLogicalChannelAck_reverseLogicalChannelParameters = + (1 << 31), + eOpenLogicalChannelAck_separateStack = (1 << 30), + eOpenLogicalChannelAck_forwardMultiplexAckParameters = + (1 << 29), + eOpenLogicalChannelAck_encryptionSync = (1 << 28), + } options; + OpenLogicalChannelAck_reverseLogicalChannelParameters + reverseLogicalChannelParameters; + OpenLogicalChannelAck_forwardMultiplexAckParameters + forwardMultiplexAckParameters; +} OpenLogicalChannelAck; + +typedef struct ResponseMessage { /* CHOICE */ + enum { + eResponseMessage_nonStandard, + eResponseMessage_masterSlaveDeterminationAck, + eResponseMessage_masterSlaveDeterminationReject, + eResponseMessage_terminalCapabilitySetAck, + eResponseMessage_terminalCapabilitySetReject, + eResponseMessage_openLogicalChannelAck, + eResponseMessage_openLogicalChannelReject, + eResponseMessage_closeLogicalChannelAck, + eResponseMessage_requestChannelCloseAck, + eResponseMessage_requestChannelCloseReject, + eResponseMessage_multiplexEntrySendAck, + eResponseMessage_multiplexEntrySendReject, + eResponseMessage_requestMultiplexEntryAck, + eResponseMessage_requestMultiplexEntryReject, + eResponseMessage_requestModeAck, + eResponseMessage_requestModeReject, + eResponseMessage_roundTripDelayResponse, + eResponseMessage_maintenanceLoopAck, + eResponseMessage_maintenanceLoopReject, + eResponseMessage_communicationModeResponse, + eResponseMessage_conferenceResponse, + eResponseMessage_multilinkResponse, + eResponseMessage_logicalChannelRateAcknowledge, + eResponseMessage_logicalChannelRateReject, + } choice; + union { + OpenLogicalChannelAck openLogicalChannelAck; + }; +} ResponseMessage; + +typedef struct MultimediaSystemControlMessage { /* CHOICE */ + enum { + eMultimediaSystemControlMessage_request, + eMultimediaSystemControlMessage_response, + eMultimediaSystemControlMessage_command, + eMultimediaSystemControlMessage_indication, + } choice; + union { + RequestMessage request; + ResponseMessage response; + }; +} MultimediaSystemControlMessage; + +typedef struct H323_UU_PDU_h245Control { /* SEQUENCE OF */ + int count; + MultimediaSystemControlMessage item[4]; +} H323_UU_PDU_h245Control; + +typedef struct H323_UU_PDU { /* SEQUENCE */ + enum { + eH323_UU_PDU_nonStandardData = (1 << 31), + eH323_UU_PDU_h4501SupplementaryService = (1 << 30), + eH323_UU_PDU_h245Tunneling = (1 << 29), + eH323_UU_PDU_h245Control = (1 << 28), + eH323_UU_PDU_nonStandardControl = (1 << 27), + eH323_UU_PDU_callLinkage = (1 << 26), + eH323_UU_PDU_tunnelledSignallingMessage = (1 << 25), + eH323_UU_PDU_provisionalRespToH245Tunneling = (1 << 24), + eH323_UU_PDU_stimulusControl = (1 << 23), + eH323_UU_PDU_genericData = (1 << 22), + } options; + H323_UU_PDU_h323_message_body h323_message_body; + H323_UU_PDU_h245Control h245Control; +} H323_UU_PDU; + +typedef struct H323_UserInformation { /* SEQUENCE */ + enum { + eH323_UserInformation_user_data = (1 << 31), + } options; + H323_UU_PDU h323_uu_pdu; +} H323_UserInformation; + +typedef struct GatekeeperRequest { /* SEQUENCE */ + enum { + eGatekeeperRequest_nonStandardData = (1 << 31), + eGatekeeperRequest_gatekeeperIdentifier = (1 << 30), + eGatekeeperRequest_callServices = (1 << 29), + eGatekeeperRequest_endpointAlias = (1 << 28), + eGatekeeperRequest_alternateEndpoints = (1 << 27), + eGatekeeperRequest_tokens = (1 << 26), + eGatekeeperRequest_cryptoTokens = (1 << 25), + eGatekeeperRequest_authenticationCapability = (1 << 24), + eGatekeeperRequest_algorithmOIDs = (1 << 23), + eGatekeeperRequest_integrity = (1 << 22), + eGatekeeperRequest_integrityCheckValue = (1 << 21), + eGatekeeperRequest_supportsAltGK = (1 << 20), + eGatekeeperRequest_featureSet = (1 << 19), + eGatekeeperRequest_genericData = (1 << 18), + } options; + TransportAddress rasAddress; +} GatekeeperRequest; + +typedef struct GatekeeperConfirm { /* SEQUENCE */ + enum { + eGatekeeperConfirm_nonStandardData = (1 << 31), + eGatekeeperConfirm_gatekeeperIdentifier = (1 << 30), + eGatekeeperConfirm_alternateGatekeeper = (1 << 29), + eGatekeeperConfirm_authenticationMode = (1 << 28), + eGatekeeperConfirm_tokens = (1 << 27), + eGatekeeperConfirm_cryptoTokens = (1 << 26), + eGatekeeperConfirm_algorithmOID = (1 << 25), + eGatekeeperConfirm_integrity = (1 << 24), + eGatekeeperConfirm_integrityCheckValue = (1 << 23), + eGatekeeperConfirm_featureSet = (1 << 22), + eGatekeeperConfirm_genericData = (1 << 21), + } options; + TransportAddress rasAddress; +} GatekeeperConfirm; + +typedef struct RegistrationRequest_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} RegistrationRequest_callSignalAddress; + +typedef struct RegistrationRequest_rasAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} RegistrationRequest_rasAddress; + +typedef struct RegistrationRequest { /* SEQUENCE */ + enum { + eRegistrationRequest_nonStandardData = (1 << 31), + eRegistrationRequest_terminalAlias = (1 << 30), + eRegistrationRequest_gatekeeperIdentifier = (1 << 29), + eRegistrationRequest_alternateEndpoints = (1 << 28), + eRegistrationRequest_timeToLive = (1 << 27), + eRegistrationRequest_tokens = (1 << 26), + eRegistrationRequest_cryptoTokens = (1 << 25), + eRegistrationRequest_integrityCheckValue = (1 << 24), + eRegistrationRequest_keepAlive = (1 << 23), + eRegistrationRequest_endpointIdentifier = (1 << 22), + eRegistrationRequest_willSupplyUUIEs = (1 << 21), + eRegistrationRequest_maintainConnection = (1 << 20), + eRegistrationRequest_alternateTransportAddresses = (1 << 19), + eRegistrationRequest_additiveRegistration = (1 << 18), + eRegistrationRequest_terminalAliasPattern = (1 << 17), + eRegistrationRequest_supportsAltGK = (1 << 16), + eRegistrationRequest_usageReportingCapability = (1 << 15), + eRegistrationRequest_multipleCalls = (1 << 14), + eRegistrationRequest_supportedH248Packages = (1 << 13), + eRegistrationRequest_callCreditCapability = (1 << 12), + eRegistrationRequest_capacityReportingCapability = (1 << 11), + eRegistrationRequest_capacity = (1 << 10), + eRegistrationRequest_featureSet = (1 << 9), + eRegistrationRequest_genericData = (1 << 8), + } options; + RegistrationRequest_callSignalAddress callSignalAddress; + RegistrationRequest_rasAddress rasAddress; + unsigned timeToLive; +} RegistrationRequest; + +typedef struct RegistrationConfirm_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} RegistrationConfirm_callSignalAddress; + +typedef struct RegistrationConfirm { /* SEQUENCE */ + enum { + eRegistrationConfirm_nonStandardData = (1 << 31), + eRegistrationConfirm_terminalAlias = (1 << 30), + eRegistrationConfirm_gatekeeperIdentifier = (1 << 29), + eRegistrationConfirm_alternateGatekeeper = (1 << 28), + eRegistrationConfirm_timeToLive = (1 << 27), + eRegistrationConfirm_tokens = (1 << 26), + eRegistrationConfirm_cryptoTokens = (1 << 25), + eRegistrationConfirm_integrityCheckValue = (1 << 24), + eRegistrationConfirm_willRespondToIRR = (1 << 23), + eRegistrationConfirm_preGrantedARQ = (1 << 22), + eRegistrationConfirm_maintainConnection = (1 << 21), + eRegistrationConfirm_serviceControl = (1 << 20), + eRegistrationConfirm_supportsAdditiveRegistration = (1 << 19), + eRegistrationConfirm_terminalAliasPattern = (1 << 18), + eRegistrationConfirm_supportedPrefixes = (1 << 17), + eRegistrationConfirm_usageSpec = (1 << 16), + eRegistrationConfirm_featureServerAlias = (1 << 15), + eRegistrationConfirm_capacityReportingSpec = (1 << 14), + eRegistrationConfirm_featureSet = (1 << 13), + eRegistrationConfirm_genericData = (1 << 12), + } options; + RegistrationConfirm_callSignalAddress callSignalAddress; + unsigned timeToLive; +} RegistrationConfirm; + +typedef struct UnregistrationRequest_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} UnregistrationRequest_callSignalAddress; + +typedef struct UnregistrationRequest { /* SEQUENCE */ + enum { + eUnregistrationRequest_endpointAlias = (1 << 31), + eUnregistrationRequest_nonStandardData = (1 << 30), + eUnregistrationRequest_endpointIdentifier = (1 << 29), + eUnregistrationRequest_alternateEndpoints = (1 << 28), + eUnregistrationRequest_gatekeeperIdentifier = (1 << 27), + eUnregistrationRequest_tokens = (1 << 26), + eUnregistrationRequest_cryptoTokens = (1 << 25), + eUnregistrationRequest_integrityCheckValue = (1 << 24), + eUnregistrationRequest_reason = (1 << 23), + eUnregistrationRequest_endpointAliasPattern = (1 << 22), + eUnregistrationRequest_supportedPrefixes = (1 << 21), + eUnregistrationRequest_alternateGatekeeper = (1 << 20), + eUnregistrationRequest_genericData = (1 << 19), + } options; + UnregistrationRequest_callSignalAddress callSignalAddress; +} UnregistrationRequest; + +typedef struct AdmissionRequest { /* SEQUENCE */ + enum { + eAdmissionRequest_callModel = (1 << 31), + eAdmissionRequest_destinationInfo = (1 << 30), + eAdmissionRequest_destCallSignalAddress = (1 << 29), + eAdmissionRequest_destExtraCallInfo = (1 << 28), + eAdmissionRequest_srcCallSignalAddress = (1 << 27), + eAdmissionRequest_nonStandardData = (1 << 26), + eAdmissionRequest_callServices = (1 << 25), + eAdmissionRequest_canMapAlias = (1 << 24), + eAdmissionRequest_callIdentifier = (1 << 23), + eAdmissionRequest_srcAlternatives = (1 << 22), + eAdmissionRequest_destAlternatives = (1 << 21), + eAdmissionRequest_gatekeeperIdentifier = (1 << 20), + eAdmissionRequest_tokens = (1 << 19), + eAdmissionRequest_cryptoTokens = (1 << 18), + eAdmissionRequest_integrityCheckValue = (1 << 17), + eAdmissionRequest_transportQOS = (1 << 16), + eAdmissionRequest_willSupplyUUIEs = (1 << 15), + eAdmissionRequest_callLinkage = (1 << 14), + eAdmissionRequest_gatewayDataRate = (1 << 13), + eAdmissionRequest_capacity = (1 << 12), + eAdmissionRequest_circuitInfo = (1 << 11), + eAdmissionRequest_desiredProtocols = (1 << 10), + eAdmissionRequest_desiredTunnelledProtocol = (1 << 9), + eAdmissionRequest_featureSet = (1 << 8), + eAdmissionRequest_genericData = (1 << 7), + } options; + TransportAddress destCallSignalAddress; + TransportAddress srcCallSignalAddress; +} AdmissionRequest; + +typedef struct AdmissionConfirm { /* SEQUENCE */ + enum { + eAdmissionConfirm_irrFrequency = (1 << 31), + eAdmissionConfirm_nonStandardData = (1 << 30), + eAdmissionConfirm_destinationInfo = (1 << 29), + eAdmissionConfirm_destExtraCallInfo = (1 << 28), + eAdmissionConfirm_destinationType = (1 << 27), + eAdmissionConfirm_remoteExtensionAddress = (1 << 26), + eAdmissionConfirm_alternateEndpoints = (1 << 25), + eAdmissionConfirm_tokens = (1 << 24), + eAdmissionConfirm_cryptoTokens = (1 << 23), + eAdmissionConfirm_integrityCheckValue = (1 << 22), + eAdmissionConfirm_transportQOS = (1 << 21), + eAdmissionConfirm_willRespondToIRR = (1 << 20), + eAdmissionConfirm_uuiesRequested = (1 << 19), + eAdmissionConfirm_language = (1 << 18), + eAdmissionConfirm_alternateTransportAddresses = (1 << 17), + eAdmissionConfirm_useSpecifiedTransport = (1 << 16), + eAdmissionConfirm_circuitInfo = (1 << 15), + eAdmissionConfirm_usageSpec = (1 << 14), + eAdmissionConfirm_supportedProtocols = (1 << 13), + eAdmissionConfirm_serviceControl = (1 << 12), + eAdmissionConfirm_multipleCalls = (1 << 11), + eAdmissionConfirm_featureSet = (1 << 10), + eAdmissionConfirm_genericData = (1 << 9), + } options; + TransportAddress destCallSignalAddress; +} AdmissionConfirm; + +typedef struct LocationRequest { /* SEQUENCE */ + enum { + eLocationRequest_endpointIdentifier = (1 << 31), + eLocationRequest_nonStandardData = (1 << 30), + eLocationRequest_sourceInfo = (1 << 29), + eLocationRequest_canMapAlias = (1 << 28), + eLocationRequest_gatekeeperIdentifier = (1 << 27), + eLocationRequest_tokens = (1 << 26), + eLocationRequest_cryptoTokens = (1 << 25), + eLocationRequest_integrityCheckValue = (1 << 24), + eLocationRequest_desiredProtocols = (1 << 23), + eLocationRequest_desiredTunnelledProtocol = (1 << 22), + eLocationRequest_featureSet = (1 << 21), + eLocationRequest_genericData = (1 << 20), + eLocationRequest_hopCount = (1 << 19), + eLocationRequest_circuitInfo = (1 << 18), + } options; + TransportAddress replyAddress; +} LocationRequest; + +typedef struct LocationConfirm { /* SEQUENCE */ + enum { + eLocationConfirm_nonStandardData = (1 << 31), + eLocationConfirm_destinationInfo = (1 << 30), + eLocationConfirm_destExtraCallInfo = (1 << 29), + eLocationConfirm_destinationType = (1 << 28), + eLocationConfirm_remoteExtensionAddress = (1 << 27), + eLocationConfirm_alternateEndpoints = (1 << 26), + eLocationConfirm_tokens = (1 << 25), + eLocationConfirm_cryptoTokens = (1 << 24), + eLocationConfirm_integrityCheckValue = (1 << 23), + eLocationConfirm_alternateTransportAddresses = (1 << 22), + eLocationConfirm_supportedProtocols = (1 << 21), + eLocationConfirm_multipleCalls = (1 << 20), + eLocationConfirm_featureSet = (1 << 19), + eLocationConfirm_genericData = (1 << 18), + eLocationConfirm_circuitInfo = (1 << 17), + eLocationConfirm_serviceControl = (1 << 16), + } options; + TransportAddress callSignalAddress; + TransportAddress rasAddress; +} LocationConfirm; + +typedef struct InfoRequestResponse_callSignalAddress { /* SEQUENCE OF */ + int count; + TransportAddress item[10]; +} InfoRequestResponse_callSignalAddress; + +typedef struct InfoRequestResponse { /* SEQUENCE */ + enum { + eInfoRequestResponse_nonStandardData = (1 << 31), + eInfoRequestResponse_endpointAlias = (1 << 30), + eInfoRequestResponse_perCallInfo = (1 << 29), + eInfoRequestResponse_tokens = (1 << 28), + eInfoRequestResponse_cryptoTokens = (1 << 27), + eInfoRequestResponse_integrityCheckValue = (1 << 26), + eInfoRequestResponse_needResponse = (1 << 25), + eInfoRequestResponse_capacity = (1 << 24), + eInfoRequestResponse_irrStatus = (1 << 23), + eInfoRequestResponse_unsolicited = (1 << 22), + eInfoRequestResponse_genericData = (1 << 21), + } options; + TransportAddress rasAddress; + InfoRequestResponse_callSignalAddress callSignalAddress; +} InfoRequestResponse; + +typedef struct RasMessage { /* CHOICE */ + enum { + eRasMessage_gatekeeperRequest, + eRasMessage_gatekeeperConfirm, + eRasMessage_gatekeeperReject, + eRasMessage_registrationRequest, + eRasMessage_registrationConfirm, + eRasMessage_registrationReject, + eRasMessage_unregistrationRequest, + eRasMessage_unregistrationConfirm, + eRasMessage_unregistrationReject, + eRasMessage_admissionRequest, + eRasMessage_admissionConfirm, + eRasMessage_admissionReject, + eRasMessage_bandwidthRequest, + eRasMessage_bandwidthConfirm, + eRasMessage_bandwidthReject, + eRasMessage_disengageRequest, + eRasMessage_disengageConfirm, + eRasMessage_disengageReject, + eRasMessage_locationRequest, + eRasMessage_locationConfirm, + eRasMessage_locationReject, + eRasMessage_infoRequest, + eRasMessage_infoRequestResponse, + eRasMessage_nonStandardMessage, + eRasMessage_unknownMessageResponse, + eRasMessage_requestInProgress, + eRasMessage_resourcesAvailableIndicate, + eRasMessage_resourcesAvailableConfirm, + eRasMessage_infoRequestAck, + eRasMessage_infoRequestNak, + eRasMessage_serviceControlIndication, + eRasMessage_serviceControlResponse, + } choice; + union { + GatekeeperRequest gatekeeperRequest; + GatekeeperConfirm gatekeeperConfirm; + RegistrationRequest registrationRequest; + RegistrationConfirm registrationConfirm; + UnregistrationRequest unregistrationRequest; + AdmissionRequest admissionRequest; + AdmissionConfirm admissionConfirm; + LocationRequest locationRequest; + LocationConfirm locationConfirm; + InfoRequestResponse infoRequestResponse; + }; +} RasMessage; diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 591c1a809c00..180337801a86 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild @@ -1,6 +1,4 @@ header-y += ip_conntrack_helper.h -header-y += ip_conntrack_helper_h323_asn1.h -header-y += ip_conntrack_helper_h323_types.h header-y += ip_conntrack_protocol.h header-y += ip_conntrack_sctp.h header-y += ip_conntrack_tcp.h diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h index 943cc6a4871d..18f769818f4e 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h @@ -3,7 +3,7 @@ #ifdef __KERNEL__ -#include +#include #define RAS_PORT 1719 #define Q931_PORT 1720 diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h deleted file mode 100644 index c6e9a0b6d30b..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** - * ip_conntrack_helper_h323_asn1.h - BER and PER decoding library for H.323 - * conntrack/NAT module. - * - * Copyright (c) 2006 by Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - * - * - * This library is based on H.225 version 4, H.235 version 2 and H.245 - * version 7. It is extremely optimized to decode only the absolutely - * necessary objects in a signal for Linux kernel NAT module use, so don't - * expect it to be a full ASN.1 library. - * - * Features: - * - * 1. Small. The total size of code plus data is less than 20 KB (IA32). - * 2. Fast. Decoding Netmeeting's Setup signal 1 million times on a PIII 866 - * takes only 3.9 seconds. - * 3. No memory allocation. It uses a static object. No need to initialize or - * cleanup. - * 4. Thread safe. - * 5. Support embedded architectures that has no misaligned memory access - * support. - * - * Limitations: - * - * 1. At most 30 faststart entries. Actually this is limited by ethernet's MTU. - * If a Setup signal contains more than 30 faststart, the packet size will - * very likely exceed the MTU size, then the TPKT will be fragmented. I - * don't know how to handle this in a Netfilter module. Anybody can help? - * Although I think 30 is enough for most of the cases. - * 2. IPv4 addresses only. - * - ****************************************************************************/ - -#ifndef _IP_CONNTRACK_HELPER_H323_ASN1_H_ -#define _IP_CONNTRACK_HELPER_H323_ASN1_H_ - -/***************************************************************************** - * H.323 Types - ****************************************************************************/ -#include "ip_conntrack_helper_h323_types.h" - -typedef struct { - enum { - Q931_NationalEscape = 0x00, - Q931_Alerting = 0x01, - Q931_CallProceeding = 0x02, - Q931_Connect = 0x07, - Q931_ConnectAck = 0x0F, - Q931_Progress = 0x03, - Q931_Setup = 0x05, - Q931_SetupAck = 0x0D, - Q931_Resume = 0x26, - Q931_ResumeAck = 0x2E, - Q931_ResumeReject = 0x22, - Q931_Suspend = 0x25, - Q931_SuspendAck = 0x2D, - Q931_SuspendReject = 0x21, - Q931_UserInformation = 0x20, - Q931_Disconnect = 0x45, - Q931_Release = 0x4D, - Q931_ReleaseComplete = 0x5A, - Q931_Restart = 0x46, - Q931_RestartAck = 0x4E, - Q931_Segment = 0x60, - Q931_CongestionCtrl = 0x79, - Q931_Information = 0x7B, - Q931_Notify = 0x6E, - Q931_Status = 0x7D, - Q931_StatusEnquiry = 0x75, - Q931_Facility = 0x62 - } MessageType; - H323_UserInformation UUIE; -} Q931; - -/***************************************************************************** - * Decode Functions Return Codes - ****************************************************************************/ - -#define H323_ERROR_NONE 0 /* Decoded successfully */ -#define H323_ERROR_STOP 1 /* Decoding stopped, not really an error */ -#define H323_ERROR_BOUND -1 -#define H323_ERROR_RANGE -2 - - -/***************************************************************************** - * Decode Functions - ****************************************************************************/ - -int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras); -int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931); -int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, - MultimediaSystemControlMessage * - mscm); - -#endif diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h deleted file mode 100644 index 3d4a773799fc..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h +++ /dev/null @@ -1,939 +0,0 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 - * - * Copyright (c) 2006 Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - */ - -typedef struct TransportAddress_ipAddress { /* SEQUENCE */ - int options; /* No use */ - unsigned ip; -} TransportAddress_ipAddress; - -typedef struct TransportAddress { /* CHOICE */ - enum { - eTransportAddress_ipAddress, - eTransportAddress_ipSourceRoute, - eTransportAddress_ipxAddress, - eTransportAddress_ip6Address, - eTransportAddress_netBios, - eTransportAddress_nsap, - eTransportAddress_nonStandardAddress, - } choice; - union { - TransportAddress_ipAddress ipAddress; - }; -} TransportAddress; - -typedef struct DataProtocolCapability { /* CHOICE */ - enum { - eDataProtocolCapability_nonStandard, - eDataProtocolCapability_v14buffered, - eDataProtocolCapability_v42lapm, - eDataProtocolCapability_hdlcFrameTunnelling, - eDataProtocolCapability_h310SeparateVCStack, - eDataProtocolCapability_h310SingleVCStack, - eDataProtocolCapability_transparent, - eDataProtocolCapability_segmentationAndReassembly, - eDataProtocolCapability_hdlcFrameTunnelingwSAR, - eDataProtocolCapability_v120, - eDataProtocolCapability_separateLANStack, - eDataProtocolCapability_v76wCompression, - eDataProtocolCapability_tcp, - eDataProtocolCapability_udp, - } choice; -} DataProtocolCapability; - -typedef struct DataApplicationCapability_application { /* CHOICE */ - enum { - eDataApplicationCapability_application_nonStandard, - eDataApplicationCapability_application_t120, - eDataApplicationCapability_application_dsm_cc, - eDataApplicationCapability_application_userData, - eDataApplicationCapability_application_t84, - eDataApplicationCapability_application_t434, - eDataApplicationCapability_application_h224, - eDataApplicationCapability_application_nlpid, - eDataApplicationCapability_application_dsvdControl, - eDataApplicationCapability_application_h222DataPartitioning, - eDataApplicationCapability_application_t30fax, - eDataApplicationCapability_application_t140, - eDataApplicationCapability_application_t38fax, - eDataApplicationCapability_application_genericDataCapability, - } choice; - union { - DataProtocolCapability t120; - }; -} DataApplicationCapability_application; - -typedef struct DataApplicationCapability { /* SEQUENCE */ - int options; /* No use */ - DataApplicationCapability_application application; -} DataApplicationCapability; - -typedef struct DataType { /* CHOICE */ - enum { - eDataType_nonStandard, - eDataType_nullData, - eDataType_videoData, - eDataType_audioData, - eDataType_data, - eDataType_encryptionData, - eDataType_h235Control, - eDataType_h235Media, - eDataType_multiplexedStream, - } choice; - union { - DataApplicationCapability data; - }; -} DataType; - -typedef struct UnicastAddress_iPAddress { /* SEQUENCE */ - int options; /* No use */ - unsigned network; -} UnicastAddress_iPAddress; - -typedef struct UnicastAddress { /* CHOICE */ - enum { - eUnicastAddress_iPAddress, - eUnicastAddress_iPXAddress, - eUnicastAddress_iP6Address, - eUnicastAddress_netBios, - eUnicastAddress_iPSourceRouteAddress, - eUnicastAddress_nsap, - eUnicastAddress_nonStandardAddress, - } choice; - union { - UnicastAddress_iPAddress iPAddress; - }; -} UnicastAddress; - -typedef struct H245_TransportAddress { /* CHOICE */ - enum { - eH245_TransportAddress_unicastAddress, - eH245_TransportAddress_multicastAddress, - } choice; - union { - UnicastAddress unicastAddress; - }; -} H245_TransportAddress; - -typedef struct H2250LogicalChannelParameters { /* SEQUENCE */ - enum { - eH2250LogicalChannelParameters_nonStandard = (1 << 31), - eH2250LogicalChannelParameters_associatedSessionID = - (1 << 30), - eH2250LogicalChannelParameters_mediaChannel = (1 << 29), - eH2250LogicalChannelParameters_mediaGuaranteedDelivery = - (1 << 28), - eH2250LogicalChannelParameters_mediaControlChannel = - (1 << 27), - eH2250LogicalChannelParameters_mediaControlGuaranteedDelivery - = (1 << 26), - eH2250LogicalChannelParameters_silenceSuppression = (1 << 25), - eH2250LogicalChannelParameters_destination = (1 << 24), - eH2250LogicalChannelParameters_dynamicRTPPayloadType = - (1 << 23), - eH2250LogicalChannelParameters_mediaPacketization = (1 << 22), - eH2250LogicalChannelParameters_transportCapability = - (1 << 21), - eH2250LogicalChannelParameters_redundancyEncoding = (1 << 20), - eH2250LogicalChannelParameters_source = (1 << 19), - } options; - H245_TransportAddress mediaChannel; - H245_TransportAddress mediaControlChannel; -} H2250LogicalChannelParameters; - -typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters { /* CHOICE */ - enum { - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, - eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none, - } choice; - union { - H2250LogicalChannelParameters h2250LogicalChannelParameters; - }; -} OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters; - -typedef struct OpenLogicalChannel_forwardLogicalChannelParameters { /* SEQUENCE */ - enum { - eOpenLogicalChannel_forwardLogicalChannelParameters_portNumber - = (1 << 31), - eOpenLogicalChannel_forwardLogicalChannelParameters_forwardLogicalChannelDependency - = (1 << 30), - eOpenLogicalChannel_forwardLogicalChannelParameters_replacementFor - = (1 << 29), - } options; - DataType dataType; - OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters - multiplexParameters; -} OpenLogicalChannel_forwardLogicalChannelParameters; - -typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ - enum { - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, - } choice; - union { - H2250LogicalChannelParameters h2250LogicalChannelParameters; - }; -} OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters; - -typedef struct OpenLogicalChannel_reverseLogicalChannelParameters { /* SEQUENCE */ - enum { - eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters - = (1 << 31), - eOpenLogicalChannel_reverseLogicalChannelParameters_reverseLogicalChannelDependency - = (1 << 30), - eOpenLogicalChannel_reverseLogicalChannelParameters_replacementFor - = (1 << 29), - } options; - OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters - multiplexParameters; -} OpenLogicalChannel_reverseLogicalChannelParameters; - -typedef struct NetworkAccessParameters_networkAddress { /* CHOICE */ - enum { - eNetworkAccessParameters_networkAddress_q2931Address, - eNetworkAccessParameters_networkAddress_e164Address, - eNetworkAccessParameters_networkAddress_localAreaAddress, - } choice; - union { - H245_TransportAddress localAreaAddress; - }; -} NetworkAccessParameters_networkAddress; - -typedef struct NetworkAccessParameters { /* SEQUENCE */ - enum { - eNetworkAccessParameters_distribution = (1 << 31), - eNetworkAccessParameters_externalReference = (1 << 30), - eNetworkAccessParameters_t120SetupProcedure = (1 << 29), - } options; - NetworkAccessParameters_networkAddress networkAddress; -} NetworkAccessParameters; - -typedef struct OpenLogicalChannel { /* SEQUENCE */ - enum { - eOpenLogicalChannel_reverseLogicalChannelParameters = - (1 << 31), - eOpenLogicalChannel_separateStack = (1 << 30), - eOpenLogicalChannel_encryptionSync = (1 << 29), - } options; - OpenLogicalChannel_forwardLogicalChannelParameters - forwardLogicalChannelParameters; - OpenLogicalChannel_reverseLogicalChannelParameters - reverseLogicalChannelParameters; - NetworkAccessParameters separateStack; -} OpenLogicalChannel; - -typedef struct Setup_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Setup_UUIE_fastStart; - -typedef struct Setup_UUIE { /* SEQUENCE */ - enum { - eSetup_UUIE_h245Address = (1 << 31), - eSetup_UUIE_sourceAddress = (1 << 30), - eSetup_UUIE_destinationAddress = (1 << 29), - eSetup_UUIE_destCallSignalAddress = (1 << 28), - eSetup_UUIE_destExtraCallInfo = (1 << 27), - eSetup_UUIE_destExtraCRV = (1 << 26), - eSetup_UUIE_callServices = (1 << 25), - eSetup_UUIE_sourceCallSignalAddress = (1 << 24), - eSetup_UUIE_remoteExtensionAddress = (1 << 23), - eSetup_UUIE_callIdentifier = (1 << 22), - eSetup_UUIE_h245SecurityCapability = (1 << 21), - eSetup_UUIE_tokens = (1 << 20), - eSetup_UUIE_cryptoTokens = (1 << 19), - eSetup_UUIE_fastStart = (1 << 18), - eSetup_UUIE_mediaWaitForConnect = (1 << 17), - eSetup_UUIE_canOverlapSend = (1 << 16), - eSetup_UUIE_endpointIdentifier = (1 << 15), - eSetup_UUIE_multipleCalls = (1 << 14), - eSetup_UUIE_maintainConnection = (1 << 13), - eSetup_UUIE_connectionParameters = (1 << 12), - eSetup_UUIE_language = (1 << 11), - eSetup_UUIE_presentationIndicator = (1 << 10), - eSetup_UUIE_screeningIndicator = (1 << 9), - eSetup_UUIE_serviceControl = (1 << 8), - eSetup_UUIE_symmetricOperationRequired = (1 << 7), - eSetup_UUIE_capacity = (1 << 6), - eSetup_UUIE_circuitInfo = (1 << 5), - eSetup_UUIE_desiredProtocols = (1 << 4), - eSetup_UUIE_neededFeatures = (1 << 3), - eSetup_UUIE_desiredFeatures = (1 << 2), - eSetup_UUIE_supportedFeatures = (1 << 1), - eSetup_UUIE_parallelH245Control = (1 << 0), - } options; - TransportAddress h245Address; - TransportAddress destCallSignalAddress; - TransportAddress sourceCallSignalAddress; - Setup_UUIE_fastStart fastStart; -} Setup_UUIE; - -typedef struct CallProceeding_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} CallProceeding_UUIE_fastStart; - -typedef struct CallProceeding_UUIE { /* SEQUENCE */ - enum { - eCallProceeding_UUIE_h245Address = (1 << 31), - eCallProceeding_UUIE_callIdentifier = (1 << 30), - eCallProceeding_UUIE_h245SecurityMode = (1 << 29), - eCallProceeding_UUIE_tokens = (1 << 28), - eCallProceeding_UUIE_cryptoTokens = (1 << 27), - eCallProceeding_UUIE_fastStart = (1 << 26), - eCallProceeding_UUIE_multipleCalls = (1 << 25), - eCallProceeding_UUIE_maintainConnection = (1 << 24), - eCallProceeding_UUIE_fastConnectRefused = (1 << 23), - eCallProceeding_UUIE_featureSet = (1 << 22), - } options; - TransportAddress h245Address; - CallProceeding_UUIE_fastStart fastStart; -} CallProceeding_UUIE; - -typedef struct Connect_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Connect_UUIE_fastStart; - -typedef struct Connect_UUIE { /* SEQUENCE */ - enum { - eConnect_UUIE_h245Address = (1 << 31), - eConnect_UUIE_callIdentifier = (1 << 30), - eConnect_UUIE_h245SecurityMode = (1 << 29), - eConnect_UUIE_tokens = (1 << 28), - eConnect_UUIE_cryptoTokens = (1 << 27), - eConnect_UUIE_fastStart = (1 << 26), - eConnect_UUIE_multipleCalls = (1 << 25), - eConnect_UUIE_maintainConnection = (1 << 24), - eConnect_UUIE_language = (1 << 23), - eConnect_UUIE_connectedAddress = (1 << 22), - eConnect_UUIE_presentationIndicator = (1 << 21), - eConnect_UUIE_screeningIndicator = (1 << 20), - eConnect_UUIE_fastConnectRefused = (1 << 19), - eConnect_UUIE_serviceControl = (1 << 18), - eConnect_UUIE_capacity = (1 << 17), - eConnect_UUIE_featureSet = (1 << 16), - } options; - TransportAddress h245Address; - Connect_UUIE_fastStart fastStart; -} Connect_UUIE; - -typedef struct Alerting_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Alerting_UUIE_fastStart; - -typedef struct Alerting_UUIE { /* SEQUENCE */ - enum { - eAlerting_UUIE_h245Address = (1 << 31), - eAlerting_UUIE_callIdentifier = (1 << 30), - eAlerting_UUIE_h245SecurityMode = (1 << 29), - eAlerting_UUIE_tokens = (1 << 28), - eAlerting_UUIE_cryptoTokens = (1 << 27), - eAlerting_UUIE_fastStart = (1 << 26), - eAlerting_UUIE_multipleCalls = (1 << 25), - eAlerting_UUIE_maintainConnection = (1 << 24), - eAlerting_UUIE_alertingAddress = (1 << 23), - eAlerting_UUIE_presentationIndicator = (1 << 22), - eAlerting_UUIE_screeningIndicator = (1 << 21), - eAlerting_UUIE_fastConnectRefused = (1 << 20), - eAlerting_UUIE_serviceControl = (1 << 19), - eAlerting_UUIE_capacity = (1 << 18), - eAlerting_UUIE_featureSet = (1 << 17), - } options; - TransportAddress h245Address; - Alerting_UUIE_fastStart fastStart; -} Alerting_UUIE; - -typedef struct Information_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Information_UUIE_fastStart; - -typedef struct Information_UUIE { /* SEQUENCE */ - enum { - eInformation_UUIE_callIdentifier = (1 << 31), - eInformation_UUIE_tokens = (1 << 30), - eInformation_UUIE_cryptoTokens = (1 << 29), - eInformation_UUIE_fastStart = (1 << 28), - eInformation_UUIE_fastConnectRefused = (1 << 27), - eInformation_UUIE_circuitInfo = (1 << 26), - } options; - Information_UUIE_fastStart fastStart; -} Information_UUIE; - -typedef struct FacilityReason { /* CHOICE */ - enum { - eFacilityReason_routeCallToGatekeeper, - eFacilityReason_callForwarded, - eFacilityReason_routeCallToMC, - eFacilityReason_undefinedReason, - eFacilityReason_conferenceListChoice, - eFacilityReason_startH245, - eFacilityReason_noH245, - eFacilityReason_newTokens, - eFacilityReason_featureSetUpdate, - eFacilityReason_forwardedElements, - eFacilityReason_transportedInformation, - } choice; -} FacilityReason; - -typedef struct Facility_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Facility_UUIE_fastStart; - -typedef struct Facility_UUIE { /* SEQUENCE */ - enum { - eFacility_UUIE_alternativeAddress = (1 << 31), - eFacility_UUIE_alternativeAliasAddress = (1 << 30), - eFacility_UUIE_conferenceID = (1 << 29), - eFacility_UUIE_callIdentifier = (1 << 28), - eFacility_UUIE_destExtraCallInfo = (1 << 27), - eFacility_UUIE_remoteExtensionAddress = (1 << 26), - eFacility_UUIE_tokens = (1 << 25), - eFacility_UUIE_cryptoTokens = (1 << 24), - eFacility_UUIE_conferences = (1 << 23), - eFacility_UUIE_h245Address = (1 << 22), - eFacility_UUIE_fastStart = (1 << 21), - eFacility_UUIE_multipleCalls = (1 << 20), - eFacility_UUIE_maintainConnection = (1 << 19), - eFacility_UUIE_fastConnectRefused = (1 << 18), - eFacility_UUIE_serviceControl = (1 << 17), - eFacility_UUIE_circuitInfo = (1 << 16), - eFacility_UUIE_featureSet = (1 << 15), - eFacility_UUIE_destinationInfo = (1 << 14), - eFacility_UUIE_h245SecurityMode = (1 << 13), - } options; - TransportAddress alternativeAddress; - FacilityReason reason; - TransportAddress h245Address; - Facility_UUIE_fastStart fastStart; -} Facility_UUIE; - -typedef struct Progress_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Progress_UUIE_fastStart; - -typedef struct Progress_UUIE { /* SEQUENCE */ - enum { - eProgress_UUIE_h245Address = (1 << 31), - eProgress_UUIE_h245SecurityMode = (1 << 30), - eProgress_UUIE_tokens = (1 << 29), - eProgress_UUIE_cryptoTokens = (1 << 28), - eProgress_UUIE_fastStart = (1 << 27), - eProgress_UUIE_multipleCalls = (1 << 26), - eProgress_UUIE_maintainConnection = (1 << 25), - eProgress_UUIE_fastConnectRefused = (1 << 24), - } options; - TransportAddress h245Address; - Progress_UUIE_fastStart fastStart; -} Progress_UUIE; - -typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */ - enum { - eH323_UU_PDU_h323_message_body_setup, - eH323_UU_PDU_h323_message_body_callProceeding, - eH323_UU_PDU_h323_message_body_connect, - eH323_UU_PDU_h323_message_body_alerting, - eH323_UU_PDU_h323_message_body_information, - eH323_UU_PDU_h323_message_body_releaseComplete, - eH323_UU_PDU_h323_message_body_facility, - eH323_UU_PDU_h323_message_body_progress, - eH323_UU_PDU_h323_message_body_empty, - eH323_UU_PDU_h323_message_body_status, - eH323_UU_PDU_h323_message_body_statusInquiry, - eH323_UU_PDU_h323_message_body_setupAcknowledge, - eH323_UU_PDU_h323_message_body_notify, - } choice; - union { - Setup_UUIE setup; - CallProceeding_UUIE callProceeding; - Connect_UUIE connect; - Alerting_UUIE alerting; - Information_UUIE information; - Facility_UUIE facility; - Progress_UUIE progress; - }; -} H323_UU_PDU_h323_message_body; - -typedef struct RequestMessage { /* CHOICE */ - enum { - eRequestMessage_nonStandard, - eRequestMessage_masterSlaveDetermination, - eRequestMessage_terminalCapabilitySet, - eRequestMessage_openLogicalChannel, - eRequestMessage_closeLogicalChannel, - eRequestMessage_requestChannelClose, - eRequestMessage_multiplexEntrySend, - eRequestMessage_requestMultiplexEntry, - eRequestMessage_requestMode, - eRequestMessage_roundTripDelayRequest, - eRequestMessage_maintenanceLoopRequest, - eRequestMessage_communicationModeRequest, - eRequestMessage_conferenceRequest, - eRequestMessage_multilinkRequest, - eRequestMessage_logicalChannelRateRequest, - } choice; - union { - OpenLogicalChannel openLogicalChannel; - }; -} RequestMessage; - -typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ - enum { - eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, - eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, - } choice; - union { - H2250LogicalChannelParameters h2250LogicalChannelParameters; - }; -} OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters; - -typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */ - enum { - eOpenLogicalChannelAck_reverseLogicalChannelParameters_portNumber - = (1 << 31), - eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters - = (1 << 30), - eOpenLogicalChannelAck_reverseLogicalChannelParameters_replacementFor - = (1 << 29), - } options; - OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters - multiplexParameters; -} OpenLogicalChannelAck_reverseLogicalChannelParameters; - -typedef struct H2250LogicalChannelAckParameters { /* SEQUENCE */ - enum { - eH2250LogicalChannelAckParameters_nonStandard = (1 << 31), - eH2250LogicalChannelAckParameters_sessionID = (1 << 30), - eH2250LogicalChannelAckParameters_mediaChannel = (1 << 29), - eH2250LogicalChannelAckParameters_mediaControlChannel = - (1 << 28), - eH2250LogicalChannelAckParameters_dynamicRTPPayloadType = - (1 << 27), - eH2250LogicalChannelAckParameters_flowControlToZero = - (1 << 26), - eH2250LogicalChannelAckParameters_portNumber = (1 << 25), - } options; - H245_TransportAddress mediaChannel; - H245_TransportAddress mediaControlChannel; -} H2250LogicalChannelAckParameters; - -typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters { /* CHOICE */ - enum { - eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters, - } choice; - union { - H2250LogicalChannelAckParameters - h2250LogicalChannelAckParameters; - }; -} OpenLogicalChannelAck_forwardMultiplexAckParameters; - -typedef struct OpenLogicalChannelAck { /* SEQUENCE */ - enum { - eOpenLogicalChannelAck_reverseLogicalChannelParameters = - (1 << 31), - eOpenLogicalChannelAck_separateStack = (1 << 30), - eOpenLogicalChannelAck_forwardMultiplexAckParameters = - (1 << 29), - eOpenLogicalChannelAck_encryptionSync = (1 << 28), - } options; - OpenLogicalChannelAck_reverseLogicalChannelParameters - reverseLogicalChannelParameters; - OpenLogicalChannelAck_forwardMultiplexAckParameters - forwardMultiplexAckParameters; -} OpenLogicalChannelAck; - -typedef struct ResponseMessage { /* CHOICE */ - enum { - eResponseMessage_nonStandard, - eResponseMessage_masterSlaveDeterminationAck, - eResponseMessage_masterSlaveDeterminationReject, - eResponseMessage_terminalCapabilitySetAck, - eResponseMessage_terminalCapabilitySetReject, - eResponseMessage_openLogicalChannelAck, - eResponseMessage_openLogicalChannelReject, - eResponseMessage_closeLogicalChannelAck, - eResponseMessage_requestChannelCloseAck, - eResponseMessage_requestChannelCloseReject, - eResponseMessage_multiplexEntrySendAck, - eResponseMessage_multiplexEntrySendReject, - eResponseMessage_requestMultiplexEntryAck, - eResponseMessage_requestMultiplexEntryReject, - eResponseMessage_requestModeAck, - eResponseMessage_requestModeReject, - eResponseMessage_roundTripDelayResponse, - eResponseMessage_maintenanceLoopAck, - eResponseMessage_maintenanceLoopReject, - eResponseMessage_communicationModeResponse, - eResponseMessage_conferenceResponse, - eResponseMessage_multilinkResponse, - eResponseMessage_logicalChannelRateAcknowledge, - eResponseMessage_logicalChannelRateReject, - } choice; - union { - OpenLogicalChannelAck openLogicalChannelAck; - }; -} ResponseMessage; - -typedef struct MultimediaSystemControlMessage { /* CHOICE */ - enum { - eMultimediaSystemControlMessage_request, - eMultimediaSystemControlMessage_response, - eMultimediaSystemControlMessage_command, - eMultimediaSystemControlMessage_indication, - } choice; - union { - RequestMessage request; - ResponseMessage response; - }; -} MultimediaSystemControlMessage; - -typedef struct H323_UU_PDU_h245Control { /* SEQUENCE OF */ - int count; - MultimediaSystemControlMessage item[4]; -} H323_UU_PDU_h245Control; - -typedef struct H323_UU_PDU { /* SEQUENCE */ - enum { - eH323_UU_PDU_nonStandardData = (1 << 31), - eH323_UU_PDU_h4501SupplementaryService = (1 << 30), - eH323_UU_PDU_h245Tunneling = (1 << 29), - eH323_UU_PDU_h245Control = (1 << 28), - eH323_UU_PDU_nonStandardControl = (1 << 27), - eH323_UU_PDU_callLinkage = (1 << 26), - eH323_UU_PDU_tunnelledSignallingMessage = (1 << 25), - eH323_UU_PDU_provisionalRespToH245Tunneling = (1 << 24), - eH323_UU_PDU_stimulusControl = (1 << 23), - eH323_UU_PDU_genericData = (1 << 22), - } options; - H323_UU_PDU_h323_message_body h323_message_body; - H323_UU_PDU_h245Control h245Control; -} H323_UU_PDU; - -typedef struct H323_UserInformation { /* SEQUENCE */ - enum { - eH323_UserInformation_user_data = (1 << 31), - } options; - H323_UU_PDU h323_uu_pdu; -} H323_UserInformation; - -typedef struct GatekeeperRequest { /* SEQUENCE */ - enum { - eGatekeeperRequest_nonStandardData = (1 << 31), - eGatekeeperRequest_gatekeeperIdentifier = (1 << 30), - eGatekeeperRequest_callServices = (1 << 29), - eGatekeeperRequest_endpointAlias = (1 << 28), - eGatekeeperRequest_alternateEndpoints = (1 << 27), - eGatekeeperRequest_tokens = (1 << 26), - eGatekeeperRequest_cryptoTokens = (1 << 25), - eGatekeeperRequest_authenticationCapability = (1 << 24), - eGatekeeperRequest_algorithmOIDs = (1 << 23), - eGatekeeperRequest_integrity = (1 << 22), - eGatekeeperRequest_integrityCheckValue = (1 << 21), - eGatekeeperRequest_supportsAltGK = (1 << 20), - eGatekeeperRequest_featureSet = (1 << 19), - eGatekeeperRequest_genericData = (1 << 18), - } options; - TransportAddress rasAddress; -} GatekeeperRequest; - -typedef struct GatekeeperConfirm { /* SEQUENCE */ - enum { - eGatekeeperConfirm_nonStandardData = (1 << 31), - eGatekeeperConfirm_gatekeeperIdentifier = (1 << 30), - eGatekeeperConfirm_alternateGatekeeper = (1 << 29), - eGatekeeperConfirm_authenticationMode = (1 << 28), - eGatekeeperConfirm_tokens = (1 << 27), - eGatekeeperConfirm_cryptoTokens = (1 << 26), - eGatekeeperConfirm_algorithmOID = (1 << 25), - eGatekeeperConfirm_integrity = (1 << 24), - eGatekeeperConfirm_integrityCheckValue = (1 << 23), - eGatekeeperConfirm_featureSet = (1 << 22), - eGatekeeperConfirm_genericData = (1 << 21), - } options; - TransportAddress rasAddress; -} GatekeeperConfirm; - -typedef struct RegistrationRequest_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} RegistrationRequest_callSignalAddress; - -typedef struct RegistrationRequest_rasAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} RegistrationRequest_rasAddress; - -typedef struct RegistrationRequest { /* SEQUENCE */ - enum { - eRegistrationRequest_nonStandardData = (1 << 31), - eRegistrationRequest_terminalAlias = (1 << 30), - eRegistrationRequest_gatekeeperIdentifier = (1 << 29), - eRegistrationRequest_alternateEndpoints = (1 << 28), - eRegistrationRequest_timeToLive = (1 << 27), - eRegistrationRequest_tokens = (1 << 26), - eRegistrationRequest_cryptoTokens = (1 << 25), - eRegistrationRequest_integrityCheckValue = (1 << 24), - eRegistrationRequest_keepAlive = (1 << 23), - eRegistrationRequest_endpointIdentifier = (1 << 22), - eRegistrationRequest_willSupplyUUIEs = (1 << 21), - eRegistrationRequest_maintainConnection = (1 << 20), - eRegistrationRequest_alternateTransportAddresses = (1 << 19), - eRegistrationRequest_additiveRegistration = (1 << 18), - eRegistrationRequest_terminalAliasPattern = (1 << 17), - eRegistrationRequest_supportsAltGK = (1 << 16), - eRegistrationRequest_usageReportingCapability = (1 << 15), - eRegistrationRequest_multipleCalls = (1 << 14), - eRegistrationRequest_supportedH248Packages = (1 << 13), - eRegistrationRequest_callCreditCapability = (1 << 12), - eRegistrationRequest_capacityReportingCapability = (1 << 11), - eRegistrationRequest_capacity = (1 << 10), - eRegistrationRequest_featureSet = (1 << 9), - eRegistrationRequest_genericData = (1 << 8), - } options; - RegistrationRequest_callSignalAddress callSignalAddress; - RegistrationRequest_rasAddress rasAddress; - unsigned timeToLive; -} RegistrationRequest; - -typedef struct RegistrationConfirm_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} RegistrationConfirm_callSignalAddress; - -typedef struct RegistrationConfirm { /* SEQUENCE */ - enum { - eRegistrationConfirm_nonStandardData = (1 << 31), - eRegistrationConfirm_terminalAlias = (1 << 30), - eRegistrationConfirm_gatekeeperIdentifier = (1 << 29), - eRegistrationConfirm_alternateGatekeeper = (1 << 28), - eRegistrationConfirm_timeToLive = (1 << 27), - eRegistrationConfirm_tokens = (1 << 26), - eRegistrationConfirm_cryptoTokens = (1 << 25), - eRegistrationConfirm_integrityCheckValue = (1 << 24), - eRegistrationConfirm_willRespondToIRR = (1 << 23), - eRegistrationConfirm_preGrantedARQ = (1 << 22), - eRegistrationConfirm_maintainConnection = (1 << 21), - eRegistrationConfirm_serviceControl = (1 << 20), - eRegistrationConfirm_supportsAdditiveRegistration = (1 << 19), - eRegistrationConfirm_terminalAliasPattern = (1 << 18), - eRegistrationConfirm_supportedPrefixes = (1 << 17), - eRegistrationConfirm_usageSpec = (1 << 16), - eRegistrationConfirm_featureServerAlias = (1 << 15), - eRegistrationConfirm_capacityReportingSpec = (1 << 14), - eRegistrationConfirm_featureSet = (1 << 13), - eRegistrationConfirm_genericData = (1 << 12), - } options; - RegistrationConfirm_callSignalAddress callSignalAddress; - unsigned timeToLive; -} RegistrationConfirm; - -typedef struct UnregistrationRequest_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} UnregistrationRequest_callSignalAddress; - -typedef struct UnregistrationRequest { /* SEQUENCE */ - enum { - eUnregistrationRequest_endpointAlias = (1 << 31), - eUnregistrationRequest_nonStandardData = (1 << 30), - eUnregistrationRequest_endpointIdentifier = (1 << 29), - eUnregistrationRequest_alternateEndpoints = (1 << 28), - eUnregistrationRequest_gatekeeperIdentifier = (1 << 27), - eUnregistrationRequest_tokens = (1 << 26), - eUnregistrationRequest_cryptoTokens = (1 << 25), - eUnregistrationRequest_integrityCheckValue = (1 << 24), - eUnregistrationRequest_reason = (1 << 23), - eUnregistrationRequest_endpointAliasPattern = (1 << 22), - eUnregistrationRequest_supportedPrefixes = (1 << 21), - eUnregistrationRequest_alternateGatekeeper = (1 << 20), - eUnregistrationRequest_genericData = (1 << 19), - } options; - UnregistrationRequest_callSignalAddress callSignalAddress; -} UnregistrationRequest; - -typedef struct AdmissionRequest { /* SEQUENCE */ - enum { - eAdmissionRequest_callModel = (1 << 31), - eAdmissionRequest_destinationInfo = (1 << 30), - eAdmissionRequest_destCallSignalAddress = (1 << 29), - eAdmissionRequest_destExtraCallInfo = (1 << 28), - eAdmissionRequest_srcCallSignalAddress = (1 << 27), - eAdmissionRequest_nonStandardData = (1 << 26), - eAdmissionRequest_callServices = (1 << 25), - eAdmissionRequest_canMapAlias = (1 << 24), - eAdmissionRequest_callIdentifier = (1 << 23), - eAdmissionRequest_srcAlternatives = (1 << 22), - eAdmissionRequest_destAlternatives = (1 << 21), - eAdmissionRequest_gatekeeperIdentifier = (1 << 20), - eAdmissionRequest_tokens = (1 << 19), - eAdmissionRequest_cryptoTokens = (1 << 18), - eAdmissionRequest_integrityCheckValue = (1 << 17), - eAdmissionRequest_transportQOS = (1 << 16), - eAdmissionRequest_willSupplyUUIEs = (1 << 15), - eAdmissionRequest_callLinkage = (1 << 14), - eAdmissionRequest_gatewayDataRate = (1 << 13), - eAdmissionRequest_capacity = (1 << 12), - eAdmissionRequest_circuitInfo = (1 << 11), - eAdmissionRequest_desiredProtocols = (1 << 10), - eAdmissionRequest_desiredTunnelledProtocol = (1 << 9), - eAdmissionRequest_featureSet = (1 << 8), - eAdmissionRequest_genericData = (1 << 7), - } options; - TransportAddress destCallSignalAddress; - TransportAddress srcCallSignalAddress; -} AdmissionRequest; - -typedef struct AdmissionConfirm { /* SEQUENCE */ - enum { - eAdmissionConfirm_irrFrequency = (1 << 31), - eAdmissionConfirm_nonStandardData = (1 << 30), - eAdmissionConfirm_destinationInfo = (1 << 29), - eAdmissionConfirm_destExtraCallInfo = (1 << 28), - eAdmissionConfirm_destinationType = (1 << 27), - eAdmissionConfirm_remoteExtensionAddress = (1 << 26), - eAdmissionConfirm_alternateEndpoints = (1 << 25), - eAdmissionConfirm_tokens = (1 << 24), - eAdmissionConfirm_cryptoTokens = (1 << 23), - eAdmissionConfirm_integrityCheckValue = (1 << 22), - eAdmissionConfirm_transportQOS = (1 << 21), - eAdmissionConfirm_willRespondToIRR = (1 << 20), - eAdmissionConfirm_uuiesRequested = (1 << 19), - eAdmissionConfirm_language = (1 << 18), - eAdmissionConfirm_alternateTransportAddresses = (1 << 17), - eAdmissionConfirm_useSpecifiedTransport = (1 << 16), - eAdmissionConfirm_circuitInfo = (1 << 15), - eAdmissionConfirm_usageSpec = (1 << 14), - eAdmissionConfirm_supportedProtocols = (1 << 13), - eAdmissionConfirm_serviceControl = (1 << 12), - eAdmissionConfirm_multipleCalls = (1 << 11), - eAdmissionConfirm_featureSet = (1 << 10), - eAdmissionConfirm_genericData = (1 << 9), - } options; - TransportAddress destCallSignalAddress; -} AdmissionConfirm; - -typedef struct LocationRequest { /* SEQUENCE */ - enum { - eLocationRequest_endpointIdentifier = (1 << 31), - eLocationRequest_nonStandardData = (1 << 30), - eLocationRequest_sourceInfo = (1 << 29), - eLocationRequest_canMapAlias = (1 << 28), - eLocationRequest_gatekeeperIdentifier = (1 << 27), - eLocationRequest_tokens = (1 << 26), - eLocationRequest_cryptoTokens = (1 << 25), - eLocationRequest_integrityCheckValue = (1 << 24), - eLocationRequest_desiredProtocols = (1 << 23), - eLocationRequest_desiredTunnelledProtocol = (1 << 22), - eLocationRequest_featureSet = (1 << 21), - eLocationRequest_genericData = (1 << 20), - eLocationRequest_hopCount = (1 << 19), - eLocationRequest_circuitInfo = (1 << 18), - } options; - TransportAddress replyAddress; -} LocationRequest; - -typedef struct LocationConfirm { /* SEQUENCE */ - enum { - eLocationConfirm_nonStandardData = (1 << 31), - eLocationConfirm_destinationInfo = (1 << 30), - eLocationConfirm_destExtraCallInfo = (1 << 29), - eLocationConfirm_destinationType = (1 << 28), - eLocationConfirm_remoteExtensionAddress = (1 << 27), - eLocationConfirm_alternateEndpoints = (1 << 26), - eLocationConfirm_tokens = (1 << 25), - eLocationConfirm_cryptoTokens = (1 << 24), - eLocationConfirm_integrityCheckValue = (1 << 23), - eLocationConfirm_alternateTransportAddresses = (1 << 22), - eLocationConfirm_supportedProtocols = (1 << 21), - eLocationConfirm_multipleCalls = (1 << 20), - eLocationConfirm_featureSet = (1 << 19), - eLocationConfirm_genericData = (1 << 18), - eLocationConfirm_circuitInfo = (1 << 17), - eLocationConfirm_serviceControl = (1 << 16), - } options; - TransportAddress callSignalAddress; - TransportAddress rasAddress; -} LocationConfirm; - -typedef struct InfoRequestResponse_callSignalAddress { /* SEQUENCE OF */ - int count; - TransportAddress item[10]; -} InfoRequestResponse_callSignalAddress; - -typedef struct InfoRequestResponse { /* SEQUENCE */ - enum { - eInfoRequestResponse_nonStandardData = (1 << 31), - eInfoRequestResponse_endpointAlias = (1 << 30), - eInfoRequestResponse_perCallInfo = (1 << 29), - eInfoRequestResponse_tokens = (1 << 28), - eInfoRequestResponse_cryptoTokens = (1 << 27), - eInfoRequestResponse_integrityCheckValue = (1 << 26), - eInfoRequestResponse_needResponse = (1 << 25), - eInfoRequestResponse_capacity = (1 << 24), - eInfoRequestResponse_irrStatus = (1 << 23), - eInfoRequestResponse_unsolicited = (1 << 22), - eInfoRequestResponse_genericData = (1 << 21), - } options; - TransportAddress rasAddress; - InfoRequestResponse_callSignalAddress callSignalAddress; -} InfoRequestResponse; - -typedef struct RasMessage { /* CHOICE */ - enum { - eRasMessage_gatekeeperRequest, - eRasMessage_gatekeeperConfirm, - eRasMessage_gatekeeperReject, - eRasMessage_registrationRequest, - eRasMessage_registrationConfirm, - eRasMessage_registrationReject, - eRasMessage_unregistrationRequest, - eRasMessage_unregistrationConfirm, - eRasMessage_unregistrationReject, - eRasMessage_admissionRequest, - eRasMessage_admissionConfirm, - eRasMessage_admissionReject, - eRasMessage_bandwidthRequest, - eRasMessage_bandwidthConfirm, - eRasMessage_bandwidthReject, - eRasMessage_disengageRequest, - eRasMessage_disengageConfirm, - eRasMessage_disengageReject, - eRasMessage_locationRequest, - eRasMessage_locationConfirm, - eRasMessage_locationReject, - eRasMessage_infoRequest, - eRasMessage_infoRequestResponse, - eRasMessage_nonStandardMessage, - eRasMessage_unknownMessageResponse, - eRasMessage_requestInProgress, - eRasMessage_resourcesAvailableIndicate, - eRasMessage_resourcesAvailableConfirm, - eRasMessage_infoRequestAck, - eRasMessage_infoRequestNak, - eRasMessage_serviceControlIndication, - eRasMessage_serviceControlResponse, - } choice; - union { - GatekeeperRequest gatekeeperRequest; - GatekeeperConfirm gatekeeperConfirm; - RegistrationRequest registrationRequest; - RegistrationConfirm registrationConfirm; - UnregistrationRequest unregistrationRequest; - AdmissionRequest admissionRequest; - AdmissionConfirm admissionConfirm; - LocationRequest locationRequest; - LocationConfirm locationConfirm; - InfoRequestResponse infoRequestResponse; - }; -} RasMessage; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 83694cfdfa8f..1646076933b1 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -41,11 +41,13 @@ union nf_conntrack_expect_proto { /* Add protocol helper include file here */ #include +#include /* per conntrack: application helper private data */ union nf_conntrack_help { /* insert conntrack helper private data (master) here */ struct nf_ct_ftp_master ct_ftp_info; + struct nf_ct_h323_master ct_h323_info; }; #include diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 54a3d038beaa..cef3136e22a3 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -41,6 +41,7 @@ struct nf_conntrack_expect unsigned int flags; #ifdef CONFIG_NF_NAT_NEEDED + __be32 saved_ip; /* This is the original per-proto part, used to map the * expected connection the way the recipient expects. */ union nf_conntrack_man_proto saved_proto; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 6993ec53dc06..e14156d1122e 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -529,6 +529,11 @@ config IP_NF_NAT_H323 default IP_NF_NAT if IP_NF_H323=y default m if IP_NF_H323=m +config NF_NAT_H323 + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_H323 + config IP_NF_NAT_SIP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 8893249bbe98..bdaba4700e3b 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -15,7 +15,7 @@ endif ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o -ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ip_conntrack_helper_h323_asn1.o +ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o ip_nat_h323-objs := ip_nat_helper_h323.o # connection tracking @@ -52,6 +52,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o # NAT helpers (nf_conntrack) obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o +obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c deleted file mode 100644 index 26dfecadb335..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ /dev/null @@ -1,874 +0,0 @@ -/**************************************************************************** - * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 - * conntrack/NAT module. - * - * Copyright (c) 2006 by Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - * - * See ip_conntrack_helper_h323_asn1.h for details. - * - ****************************************************************************/ - -#ifdef __KERNEL__ -#include -#else -#include -#endif -#include - -/* Trace Flag */ -#ifndef H323_TRACE -#define H323_TRACE 0 -#endif - -#if H323_TRACE -#define TAB_SIZE 4 -#define IFTHEN(cond, act) if(cond){act;} -#ifdef __KERNEL__ -#define PRINT printk -#else -#define PRINT printf -#endif -#define FNAME(name) name, -#else -#define IFTHEN(cond, act) -#define PRINT(fmt, args...) -#define FNAME(name) -#endif - -/* ASN.1 Types */ -#define NUL 0 -#define BOOL 1 -#define OID 2 -#define INT 3 -#define ENUM 4 -#define BITSTR 5 -#define NUMSTR 6 -#define NUMDGT 6 -#define TBCDSTR 6 -#define OCTSTR 7 -#define PRTSTR 7 -#define IA5STR 7 -#define GENSTR 7 -#define BMPSTR 8 -#define SEQ 9 -#define SET 9 -#define SEQOF 10 -#define SETOF 10 -#define CHOICE 11 - -/* Constraint Types */ -#define FIXD 0 -/* #define BITS 1-8 */ -#define BYTE 9 -#define WORD 10 -#define CONS 11 -#define SEMI 12 -#define UNCO 13 - -/* ASN.1 Type Attributes */ -#define SKIP 0 -#define STOP 1 -#define DECODE 2 -#define EXT 4 -#define OPEN 8 -#define OPT 16 - - -/* ASN.1 Field Structure */ -typedef struct field_t { -#if H323_TRACE - char *name; -#endif - unsigned char type; - unsigned char sz; - unsigned char lb; - unsigned char ub; - unsigned short attr; - unsigned short offset; - struct field_t *fields; -} field_t; - -/* Bit Stream */ -typedef struct { - unsigned char *buf; - unsigned char *beg; - unsigned char *end; - unsigned char *cur; - unsigned bit; -} bitstr_t; - -/* Tool Functions */ -#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;} -#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;} -#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;} -#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND) -static unsigned get_len(bitstr_t * bs); -static unsigned get_bit(bitstr_t * bs); -static unsigned get_bits(bitstr_t * bs, unsigned b); -static unsigned get_bitmap(bitstr_t * bs, unsigned b); -static unsigned get_uint(bitstr_t * bs, int b); - -/* Decoder Functions */ -static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_int(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level); -static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level); - -/* Decoder Functions Vector */ -typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int); -static decoder_t Decoders[] = { - decode_nul, - decode_bool, - decode_oid, - decode_int, - decode_enum, - decode_bitstr, - decode_numstr, - decode_octstr, - decode_bmpstr, - decode_seq, - decode_seqof, - decode_choice, -}; - -/**************************************************************************** - * H.323 Types - ****************************************************************************/ -#include "ip_conntrack_helper_h323_types.c" - -/**************************************************************************** - * Functions - ****************************************************************************/ -/* Assume bs is aligned && v < 16384 */ -unsigned get_len(bitstr_t * bs) -{ - unsigned v; - - v = *bs->cur++; - - if (v & 0x80) { - v &= 0x3f; - v <<= 8; - v += *bs->cur++; - } - - return v; -} - -/****************************************************************************/ -unsigned get_bit(bitstr_t * bs) -{ - unsigned b = (*bs->cur) & (0x80 >> bs->bit); - - INC_BIT(bs); - - return b; -} - -/****************************************************************************/ -/* Assume b <= 8 */ -unsigned get_bits(bitstr_t * bs, unsigned b) -{ - unsigned v, l; - - v = (*bs->cur) & (0xffU >> bs->bit); - l = b + bs->bit; - - if (l < 8) { - v >>= 8 - l; - bs->bit = l; - } else if (l == 8) { - bs->cur++; - bs->bit = 0; - } else { /* l > 8 */ - - v <<= 8; - v += *(++bs->cur); - v >>= 16 - l; - bs->bit = l - 8; - } - - return v; -} - -/****************************************************************************/ -/* Assume b <= 32 */ -unsigned get_bitmap(bitstr_t * bs, unsigned b) -{ - unsigned v, l, shift, bytes; - - if (!b) - return 0; - - l = bs->bit + b; - - if (l < 8) { - v = (unsigned) (*bs->cur) << (bs->bit + 24); - bs->bit = l; - } else if (l == 8) { - v = (unsigned) (*bs->cur++) << (bs->bit + 24); - bs->bit = 0; - } else { - for (bytes = l >> 3, shift = 24, v = 0; bytes; - bytes--, shift -= 8) - v |= (unsigned) (*bs->cur++) << shift; - - if (l < 32) { - v |= (unsigned) (*bs->cur) << shift; - v <<= bs->bit; - } else if (l > 32) { - v <<= bs->bit; - v |= (*bs->cur) >> (8 - bs->bit); - } - - bs->bit = l & 0x7; - } - - v &= 0xffffffff << (32 - b); - - return v; -} - -/**************************************************************************** - * Assume bs is aligned and sizeof(unsigned int) == 4 - ****************************************************************************/ -unsigned get_uint(bitstr_t * bs, int b) -{ - unsigned v = 0; - - switch (b) { - case 4: - v |= *bs->cur++; - v <<= 8; - case 3: - v |= *bs->cur++; - v <<= 8; - case 2: - v |= *bs->cur++; - v <<= 8; - case 1: - v |= *bs->cur++; - break; - } - return v; -} - -/****************************************************************************/ -int decode_nul(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bool(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - INC_BIT(bs); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_oid(bitstr_t * bs, field_t * f, char *base, int level) -{ - int len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = *bs->cur++; - bs->cur += len; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_int(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - bs->cur++; - break; - case WORD: /* 257 <= Range <= 64K */ - BYTE_ALIGN(bs); - bs->cur += 2; - break; - case CONS: /* 64K < Range < 4G */ - len = get_bits(bs, 2) + 1; - BYTE_ALIGN(bs); - if (base && (f->attr & DECODE)) { /* timeToLive */ - unsigned v = get_uint(bs, len) + f->lb; - PRINT(" = %u", v); - *((unsigned *) (base + f->offset)) = v; - } - bs->cur += len; - break; - case UNCO: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - len = get_len(bs); - bs->cur += len; - break; - default: /* 2 <= Range <= 255 */ - INC_BITS(bs, f->sz); - break; - } - - PRINT("\n"); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_enum(bitstr_t * bs, field_t * f, char *base, int level) -{ - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - if ((f->attr & EXT) && get_bit(bs)) { - INC_BITS(bs, 7); - } else { - INC_BITS(bs, f->sz); - } - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - BYTE_ALIGN(bs); - switch (f->sz) { - case FIXD: /* fixed length > 16 */ - len = f->lb; - break; - case WORD: /* 2-byte length */ - CHECK_BOUND(bs, 2); - len = (*bs->cur++) << 8; - len += (*bs->cur++) + f->lb; - break; - case SEMI: - CHECK_BOUND(bs, 2); - len = get_len(bs); - break; - default: - len = 0; - break; - } - - bs->cur += len >> 3; - bs->bit = len & 7; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - - BYTE_ALIGN(bs); - INC_BITS(bs, (len << 2)); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case FIXD: /* Range == 1 */ - if (f->lb > 2) { - BYTE_ALIGN(bs); - if (base && (f->attr & DECODE)) { - /* The IP Address */ - IFTHEN(f->lb == 4, - PRINT(" = %d.%d.%d.%d:%d", - bs->cur[0], bs->cur[1], - bs->cur[2], bs->cur[3], - bs->cur[4] * 256 + bs->cur[5])); - *((unsigned *) (base + f->offset)) = - bs->cur - bs->buf; - } - } - len = f->lb; - break; - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = (*bs->cur++) + f->lb; - break; - case SEMI: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - len = get_len(bs) + f->lb; - break; - default: /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - BYTE_ALIGN(bs); - break; - } - - bs->cur += len; - - PRINT("\n"); - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned len; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - switch (f->sz) { - case BYTE: /* Range == 256 */ - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - len = (*bs->cur++) + f->lb; - break; - default: /* 2 <= Range <= 255 */ - len = get_bits(bs, f->sz) + f->lb; - BYTE_ALIGN(bs); - break; - } - - bs->cur += len << 1; - - CHECK_BOUND(bs, 0); - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Extensible? */ - ext = (f->attr & EXT) ? get_bit(bs) : 0; - - /* Get fields bitmap */ - bmp = get_bitmap(bs, f->sz); - if (base) - *(unsigned *) base = bmp; - - /* Decode the root components */ - for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) { - if (son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - return H323_ERROR_STOP; - } - - if (son->attr & OPT) { /* Optional component */ - if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */ - continue; - } - - /* Decode */ - if (son->attr & OPEN) { /* Open field */ - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, - " ", son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - /* Decode */ - if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - } - - /* No extension? */ - if (!ext) - return H323_ERROR_NONE; - - /* Get the extension bitmap */ - bmp2_len = get_bits(bs, 7) + 1; - CHECK_BOUND(bs, (bmp2_len + 7) >> 3); - bmp2 = get_bitmap(bs, bmp2_len); - bmp |= bmp2 >> f->sz; - if (base) - *(unsigned *) base = bmp; - BYTE_ALIGN(bs); - - /* Decode the extension components */ - for (opt = 0; opt < bmp2_len; opt++, i++, son++) { - if (i < f->ub && son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - return H323_ERROR_STOP; - } - - if (!((0x80000000 >> opt) & bmp2)) /* Not present */ - continue; - - /* Check Range */ - if (i >= f->ub) { /* Newer Version? */ - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - bs->cur += len; - continue; - } - - CHECK_BOUND(bs, 2); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned count, effective_count = 0, i, len = 0; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Decode item count */ - switch (f->sz) { - case BYTE: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 1); - count = *bs->cur++; - break; - case WORD: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - count = *bs->cur++; - count <<= 8; - count = *bs->cur++; - break; - case SEMI: - BYTE_ALIGN(bs); - CHECK_BOUND(bs, 2); - count = get_len(bs); - break; - default: - count = get_bits(bs, f->sz); - break; - } - count += f->lb; - - /* Write Count */ - if (base) { - effective_count = count > f->ub ? f->ub : count; - *(unsigned *) base = effective_count; - base += sizeof(unsigned); - } - - /* Decode nested field */ - son = f->fields; - if (base) - base -= son->offset; - for (i = 0; i < count; i++) { - if (son->attr & OPEN) { - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, - " ", son->name); - bs->cur += len; - continue; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, - i < - effective_count ? - base : NULL, - level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else - if ((err = (Decoders[son->type]) (bs, son, - i < - effective_count ? - base : NULL, - level + 1)) < - H323_ERROR_NONE) - return err; - - if (base) - base += son->offset; - } - - return H323_ERROR_NONE; -} - - -/****************************************************************************/ -int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) -{ - unsigned type, ext, len = 0; - int err; - field_t *son; - unsigned char *beg = NULL; - - PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); - - /* Decode? */ - base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; - - /* Decode the choice index number */ - if ((f->attr & EXT) && get_bit(bs)) { - ext = 1; - type = get_bits(bs, 7) + f->lb; - } else { - ext = 0; - type = get_bits(bs, f->sz); - } - - /* Write Type */ - if (base) - *(unsigned *) base = type; - - /* Check Range */ - if (type >= f->ub) { /* Newer version? */ - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - bs->cur += len; - return H323_ERROR_NONE; - } - - /* Transfer to son level */ - son = &f->fields[type]; - if (son->attr & STOP) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); - return H323_ERROR_STOP; - } - - if (ext || (son->attr & OPEN)) { - BYTE_ALIGN(bs); - len = get_len(bs); - CHECK_BOUND(bs, len); - if (!base || !(son->attr & DECODE)) { - PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", - son->name); - bs->cur += len; - return H323_ERROR_NONE; - } - beg = bs->cur; - - if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < - H323_ERROR_NONE) - return err; - - bs->cur = beg + len; - bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < - H323_ERROR_NONE) - return err; - - return H323_ERROR_NONE; -} - -/****************************************************************************/ -int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras) -{ - static field_t ras_message = { - FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT, - 0, _RasMessage - }; - bitstr_t bs; - - bs.buf = bs.beg = bs.cur = buf; - bs.end = buf + sz; - bs.bit = 0; - - return decode_choice(&bs, &ras_message, (char *) ras, 0); -} - -/****************************************************************************/ -static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, - size_t sz, H323_UserInformation * uuie) -{ - static field_t h323_userinformation = { - FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT, - 0, _H323_UserInformation - }; - bitstr_t bs; - - bs.buf = buf; - bs.beg = bs.cur = beg; - bs.end = beg + sz; - bs.bit = 0; - - return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); -} - -/****************************************************************************/ -int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, - MultimediaSystemControlMessage * - mscm) -{ - static field_t multimediasystemcontrolmessage = { - FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4, - DECODE | EXT, 0, _MultimediaSystemControlMessage - }; - bitstr_t bs; - - bs.buf = bs.beg = bs.cur = buf; - bs.end = buf + sz; - bs.bit = 0; - - return decode_choice(&bs, &multimediasystemcontrolmessage, - (char *) mscm, 0); -} - -/****************************************************************************/ -int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931) -{ - unsigned char *p = buf; - int len; - - if (!p || sz < 1) - return H323_ERROR_BOUND; - - /* Protocol Discriminator */ - if (*p != 0x08) { - PRINT("Unknown Protocol Discriminator\n"); - return H323_ERROR_RANGE; - } - p++; - sz--; - - /* CallReferenceValue */ - if (sz < 1) - return H323_ERROR_BOUND; - len = *p++; - sz--; - if (sz < len) - return H323_ERROR_BOUND; - p += len; - sz -= len; - - /* Message Type */ - if (sz < 1) - return H323_ERROR_BOUND; - q931->MessageType = *p++; - PRINT("MessageType = %02X\n", q931->MessageType); - if (*p & 0x80) { - p++; - sz--; - } - - /* Decode Information Elements */ - while (sz > 0) { - if (*p == 0x7e) { /* UserUserIE */ - if (sz < 3) - break; - p++; - len = *p++ << 8; - len |= *p++; - sz -= 3; - if (sz < len) - break; - p++; - len--; - return DecodeH323_UserInformation(buf, p, len, - &q931->UUIE); - } - p++; - sz--; - if (sz < 1) - break; - len = *p++; - if (sz < len) - break; - p += len; - sz -= len; - } - - PRINT("Q.931 UUIE not found\n"); - - return H323_ERROR_BOUND; -} diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c deleted file mode 100644 index 4b359618bedd..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c +++ /dev/null @@ -1,1926 +0,0 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 - * - * Copyright (c) 2006 Jing Min Zhao - * - * This source code is licensed under General Public License version 2. - */ - -static field_t _TransportAddress_ipAddress[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE, - offsetof(TransportAddress_ipAddress, ip), NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute_route[] = { /* SEQUENCE OF */ - {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute_routing[] = { /* CHOICE */ - {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ipSourceRoute[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, - _TransportAddress_ipSourceRoute_route}, - {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _TransportAddress_ipSourceRoute_routing}, -}; - -static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ - {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, - {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ - {FNAME("ip") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H221NonStandard[] = { /* SEQUENCE */ - {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _NonStandardIdentifier[] = { /* CHOICE */ - {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0, - _H221NonStandard}, -}; - -static field_t _NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _NonStandardIdentifier}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TransportAddress[] = { /* CHOICE */ - {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE, - offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress}, - {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0, - _TransportAddress_ipSourceRoute}, - {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, - _TransportAddress_ipxAddress}, - {FNAME("ip6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _TransportAddress_ip6Address}, - {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, - _NonStandardParameter}, -}; - -static field_t _AliasAddress[] = { /* CHOICE */ - {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL}, - {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL}, - {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL}, -}; - -static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _VendorIdentifier[] = { /* SEQUENCE */ - {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard}, - {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _GatekeeperInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _H310Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H320Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H321Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H322Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H323Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H324Caps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _VoiceCaps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T120OnlyCaps[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _SupportedProtocols[] = { /* CHOICE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0, - _NonStandardParameter}, - {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps}, - {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps}, - {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps}, - {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps}, - {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps}, - {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps}, - {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps}, - {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps}, - {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL}, -}; - -static field_t _GatewayInfo_protocol[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols}, -}; - -static field_t _GatewayInfo[] = { /* SEQUENCE */ - {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _GatewayInfo_protocol}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _McuInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _TerminalInfo[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, -}; - -static field_t _EndpointType[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0, - _VendorIdentifier}, - {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, - _GatekeeperInfo}, - {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo}, - {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo}, - {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo}, - {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, - 0, NULL}, -}; - -static field_t _Setup_UUIE_destinationAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _Setup_UUIE_destExtraCallInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _Setup_UUIE_destExtraCRV[] = { /* SEQUENCE OF */ - {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Setup_UUIE_conferenceGoal[] = { /* CHOICE */ - {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP, - 0, NULL}, -}; - -static field_t _Q954Details[] = { /* SEQUENCE */ - {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _QseriesOptions[] = { /* SEQUENCE */ - {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details}, -}; - -static field_t _CallType[] = { /* CHOICE */ - {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H245_NonStandardIdentifier_h221NonStandard[] = { /* SEQUENCE */ - {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H245_NonStandardIdentifier[] = { /* CHOICE */ - {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0, - _H245_NonStandardIdentifier_h221NonStandard}, -}; - -static field_t _H245_NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0, - _H245_NonStandardIdentifier}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H261VideoCapability[] = { /* SEQUENCE */ - {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H262VideoCapability[] = { /* SEQUENCE */ - {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H263VideoCapability[] = { /* SEQUENCE */ - {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, - NULL}, - {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _IS11172VideoCapability[] = { /* SEQUENCE */ - {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _VideoCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0, - _H261VideoCapability}, - {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0, - _H262VideoCapability}, - {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0, - _H263VideoCapability}, - {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0, - _IS11172VideoCapability}, - {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _AudioCapability_g7231[] = { /* SEQUENCE */ - {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _IS11172AudioCapability[] = { /* SEQUENCE */ - {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _IS13818AudioCapability[] = { /* SEQUENCE */ - {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _AudioCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231}, - {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0, - _IS11172AudioCapability}, - {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0, - _IS13818AudioCapability}, - {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, - {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, - {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL}, -}; - -static field_t _DataProtocolCapability[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL}, - {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */ - {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _T84Profile[] = { /* CHOICE */ - {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0, - _T84Profile_t84Restricted}, -}; - -static field_t _DataApplicationCapability_application_t84[] = { /* SEQUENCE */ - {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile}, -}; - -static field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */ - {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _DataApplicationCapability_application[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT, - offsetof(DataApplicationCapability_application, t120), - _DataProtocolCapability}, - {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0, - _DataApplicationCapability_application_t84}, - {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0, - _DataApplicationCapability_application_nlpid}, - {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0, - _DataProtocolCapability}, - {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, - {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, - {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _DataApplicationCapability[] = { /* SEQUENCE */ - {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT, - offsetof(DataApplicationCapability, application), - _DataApplicationCapability_application}, - {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _EncryptionMode[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _DataType[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability}, - {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0, - _AudioCapability}, - {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data), - _DataApplicationCapability}, - {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _EncryptionMode}, - {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, - {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, -}; - -static field_t _H222LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = { /* SEQUENCE */ - {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL}, - {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, - _H245_NonStandardParameter}, - {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0, - _H223LogicalChannelParameters_adaptationLayerType_al3}, - {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL}, - {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, - {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL}, -}; - -static field_t _H223LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0, - _H223LogicalChannelParameters_adaptationLayerType}, - {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CRCLength[] = { /* CHOICE */ - {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76HDLCParameters[] = { /* SEQUENCE */ - {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength}, - {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_suspendResume[] = { /* CHOICE */ - {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = { /* CHOICE */ - {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters_mode_eRM[] = { /* SEQUENCE */ - {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode_eRM_recovery}, -}; - -static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */ - {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode_eRM}, - {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V75Parameters[] = { /* SEQUENCE */ - {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0, - _V76HDLCParameters}, - {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _V76LogicalChannelParameters_suspendResume}, - {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _V76LogicalChannelParameters_mode}, - {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters}, -}; - -static field_t _H2250LogicalChannelParameters_nonStandard[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, -}; - -static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE, - offsetof(UnicastAddress_iPAddress, network), NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ - {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, - {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */ - {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress_route[] = { /* SEQUENCE OF */ - {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, -}; - -static field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */ - {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0, - _UnicastAddress_iPSourceRouteAddress_routing}, - {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, - _UnicastAddress_iPSourceRouteAddress_route}, -}; - -static field_t _UnicastAddress[] = { /* CHOICE */ - {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT, - offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, - {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, - _UnicastAddress_iPXAddress}, - {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _UnicastAddress_iP6Address}, - {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, - _UnicastAddress_iPSourceRouteAddress}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress_iPAddress[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _MulticastAddress[] = { /* CHOICE */ - {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0, - _MulticastAddress_iPAddress}, - {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _MulticastAddress_iP6Address}, - {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, - {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, -}; - -static field_t _H245_TransportAddress[] = { /* CHOICE */ - {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT, - offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress}, - {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0, - _MulticastAddress}, -}; - -static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _H2250LogicalChannelParameters_nonStandard}, - {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelParameters, mediaChannel), - _H245_TransportAddress}, - {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelParameters, mediaControlChannel), - _H245_TransportAddress}, - {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT, - 0, NULL}, - {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL}, - {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, - NULL}, - {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, - _H222LogicalChannelParameters}, - {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, - _H223LogicalChannelParameters}, - {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, - _V76LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, - {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT, - offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, - dataType), _DataType}, - {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT, - offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters}, - {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, - 0, NULL}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, - _H223LogicalChannelParameters}, - {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, - _V76LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, -}; - -static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType}, - {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT, - offsetof(OpenLogicalChannel_reverseLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters}, - {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, - 0, NULL}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _NetworkAccessParameters_distribution[] = { /* CHOICE */ - {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Q2931Address_address[] = { /* CHOICE */ - {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL}, - {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, -}; - -static field_t _Q2931Address[] = { /* SEQUENCE */ - {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0, - _Q2931Address_address}, - {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _NetworkAccessParameters_networkAddress[] = { /* CHOICE */ - {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address}, - {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT, - offsetof(NetworkAccessParameters_networkAddress, localAreaAddress), - _H245_TransportAddress}, -}; - -static field_t _NetworkAccessParameters[] = { /* SEQUENCE */ - {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, - _NetworkAccessParameters_distribution}, - {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT, - offsetof(NetworkAccessParameters, networkAddress), - _NetworkAccessParameters_networkAddress}, - {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, -}; - -static field_t _OpenLogicalChannel[] = { /* SEQUENCE */ - {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT, - offsetof(OpenLogicalChannel, forwardLogicalChannelParameters), - _OpenLogicalChannel_forwardLogicalChannelParameters}, - {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4, - DECODE | EXT | OPT, offsetof(OpenLogicalChannel, - reverseLogicalChannelParameters), - _OpenLogicalChannel_reverseLogicalChannelParameters}, - {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, - offsetof(OpenLogicalChannel, separateStack), - _NetworkAccessParameters}, - {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _Setup_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Setup_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, h245Address), _TransportAddress}, - {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_sourceAddress}, - {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destinationAddress}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destExtraCallInfo}, - {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Setup_UUIE_destExtraCRV}, - {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0, - _Setup_UUIE_conferenceGoal}, - {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0, - _QseriesOptions}, - {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, - {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress}, - {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart}, - {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, -}; - -static field_t _CallProceeding_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(CallProceeding_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(CallProceeding_UUIE, fastStart), - _CallProceeding_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Connect_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Connect_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Connect_UUIE, h245Address), _TransportAddress}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Alerting_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Alerting_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Alerting_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Information_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _ReleaseCompleteReason[] = { /* CHOICE */ - {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL}, - {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0, - NULL}, - {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _ReleaseComplete_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0, - _ReleaseCompleteReason}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, -}; - -static field_t _Facility_UUIE_alternativeAliasAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _FacilityReason[] = { /* CHOICE */ - {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Facility_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Facility_UUIE, alternativeAddress), _TransportAddress}, - {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Facility_UUIE_alternativeAliasAddress}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, - {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT, - offsetof(Facility_UUIE, reason), _FacilityReason}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Facility_UUIE, h245Address), _TransportAddress}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - NULL}, -}; - -static field_t _CallIdentifier[] = { /* SEQUENCE */ - {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, -}; - -static field_t _SecurityServiceMode[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, - {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _SecurityCapabilities[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, - {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, - {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0, - _SecurityServiceMode}, -}; - -static field_t _H245Security[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, - {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, - {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, -}; - -static field_t _DHset[] = { /* SEQUENCE */ - {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, - {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _TypedCertificate[] = { /* SEQUENCE */ - {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _H235_NonStandardParameter[] = { /* SEQUENCE */ - {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _ClearToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset}, - {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL}, - {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, - _TypedCertificate}, - {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, - _H235_NonStandardParameter}, - {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL}, - {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _Progress_UUIE_tokens[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, -}; - -static field_t _Params[] = { /* SEQUENCE */ - {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL}, - {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdHash[] = { /* SEQUENCE */ - {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdHash_token}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdHash[] = { /* SEQUENCE */ - {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdHash_token}, -}; - -static field_t _CryptoH323Token_cryptoEPPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoEPCert[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoGKCert[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoH323Token_cryptoFastStart[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoEncryptedToken_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoEncryptedToken_token}, -}; - -static field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */ - {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoSignedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("token") SEQ, 0, 4, 4, SKIP, 0, - _CryptoToken_cryptoSignedToken_token}, -}; - -static field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken_cryptoHashedToken[] = { /* SEQUENCE */ - {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, - {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoHashedToken_token}, -}; - -static field_t _CryptoToken_cryptoPwdEncr[] = { /* SEQUENCE */ - {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, - {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _CryptoToken[] = { /* CHOICE */ - {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0, - _CryptoToken_cryptoEncryptedToken}, - {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0, - _CryptoToken_cryptoSignedToken}, - {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoHashedToken}, - {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoToken_cryptoPwdEncr}, -}; - -static field_t _CryptoH323Token[] = { /* CHOICE */ - {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdHash}, - {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdHash}, - {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoEPPwdEncr}, - {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0, - _CryptoH323Token_cryptoGKPwdEncr}, - {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoEPCert}, - {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoGKCert}, - {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0, - _CryptoH323Token_cryptoFastStart}, - {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0, - _CryptoToken}, -}; - -static field_t _Progress_UUIE_cryptoTokens[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token}, -}; - -static field_t _Progress_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - -static field_t _Progress_UUIE[] = { /* SEQUENCE */ - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, - _EndpointType}, - {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(Progress_UUIE, h245Address), _TransportAddress}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, - _CallIdentifier}, - {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, - _H245Security}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Progress_UUIE_tokens}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _Progress_UUIE_cryptoTokens}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ - {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE}, - {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, callProceeding), - _CallProceeding_UUIE}, - {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, - {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, - {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, information), - _Information_UUIE}, - {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, - _ReleaseComplete_UUIE}, - {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE}, - {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE}, - {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, - {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, -}; - -static field_t _RequestMessage[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT, - offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel}, - {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL}, - {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL}, - {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL}, - {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, - {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0, - NULL}, -}; - -static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ - {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, - _H222LogicalChannelParameters}, - {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, - offsetof - (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters, - h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, -}; - -static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = { /* SEQUENCE */ - {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT, - offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters, - multiplexParameters), - _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters}, - {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _H2250LogicalChannelAckParameters_nonStandard[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, -}; - -static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */ - {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _H2250LogicalChannelAckParameters_nonStandard}, - {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelAckParameters, mediaChannel), - _H245_TransportAddress}, - {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, - offsetof(H2250LogicalChannelAckParameters, mediaControlChannel), - _H245_TransportAddress}, - {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL}, - {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, -}; - -static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */ - {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT, - offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters, - h2250LogicalChannelAckParameters), - _H2250LogicalChannelAckParameters}, -}; - -static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ - {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4, - DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, - reverseLogicalChannelParameters), - _OpenLogicalChannelAck_reverseLogicalChannelParameters}, - {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, - {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, - DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, - forwardMultiplexAckParameters), - _OpenLogicalChannelAck_forwardMultiplexAckParameters}, - {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _ResponseMessage[] = { /* CHOICE */ - {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT, - offsetof(ResponseMessage, openLogicalChannelAck), - _OpenLogicalChannelAck}, - {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0, - NULL}, - {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, - {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0, - NULL}, - {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, - {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0, - NULL}, - {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL}, -}; - -static field_t _MultimediaSystemControlMessage[] = { /* CHOICE */ - {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT, - offsetof(MultimediaSystemControlMessage, request), _RequestMessage}, - {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT, - offsetof(MultimediaSystemControlMessage, response), - _ResponseMessage}, - {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL}, - {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL}, -}; - -static field_t _H323_UU_PDU_h245Control[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT, - sizeof(MultimediaSystemControlMessage), - _MultimediaSystemControlMessage} - , -}; - -static field_t _H323_UU_PDU[] = { /* SEQUENCE */ - {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT, - offsetof(H323_UU_PDU, h323_message_body), - _H323_UU_PDU_h323_message_body}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - NULL}, - {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT, - offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control}, - {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT, - 0, NULL}, - {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT, - 0, NULL}, - {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _H323_UserInformation[] = { /* SEQUENCE */ - {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT, - offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU}, - {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _GatekeeperRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(GatekeeperRequest, rasAddress), _TransportAddress}, - {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _GatekeeperConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(GatekeeperConfirm, rasAddress), _TransportAddress}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0, - NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RegistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationRequest_rasAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationRequest_terminalAlias[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _RegistrationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationRequest, callSignalAddress), - _RegistrationRequest_callSignalAddress}, - {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationRequest, rasAddress), - _RegistrationRequest_rasAddress}, - {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _RegistrationRequest_terminalAlias}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0, - _VendorIdentifier}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, - offsetof(RegistrationRequest, timeToLive), NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, - NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RegistrationConfirm_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _RegistrationConfirm_terminalAlias[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _RegistrationConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(RegistrationConfirm, callSignalAddress), - _RegistrationConfirm_callSignalAddress}, - {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _RegistrationConfirm_terminalAlias}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, - offsetof(RegistrationConfirm, timeToLive), NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0, - NULL}, - {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _UnregistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _UnregistrationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(UnregistrationRequest, callSignalAddress), - _UnregistrationRequest_callSignalAddress}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL}, - {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _CallModel[] = { /* CHOICE */ - {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL}, - {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, -}; - -static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest_destExtraCallInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _AdmissionRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, - {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _AdmissionRequest_destinationInfo}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(AdmissionRequest, destCallSignalAddress), - _TransportAddress}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, - _AdmissionRequest_destExtraCallInfo}, - {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0, - _AdmissionRequest_srcInfo}, - {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, - offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress}, - {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL}, - {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, - {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL}, - {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, - {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _AdmissionConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL}, - {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel}, - {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(AdmissionConfirm, destCallSignalAddress), - _TransportAddress}, - {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL}, - {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _LocationRequest_destinationInfo[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, -}; - -static field_t _LocationRequest[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0, - _LocationRequest_destinationInfo}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationRequest, replyAddress), _TransportAddress}, - {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, - NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, -}; - -static field_t _LocationConfirm[] = { /* SEQUENCE */ - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationConfirm, callSignalAddress), _TransportAddress}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(LocationConfirm, rasAddress), _TransportAddress}, - {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, - {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, - NULL}, - {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, - 0, NULL}, - {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, - {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _InfoRequestResponse_callSignalAddress[] = { /* SEQUENCE OF */ - {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, - sizeof(TransportAddress), _TransportAddress} - , -}; - -static field_t _InfoRequestResponse[] = { /* SEQUENCE */ - {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, - _NonStandardParameter}, - {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, - {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, - {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, - {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, - offsetof(InfoRequestResponse, rasAddress), _TransportAddress}, - {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, - offsetof(InfoRequestResponse, callSignalAddress), - _InfoRequestResponse_callSignalAddress}, - {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, - {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, - {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, - {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, - {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL}, - {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, -}; - -static field_t _RasMessage[] = { /* CHOICE */ - {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT, - offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest}, - {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT, - offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm}, - {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, - {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT, - offsetof(RasMessage, registrationRequest), _RegistrationRequest}, - {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT, - offsetof(RasMessage, registrationConfirm), _RegistrationConfirm}, - {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, - {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT, - offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest}, - {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL}, - {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT, - offsetof(RasMessage, admissionRequest), _AdmissionRequest}, - {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT, - offsetof(RasMessage, admissionConfirm), _AdmissionConfirm}, - {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL}, - {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL}, - {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL}, - {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL}, - {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL}, - {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, - {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT, - offsetof(RasMessage, locationRequest), _LocationRequest}, - {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT, - offsetof(RasMessage, locationConfirm), _LocationConfirm}, - {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL}, - {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL}, - {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT, - offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse}, - {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL}, - {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL}, - {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL}, - {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0, - NULL}, - {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0, - NULL}, - {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL}, - {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL}, - {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0, - NULL}, - {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL}, -}; diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c new file mode 100644 index 000000000000..fb9ab0114c23 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -0,0 +1,596 @@ +/* + * H.323 extension for NAT alteration. + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * Based on the 'brute force' H.323 NAT module by + * Jozsef Kadlecsik + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/****************************************************************************/ +static int set_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + unsigned int addroff, __be32 ip, __be16 port) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo); + struct { + __be32 ip; + __be16 port; + } __attribute__ ((__packed__)) buf; + struct tcphdr _tcph, *th; + + buf.ip = ip; + buf.port = port; + addroff += dataoff; + + if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) { + if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + addroff, sizeof(buf), + (char *) &buf, sizeof(buf))) { + if (net_ratelimit()) + printk("nf_nat_h323: nf_nat_mangle_tcp_packet" + " error\n"); + return -1; + } + + /* Relocate data pointer */ + th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, + sizeof(_tcph), &_tcph); + if (th == NULL) + return -1; + *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + + th->doff * 4 + dataoff; + } else { + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + addroff, sizeof(buf), + (char *) &buf, sizeof(buf))) { + if (net_ratelimit()) + printk("nf_nat_h323: nf_nat_mangle_udp_packet" + " error\n"); + return -1; + } + /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy + * or pull everything in a linear buffer, so we can safely + * use the skb pointers now */ + *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + + sizeof(struct udphdr); + } + + return 0; +} + +/****************************************************************************/ +static int set_h225_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) +{ + return set_addr(pskb, data, dataoff, taddr->ipAddress.ip, + addr->ip, port); +} + +/****************************************************************************/ +static int set_h245_addr(struct sk_buff **pskb, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) +{ + return set_addr(pskb, data, dataoff, + taddr->unicastAddress.iPAddress.network, + addr->ip, port); +} + +/****************************************************************************/ +static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int i; + __be16 port; + union nf_conntrack_address addr; + + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { + if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && + port == info->sig_port[dir]) { + /* GW->GK */ + + /* Fix for Gnomemeeting */ + if (i > 0 && + get_h225_addr(ct, *data, &taddr[0], + &addr, &port) && + (ntohl(addr.ip) & 0xff000000) == 0x7f000000) + i = 0; + + DEBUGP + ("nf_nat_ras: set signal address " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), port, + NIPQUAD(ct->tuplehash[!dir].tuple.dst. + ip), info->sig_port[!dir]); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir]. + tuple.dst.u3, + info->sig_port[!dir]); + } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && + port == info->sig_port[dir]) { + /* GK->GW */ + DEBUGP + ("nf_nat_ras: set signal address " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), port, + NIPQUAD(ct->tuplehash[!dir].tuple.src. + ip), info->sig_port[!dir]); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir]. + tuple.src.u3, + info->sig_port[!dir]); + } + } + } + + return 0; +} + +/****************************************************************************/ +static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + int dir = CTINFO2DIR(ctinfo); + int i; + __be16 port; + union nf_conntrack_address addr; + + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && + addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && + port == ct->tuplehash[dir].tuple.src.u.udp.port) { + DEBUGP("nf_nat_ras: set rasAddress " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(ip), ntohs(port), + NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip), + ntohs(ct->tuplehash[!dir].tuple.dst.u.udp. + port)); + return set_h225_addr(pskb, data, 0, &taddr[i], + &ct->tuplehash[!dir].tuple.dst.u3, + ct->tuplehash[!dir].tuple. + dst.u.udp.port); + } + } + + return 0; +} + +/****************************************************************************/ +static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + __be16 port, __be16 rtp_port, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int i; + u_int16_t nated_port; + + /* Set expectations for NAT */ + rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; + rtp_exp->expectfn = nf_nat_follow_master; + rtp_exp->dir = !dir; + rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; + rtcp_exp->expectfn = nf_nat_follow_master; + rtcp_exp->dir = !dir; + + /* Lookup existing expects */ + for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { + if (info->rtp_port[i][dir] == rtp_port) { + /* Expected */ + + /* Use allocated ports first. This will refresh + * the expects */ + rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir]; + rtcp_exp->tuple.dst.u.udp.port = + htons(ntohs(info->rtp_port[i][dir]) + 1); + break; + } else if (info->rtp_port[i][dir] == 0) { + /* Not expected */ + break; + } + } + + /* Run out of expectations */ + if (i >= H323_RTP_CHANNEL_MAX) { + if (net_ratelimit()) + printk("nf_nat_h323: out of expectations\n"); + return 0; + } + + /* Try to get a pair of ports. */ + for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); + nated_port != 0; nated_port += 2) { + rtp_exp->tuple.dst.u.udp.port = htons(nated_port); + if (nf_conntrack_expect_related(rtp_exp) == 0) { + rtcp_exp->tuple.dst.u.udp.port = + htons(nated_port + 1); + if (nf_conntrack_expect_related(rtcp_exp) == 0) + break; + nf_conntrack_unexpect_related(rtp_exp); + } + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_h323: out of RTP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h245_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons((port & htons(1)) ? nated_port + 1 : + nated_port)) == 0) { + /* Save ports */ + info->rtp_port[i][dir] = rtp_port; + info->rtp_port[i][!dir] = htons(nated_port); + } else { + nf_conntrack_unexpect_related(rtp_exp); + nf_conntrack_unexpect_related(rtcp_exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(rtp_exp->tuple.src.ip), + ntohs(rtp_exp->tuple.src.u.udp.port), + NIPQUAD(rtp_exp->tuple.dst.ip), + ntohs(rtp_exp->tuple.dst.u.udp.port)); + DEBUGP("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(rtcp_exp->tuple.src.ip), + ntohs(rtcp_exp->tuple.src.u.udp.port), + NIPQUAD(rtcp_exp->tuple.dst.ip), + ntohs(rtcp_exp->tuple.dst.u.udp.port)); + + return 0; +} + +/****************************************************************************/ +static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = nf_nat_follow_master; + exp->dir = !dir; + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_h323: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h245_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) < 0) { + nf_conntrack_unexpect_related(exp); + return -1; + } + + DEBUGP("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = nf_nat_follow_master; + exp->dir = !dir; + + /* Check existing expects */ + if (info->sig_port[dir] == port) + nated_port = ntohs(info->sig_port[!dir]); + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_q931: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h225_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + } else { + nf_conntrack_unexpect_related(exp); + return -1; + } + + DEBUGP("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/**************************************************************************** + * This conntrack expect function replaces nf_conntrack_q931_expect() + * which was set by nf_conntrack_h323.c. + ****************************************************************************/ +static void ip_nat_q931_expect(struct nf_conn *new, + struct nf_conntrack_expect *this) +{ + struct ip_nat_range range; + + if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ + nf_nat_follow_master(new, this); + return; + } + + /* This must be a fresh one. */ + BUG_ON(new->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = this->saved_proto; + range.min_ip = range.max_ip = + new->master->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); +} + +/****************************************************************************/ +static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress *taddr, int idx, + __be16 port, struct nf_conntrack_expect *exp) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port = ntohs(port); + union nf_conntrack_address addr; + + /* Set expectations for NAT */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = ip_nat_q931_expect; + exp->dir = !dir; + + /* Check existing expects */ + if (info->sig_port[dir] == port) + nated_port = ntohs(info->sig_port[!dir]); + + /* Try to get same port: if not, try to change it. */ + for (; nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_ras: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (set_h225_addr(pskb, data, 0, &taddr[idx], + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + + /* Fix for Gnomemeeting */ + if (idx > 0 && + get_h225_addr(ct, *data, &taddr[0], &addr, &port) && + (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { + set_h225_addr_hook(pskb, data, 0, &taddr[0], + &ct->tuplehash[!dir].tuple.dst.u3, + info->sig_port[!dir]); + } + } else { + nf_conntrack_unexpect_related(exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static void ip_nat_callforwarding_expect(struct nf_conn *new, + struct nf_conntrack_expect *this) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(new->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; + + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = this->saved_proto; + range.min_ip = range.max_ip = this->saved_ip; + + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); +} + +/****************************************************************************/ +static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) +{ + int dir = CTINFO2DIR(ctinfo); + u_int16_t nated_port; + + /* Set expectations for NAT */ + exp->saved_ip = exp->tuple.dst.u3.ip; + exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->expectfn = ip_nat_callforwarding_expect; + exp->dir = !dir; + + /* Try to get same port: if not, try to change it. */ + for (nated_port = ntohs(port); nated_port != 0; nated_port++) { + exp->tuple.dst.u.tcp.port = htons(nated_port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (nated_port == 0) { /* No port available */ + if (net_ratelimit()) + printk("nf_nat_q931: out of TCP ports\n"); + return 0; + } + + /* Modify signal */ + if (!set_h225_addr(pskb, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port)) == 0) { + nf_conntrack_unexpect_related(exp); + return -1; + } + + /* Success */ + DEBUGP("nf_nat_q931: expect Call Forwarding " + "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + return 0; +} + +/****************************************************************************/ +static int __init init(void) +{ + BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL); + BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL); + BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL); + BUG_ON(rcu_dereference(nat_t120_hook) != NULL); + BUG_ON(rcu_dereference(nat_h245_hook) != NULL); + BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL); + BUG_ON(rcu_dereference(nat_q931_hook) != NULL); + + rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); + rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); + rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); + rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); + rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); + rcu_assign_pointer(nat_t120_hook, nat_t120); + rcu_assign_pointer(nat_h245_hook, nat_h245); + rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); + rcu_assign_pointer(nat_q931_hook, nat_q931); + + DEBUGP("nf_nat_h323: init success\n"); + return 0; +} + +/****************************************************************************/ +static void __exit fini(void) +{ + rcu_assign_pointer(set_h245_addr_hook, NULL); + rcu_assign_pointer(set_h225_addr_hook, NULL); + rcu_assign_pointer(set_sig_addr_hook, NULL); + rcu_assign_pointer(set_ras_addr_hook, NULL); + rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); + rcu_assign_pointer(nat_t120_hook, NULL); + rcu_assign_pointer(nat_h245_hook, NULL); + rcu_assign_pointer(nat_callforwarding_hook, NULL); + rcu_assign_pointer(nat_q931_hook, NULL); + synchronize_rcu(); +} + +/****************************************************************************/ +module_init(init); +module_exit(fini); + +MODULE_AUTHOR("Jing Min Zhao "); +MODULE_DESCRIPTION("H.323 NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_h323"); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f85fd43b344b..d8f3451c95b6 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -160,6 +160,25 @@ config NF_CONNTRACK_FTP To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_H323 + tristate "H.323 protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most + important VoIP protocols, it is widely used by voice hardware and + software including voice gateways, IP phones, Netmeeting, OpenPhone, + Gnomemeeting, etc. + + With this module you can support H.323 on a connection tracking/NAT + firewall. + + This module supports RAS, Fast Start, H.245 Tunnelling, Call + Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat, + whiteboard, file transfer, etc. For more information, please + visit http://nath323.sourceforge.net/. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index a5ee93817427..69b554576b6b 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -20,8 +20,11 @@ obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o # connection tracking helpers +nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o + obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o +obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c new file mode 100644 index 000000000000..f6fad713d484 --- /dev/null +++ b/net/netfilter/nf_conntrack_h323_asn1.c @@ -0,0 +1,874 @@ +/**************************************************************************** + * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 + * conntrack/NAT module. + * + * Copyright (c) 2006 by Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * See ip_conntrack_helper_h323_asn1.h for details. + * + ****************************************************************************/ + +#ifdef __KERNEL__ +#include +#else +#include +#endif +#include + +/* Trace Flag */ +#ifndef H323_TRACE +#define H323_TRACE 0 +#endif + +#if H323_TRACE +#define TAB_SIZE 4 +#define IFTHEN(cond, act) if(cond){act;} +#ifdef __KERNEL__ +#define PRINT printk +#else +#define PRINT printf +#endif +#define FNAME(name) name, +#else +#define IFTHEN(cond, act) +#define PRINT(fmt, args...) +#define FNAME(name) +#endif + +/* ASN.1 Types */ +#define NUL 0 +#define BOOL 1 +#define OID 2 +#define INT 3 +#define ENUM 4 +#define BITSTR 5 +#define NUMSTR 6 +#define NUMDGT 6 +#define TBCDSTR 6 +#define OCTSTR 7 +#define PRTSTR 7 +#define IA5STR 7 +#define GENSTR 7 +#define BMPSTR 8 +#define SEQ 9 +#define SET 9 +#define SEQOF 10 +#define SETOF 10 +#define CHOICE 11 + +/* Constraint Types */ +#define FIXD 0 +/* #define BITS 1-8 */ +#define BYTE 9 +#define WORD 10 +#define CONS 11 +#define SEMI 12 +#define UNCO 13 + +/* ASN.1 Type Attributes */ +#define SKIP 0 +#define STOP 1 +#define DECODE 2 +#define EXT 4 +#define OPEN 8 +#define OPT 16 + + +/* ASN.1 Field Structure */ +typedef struct field_t { +#if H323_TRACE + char *name; +#endif + unsigned char type; + unsigned char sz; + unsigned char lb; + unsigned char ub; + unsigned short attr; + unsigned short offset; + struct field_t *fields; +} field_t; + +/* Bit Stream */ +typedef struct { + unsigned char *buf; + unsigned char *beg; + unsigned char *end; + unsigned char *cur; + unsigned bit; +} bitstr_t; + +/* Tool Functions */ +#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;} +#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;} +#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;} +#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND) +static unsigned get_len(bitstr_t * bs); +static unsigned get_bit(bitstr_t * bs); +static unsigned get_bits(bitstr_t * bs, unsigned b); +static unsigned get_bitmap(bitstr_t * bs, unsigned b); +static unsigned get_uint(bitstr_t * bs, int b); + +/* Decoder Functions */ +static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_int(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level); +static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level); + +/* Decoder Functions Vector */ +typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int); +static decoder_t Decoders[] = { + decode_nul, + decode_bool, + decode_oid, + decode_int, + decode_enum, + decode_bitstr, + decode_numstr, + decode_octstr, + decode_bmpstr, + decode_seq, + decode_seqof, + decode_choice, +}; + +/**************************************************************************** + * H.323 Types + ****************************************************************************/ +#include "nf_conntrack_h323_types.c" + +/**************************************************************************** + * Functions + ****************************************************************************/ +/* Assume bs is aligned && v < 16384 */ +unsigned get_len(bitstr_t * bs) +{ + unsigned v; + + v = *bs->cur++; + + if (v & 0x80) { + v &= 0x3f; + v <<= 8; + v += *bs->cur++; + } + + return v; +} + +/****************************************************************************/ +unsigned get_bit(bitstr_t * bs) +{ + unsigned b = (*bs->cur) & (0x80 >> bs->bit); + + INC_BIT(bs); + + return b; +} + +/****************************************************************************/ +/* Assume b <= 8 */ +unsigned get_bits(bitstr_t * bs, unsigned b) +{ + unsigned v, l; + + v = (*bs->cur) & (0xffU >> bs->bit); + l = b + bs->bit; + + if (l < 8) { + v >>= 8 - l; + bs->bit = l; + } else if (l == 8) { + bs->cur++; + bs->bit = 0; + } else { /* l > 8 */ + + v <<= 8; + v += *(++bs->cur); + v >>= 16 - l; + bs->bit = l - 8; + } + + return v; +} + +/****************************************************************************/ +/* Assume b <= 32 */ +unsigned get_bitmap(bitstr_t * bs, unsigned b) +{ + unsigned v, l, shift, bytes; + + if (!b) + return 0; + + l = bs->bit + b; + + if (l < 8) { + v = (unsigned) (*bs->cur) << (bs->bit + 24); + bs->bit = l; + } else if (l == 8) { + v = (unsigned) (*bs->cur++) << (bs->bit + 24); + bs->bit = 0; + } else { + for (bytes = l >> 3, shift = 24, v = 0; bytes; + bytes--, shift -= 8) + v |= (unsigned) (*bs->cur++) << shift; + + if (l < 32) { + v |= (unsigned) (*bs->cur) << shift; + v <<= bs->bit; + } else if (l > 32) { + v <<= bs->bit; + v |= (*bs->cur) >> (8 - bs->bit); + } + + bs->bit = l & 0x7; + } + + v &= 0xffffffff << (32 - b); + + return v; +} + +/**************************************************************************** + * Assume bs is aligned and sizeof(unsigned int) == 4 + ****************************************************************************/ +unsigned get_uint(bitstr_t * bs, int b) +{ + unsigned v = 0; + + switch (b) { + case 4: + v |= *bs->cur++; + v <<= 8; + case 3: + v |= *bs->cur++; + v <<= 8; + case 2: + v |= *bs->cur++; + v <<= 8; + case 1: + v |= *bs->cur++; + break; + } + return v; +} + +/****************************************************************************/ +int decode_nul(bitstr_t * bs, field_t * f, char *base, int level) +{ + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_bool(bitstr_t * bs, field_t * f, char *base, int level) +{ + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + INC_BIT(bs); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_oid(bitstr_t * bs, field_t * f, char *base, int level) +{ + int len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + len = *bs->cur++; + bs->cur += len; + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_int(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); + + switch (f->sz) { + case BYTE: /* Range == 256 */ + BYTE_ALIGN(bs); + bs->cur++; + break; + case WORD: /* 257 <= Range <= 64K */ + BYTE_ALIGN(bs); + bs->cur += 2; + break; + case CONS: /* 64K < Range < 4G */ + len = get_bits(bs, 2) + 1; + BYTE_ALIGN(bs); + if (base && (f->attr & DECODE)) { /* timeToLive */ + unsigned v = get_uint(bs, len) + f->lb; + PRINT(" = %u", v); + *((unsigned *) (base + f->offset)) = v; + } + bs->cur += len; + break; + case UNCO: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + len = get_len(bs); + bs->cur += len; + break; + default: /* 2 <= Range <= 255 */ + INC_BITS(bs, f->sz); + break; + } + + PRINT("\n"); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_enum(bitstr_t * bs, field_t * f, char *base, int level) +{ + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + if ((f->attr & EXT) && get_bit(bs)) { + INC_BITS(bs, 7); + } else { + INC_BITS(bs, f->sz); + } + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + BYTE_ALIGN(bs); + switch (f->sz) { + case FIXD: /* fixed length > 16 */ + len = f->lb; + break; + case WORD: /* 2-byte length */ + CHECK_BOUND(bs, 2); + len = (*bs->cur++) << 8; + len += (*bs->cur++) + f->lb; + break; + case SEMI: + CHECK_BOUND(bs, 2); + len = get_len(bs); + break; + default: + len = 0; + break; + } + + bs->cur += len >> 3; + bs->bit = len & 7; + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* 2 <= Range <= 255 */ + len = get_bits(bs, f->sz) + f->lb; + + BYTE_ALIGN(bs); + INC_BITS(bs, (len << 2)); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); + + switch (f->sz) { + case FIXD: /* Range == 1 */ + if (f->lb > 2) { + BYTE_ALIGN(bs); + if (base && (f->attr & DECODE)) { + /* The IP Address */ + IFTHEN(f->lb == 4, + PRINT(" = %d.%d.%d.%d:%d", + bs->cur[0], bs->cur[1], + bs->cur[2], bs->cur[3], + bs->cur[4] * 256 + bs->cur[5])); + *((unsigned *) (base + f->offset)) = + bs->cur - bs->buf; + } + } + len = f->lb; + break; + case BYTE: /* Range == 256 */ + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + len = (*bs->cur++) + f->lb; + break; + case SEMI: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + len = get_len(bs) + f->lb; + break; + default: /* 2 <= Range <= 255 */ + len = get_bits(bs, f->sz) + f->lb; + BYTE_ALIGN(bs); + break; + } + + bs->cur += len; + + PRINT("\n"); + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned len; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + switch (f->sz) { + case BYTE: /* Range == 256 */ + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + len = (*bs->cur++) + f->lb; + break; + default: /* 2 <= Range <= 255 */ + len = get_bits(bs, f->sz) + f->lb; + BYTE_ALIGN(bs); + break; + } + + bs->cur += len << 1; + + CHECK_BOUND(bs, 0); + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len; + int err; + field_t *son; + unsigned char *beg = NULL; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* Decode? */ + base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; + + /* Extensible? */ + ext = (f->attr & EXT) ? get_bit(bs) : 0; + + /* Get fields bitmap */ + bmp = get_bitmap(bs, f->sz); + if (base) + *(unsigned *) base = bmp; + + /* Decode the root components */ + for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) { + if (son->attr & STOP) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + return H323_ERROR_STOP; + } + + if (son->attr & OPT) { /* Optional component */ + if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */ + continue; + } + + /* Decode */ + if (son->attr & OPEN) { /* Open field */ + CHECK_BOUND(bs, 2); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, + " ", son->name); + bs->cur += len; + continue; + } + beg = bs->cur; + + /* Decode */ + if ((err = (Decoders[son->type]) (bs, son, base, + level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } else if ((err = (Decoders[son->type]) (bs, son, base, + level + 1)) < + H323_ERROR_NONE) + return err; + } + + /* No extension? */ + if (!ext) + return H323_ERROR_NONE; + + /* Get the extension bitmap */ + bmp2_len = get_bits(bs, 7) + 1; + CHECK_BOUND(bs, (bmp2_len + 7) >> 3); + bmp2 = get_bitmap(bs, bmp2_len); + bmp |= bmp2 >> f->sz; + if (base) + *(unsigned *) base = bmp; + BYTE_ALIGN(bs); + + /* Decode the extension components */ + for (opt = 0; opt < bmp2_len; opt++, i++, son++) { + if (i < f->ub && son->attr & STOP) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + return H323_ERROR_STOP; + } + + if (!((0x80000000 >> opt) & bmp2)) /* Not present */ + continue; + + /* Check Range */ + if (i >= f->ub) { /* Newer Version? */ + CHECK_BOUND(bs, 2); + len = get_len(bs); + CHECK_BOUND(bs, len); + bs->cur += len; + continue; + } + + CHECK_BOUND(bs, 2); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base || !(son->attr & DECODE)) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + bs->cur += len; + continue; + } + beg = bs->cur; + + if ((err = (Decoders[son->type]) (bs, son, base, + level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned count, effective_count = 0, i, len = 0; + int err; + field_t *son; + unsigned char *beg = NULL; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* Decode? */ + base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; + + /* Decode item count */ + switch (f->sz) { + case BYTE: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 1); + count = *bs->cur++; + break; + case WORD: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + count = *bs->cur++; + count <<= 8; + count = *bs->cur++; + break; + case SEMI: + BYTE_ALIGN(bs); + CHECK_BOUND(bs, 2); + count = get_len(bs); + break; + default: + count = get_bits(bs, f->sz); + break; + } + count += f->lb; + + /* Write Count */ + if (base) { + effective_count = count > f->ub ? f->ub : count; + *(unsigned *) base = effective_count; + base += sizeof(unsigned); + } + + /* Decode nested field */ + son = f->fields; + if (base) + base -= son->offset; + for (i = 0; i < count; i++) { + if (son->attr & OPEN) { + BYTE_ALIGN(bs); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base || !(son->attr & DECODE)) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, + " ", son->name); + bs->cur += len; + continue; + } + beg = bs->cur; + + if ((err = (Decoders[son->type]) (bs, son, + i < + effective_count ? + base : NULL, + level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } else + if ((err = (Decoders[son->type]) (bs, son, + i < + effective_count ? + base : NULL, + level + 1)) < + H323_ERROR_NONE) + return err; + + if (base) + base += son->offset; + } + + return H323_ERROR_NONE; +} + + +/****************************************************************************/ +int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) +{ + unsigned type, ext, len = 0; + int err; + field_t *son; + unsigned char *beg = NULL; + + PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); + + /* Decode? */ + base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; + + /* Decode the choice index number */ + if ((f->attr & EXT) && get_bit(bs)) { + ext = 1; + type = get_bits(bs, 7) + f->lb; + } else { + ext = 0; + type = get_bits(bs, f->sz); + } + + /* Write Type */ + if (base) + *(unsigned *) base = type; + + /* Check Range */ + if (type >= f->ub) { /* Newer version? */ + BYTE_ALIGN(bs); + len = get_len(bs); + CHECK_BOUND(bs, len); + bs->cur += len; + return H323_ERROR_NONE; + } + + /* Transfer to son level */ + son = &f->fields[type]; + if (son->attr & STOP) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); + return H323_ERROR_STOP; + } + + if (ext || (son->attr & OPEN)) { + BYTE_ALIGN(bs); + len = get_len(bs); + CHECK_BOUND(bs, len); + if (!base || !(son->attr & DECODE)) { + PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", + son->name); + bs->cur += len; + return H323_ERROR_NONE; + } + beg = bs->cur; + + if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) + return err; + + bs->cur = beg + len; + bs->bit = 0; + } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) + return err; + + return H323_ERROR_NONE; +} + +/****************************************************************************/ +int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras) +{ + static field_t ras_message = { + FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT, + 0, _RasMessage + }; + bitstr_t bs; + + bs.buf = bs.beg = bs.cur = buf; + bs.end = buf + sz; + bs.bit = 0; + + return decode_choice(&bs, &ras_message, (char *) ras, 0); +} + +/****************************************************************************/ +static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, + size_t sz, H323_UserInformation * uuie) +{ + static field_t h323_userinformation = { + FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT, + 0, _H323_UserInformation + }; + bitstr_t bs; + + bs.buf = buf; + bs.beg = bs.cur = beg; + bs.end = beg + sz; + bs.bit = 0; + + return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); +} + +/****************************************************************************/ +int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, + MultimediaSystemControlMessage * + mscm) +{ + static field_t multimediasystemcontrolmessage = { + FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4, + DECODE | EXT, 0, _MultimediaSystemControlMessage + }; + bitstr_t bs; + + bs.buf = bs.beg = bs.cur = buf; + bs.end = buf + sz; + bs.bit = 0; + + return decode_choice(&bs, &multimediasystemcontrolmessage, + (char *) mscm, 0); +} + +/****************************************************************************/ +int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931) +{ + unsigned char *p = buf; + int len; + + if (!p || sz < 1) + return H323_ERROR_BOUND; + + /* Protocol Discriminator */ + if (*p != 0x08) { + PRINT("Unknown Protocol Discriminator\n"); + return H323_ERROR_RANGE; + } + p++; + sz--; + + /* CallReferenceValue */ + if (sz < 1) + return H323_ERROR_BOUND; + len = *p++; + sz--; + if (sz < len) + return H323_ERROR_BOUND; + p += len; + sz -= len; + + /* Message Type */ + if (sz < 1) + return H323_ERROR_BOUND; + q931->MessageType = *p++; + PRINT("MessageType = %02X\n", q931->MessageType); + if (*p & 0x80) { + p++; + sz--; + } + + /* Decode Information Elements */ + while (sz > 0) { + if (*p == 0x7e) { /* UserUserIE */ + if (sz < 3) + break; + p++; + len = *p++ << 8; + len |= *p++; + sz -= 3; + if (sz < len) + break; + p++; + len--; + return DecodeH323_UserInformation(buf, p, len, + &q931->UUIE); + } + p++; + sz--; + if (sz < 1) + break; + len = *p++; + if (sz < len) + break; + p += len; + sz -= len; + } + + PRINT("Q.931 UUIE not found\n"); + + return H323_ERROR_BOUND; +} diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c new file mode 100644 index 000000000000..6d8568959f82 --- /dev/null +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -0,0 +1,1856 @@ +/* + * H.323 connection tracking helper + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + * + * Based on the 'brute force' H.323 connection tracking module by + * Jozsef Kadlecsik + * + * For more information, please see http://nath323.sourceforge.net/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* Parameters */ +static unsigned int default_rrq_ttl __read_mostly = 300; +module_param(default_rrq_ttl, uint, 0600); +MODULE_PARM_DESC(default_rrq_ttl, "use this TTL if it's missing in RRQ"); + +static int gkrouted_only __read_mostly = 1; +module_param(gkrouted_only, int, 0600); +MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper"); + +static int callforward_filter __read_mostly = 1; +module_param(callforward_filter, bool, 0600); +MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations " + "if both endpoints are on different sides " + "(determined by routing information)"); + +/* Hooks for NAT */ +int (*set_h245_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) + __read_mostly; +int (*set_h225_addr_hook) (struct sk_buff **pskb, + unsigned char **data, int dataoff, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 port) + __read_mostly; +int (*set_sig_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) __read_mostly; +int (*set_ras_addr_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) __read_mostly; +int (*nat_rtp_rtcp_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, + __be16 port, __be16 rtp_port, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) __read_mostly; +int (*nat_t120_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) __read_mostly; +int (*nat_h245_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) __read_mostly; +int (*nat_callforwarding_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr, __be16 port, + struct nf_conntrack_expect *exp) __read_mostly; +int (*nat_q931_hook) (struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress *taddr, int idx, + __be16 port, struct nf_conntrack_expect *exp) + __read_mostly; + +static DEFINE_SPINLOCK(nf_h323_lock); +static char *h323_buffer; + +static struct nf_conntrack_helper nf_conntrack_helper_h245; +static struct nf_conntrack_helper nf_conntrack_helper_q931[]; +static struct nf_conntrack_helper nf_conntrack_helper_ras[]; + +/****************************************************************************/ +static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + unsigned char **data, int *datalen, int *dataoff) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + struct tcphdr _tcph, *th; + int tcpdatalen; + int tcpdataoff; + unsigned char *tpkt; + int tpktlen; + int tpktoff; + + /* Get TCP header */ + th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); + if (th == NULL) + return 0; + + /* Get TCP data offset */ + tcpdataoff = protoff + th->doff * 4; + + /* Get TCP data length */ + tcpdatalen = (*pskb)->len - tcpdataoff; + if (tcpdatalen <= 0) /* No TCP data */ + goto clear_out; + + if (*data == NULL) { /* first TPKT */ + /* Get first TPKT pointer */ + tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen, + h323_buffer); + BUG_ON(tpkt == NULL); + + /* Validate TPKT identifier */ + if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) { + /* Netmeeting sends TPKT header and data separately */ + if (info->tpkt_len[dir] > 0) { + DEBUGP("nf_ct_h323: previous packet " + "indicated separate TPKT data of %hu " + "bytes\n", info->tpkt_len[dir]); + if (info->tpkt_len[dir] <= tcpdatalen) { + /* Yes, there was a TPKT header + * received */ + *data = tpkt; + *datalen = info->tpkt_len[dir]; + *dataoff = 0; + goto out; + } + + /* Fragmented TPKT */ + if (net_ratelimit()) + printk("nf_ct_h323: " + "fragmented TPKT\n"); + goto clear_out; + } + + /* It is not even a TPKT */ + return 0; + } + tpktoff = 0; + } else { /* Next TPKT */ + tpktoff = *dataoff + *datalen; + tcpdatalen -= tpktoff; + if (tcpdatalen <= 4) /* No more TPKT */ + goto clear_out; + tpkt = *data + *datalen; + + /* Validate TPKT identifier */ + if (tpkt[0] != 0x03 || tpkt[1] != 0) + goto clear_out; + } + + /* Validate TPKT length */ + tpktlen = tpkt[2] * 256 + tpkt[3]; + if (tpktlen < 4) + goto clear_out; + if (tpktlen > tcpdatalen) { + if (tcpdatalen == 4) { /* Separate TPKT header */ + /* Netmeeting sends TPKT header and data separately */ + DEBUGP("nf_ct_h323: separate TPKT header indicates " + "there will be TPKT data of %hu bytes\n", + tpktlen - 4); + info->tpkt_len[dir] = tpktlen - 4; + return 0; + } + + if (net_ratelimit()) + printk("nf_ct_h323: incomplete TPKT (fragmented?)\n"); + goto clear_out; + } + + /* This is the encapsulated data */ + *data = tpkt + 4; + *datalen = tpktlen - 4; + *dataoff = tpktoff + 4; + + out: + /* Clear TPKT length */ + info->tpkt_len[dir] = 0; + return 1; + + clear_out: + info->tpkt_len[dir] = 0; + return 0; +} + +/****************************************************************************/ +static int get_h245_addr(struct nf_conn *ct, unsigned char *data, + H245_TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 *port) +{ + unsigned char *p; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int len; + + if (taddr->choice != eH245_TransportAddress_unicastAddress) + return 0; + + switch (taddr->unicastAddress.choice) { + case eUnicastAddress_iPAddress: + if (family != AF_INET) + return 0; + p = data + taddr->unicastAddress.iPAddress.network; + len = 4; + break; + case eUnicastAddress_iP6Address: + if (family != AF_INET6) + return 0; + p = data + taddr->unicastAddress.iP6Address.network; + len = 16; + break; + default: + return 0; + } + + memcpy(addr, p, len); + memset((void *)addr + len, 0, sizeof(*addr) - len); + memcpy(port, p + len, sizeof(__be16)); + + return 1; +} + +/****************************************************************************/ +static int expect_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + __be16 rtp_port, rtcp_port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *rtp_exp; + struct nf_conntrack_expect *rtcp_exp; + typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp; + + /* Read RTP or RTCP address */ + if (!get_h245_addr(ct, *data, taddr, &addr, &port) || + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) || + port == 0) + return 0; + + /* RTP port is even */ + port &= htons(~1); + rtp_port = port; + rtcp_port = htons(ntohs(port) + 1); + + /* Create expect for RTP */ + if ((rtp_exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_UDP, NULL, &rtp_port); + + /* Create expect for RTCP */ + if ((rtcp_exp = nf_conntrack_expect_alloc(ct)) == NULL) { + nf_conntrack_expect_put(rtp_exp); + return -1; + } + nf_conntrack_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_UDP, NULL, &rtcp_port); + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook)) && + ct->status & IPS_NAT_MASK) { + /* NAT needed */ + ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + taddr, port, rtp_port, rtp_exp, rtcp_exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(rtp_exp) == 0) { + if (nf_conntrack_expect_related(rtcp_exp) == 0) { + DEBUGP("nf_ct_h323: expect RTP "); + NF_CT_DUMP_TUPLE(&rtp_exp->tuple); + DEBUGP("nf_ct_h323: expect RTCP "); + NF_CT_DUMP_TUPLE(&rtcp_exp->tuple); + } else { + nf_conntrack_unexpect_related(rtp_exp); + ret = -1; + } + } else + ret = -1; + } + + nf_conntrack_expect_put(rtp_exp); + nf_conntrack_expect_put(rtcp_exp); + + return ret; +} + +/****************************************************************************/ +static int expect_t120(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_t120_hook) nat_t120; + + /* Read T.120 address */ + if (!get_h245_addr(ct, *data, taddr, &addr, &port) || + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) || + port == 0) + return 0; + + /* Create expect for T.120 connections */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple channels */ + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_t120 = rcu_dereference(nat_t120_hook)) && + ct->status & IPS_NAT_MASK) { + /* NAT needed */ + ret = nat_t120(pskb, ct, ctinfo, data, dataoff, taddr, + port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_h323: expect T.120 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_h245_channel(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H2250LogicalChannelParameters *channel) +{ + int ret; + + if (channel->options & eH2250LogicalChannelParameters_mediaChannel) { + /* RTP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &channel->mediaChannel); + if (ret < 0) + return -1; + } + + if (channel-> + options & eH2250LogicalChannelParameters_mediaControlChannel) { + /* RTCP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &channel->mediaControlChannel); + if (ret < 0) + return -1; + } + + return 0; +} + +/****************************************************************************/ +static int process_olc(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + OpenLogicalChannel *olc) +{ + int ret; + + DEBUGP("nf_ct_h323: OpenLogicalChannel\n"); + + if (olc->forwardLogicalChannelParameters.multiplexParameters.choice == + eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) + { + ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, + &olc-> + forwardLogicalChannelParameters. + multiplexParameters. + h2250LogicalChannelParameters); + if (ret < 0) + return -1; + } + + if ((olc->options & + eOpenLogicalChannel_reverseLogicalChannelParameters) && + (olc->reverseLogicalChannelParameters.options & + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters) + && (olc->reverseLogicalChannelParameters.multiplexParameters. + choice == + eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) + { + ret = + process_h245_channel(pskb, ct, ctinfo, data, dataoff, + &olc-> + reverseLogicalChannelParameters. + multiplexParameters. + h2250LogicalChannelParameters); + if (ret < 0) + return -1; + } + + if ((olc->options & eOpenLogicalChannel_separateStack) && + olc->forwardLogicalChannelParameters.dataType.choice == + eDataType_data && + olc->forwardLogicalChannelParameters.dataType.data.application. + choice == eDataApplicationCapability_application_t120 && + olc->forwardLogicalChannelParameters.dataType.data.application. + t120.choice == eDataProtocolCapability_separateLANStack && + olc->separateStack.networkAddress.choice == + eNetworkAccessParameters_networkAddress_localAreaAddress) { + ret = expect_t120(pskb, ct, ctinfo, data, dataoff, + &olc->separateStack.networkAddress. + localAreaAddress); + if (ret < 0) + return -1; + } + + return 0; +} + +/****************************************************************************/ +static int process_olca(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + OpenLogicalChannelAck *olca) +{ + H2250LogicalChannelAckParameters *ack; + int ret; + + DEBUGP("nf_ct_h323: OpenLogicalChannelAck\n"); + + if ((olca->options & + eOpenLogicalChannelAck_reverseLogicalChannelParameters) && + (olca->reverseLogicalChannelParameters.options & + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters) + && (olca->reverseLogicalChannelParameters.multiplexParameters. + choice == + eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) + { + ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, + &olca-> + reverseLogicalChannelParameters. + multiplexParameters. + h2250LogicalChannelParameters); + if (ret < 0) + return -1; + } + + if ((olca->options & + eOpenLogicalChannelAck_forwardMultiplexAckParameters) && + (olca->forwardMultiplexAckParameters.choice == + eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters)) + { + ack = &olca->forwardMultiplexAckParameters. + h2250LogicalChannelAckParameters; + if (ack->options & + eH2250LogicalChannelAckParameters_mediaChannel) { + /* RTP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &ack->mediaChannel); + if (ret < 0) + return -1; + } + + if (ack->options & + eH2250LogicalChannelAckParameters_mediaControlChannel) { + /* RTCP */ + ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, + &ack->mediaControlChannel); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_h245(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + MultimediaSystemControlMessage *mscm) +{ + switch (mscm->choice) { + case eMultimediaSystemControlMessage_request: + if (mscm->request.choice == + eRequestMessage_openLogicalChannel) { + return process_olc(pskb, ct, ctinfo, data, dataoff, + &mscm->request.openLogicalChannel); + } + DEBUGP("nf_ct_h323: H.245 Request %d\n", + mscm->request.choice); + break; + case eMultimediaSystemControlMessage_response: + if (mscm->response.choice == + eResponseMessage_openLogicalChannelAck) { + return process_olca(pskb, ct, ctinfo, data, dataoff, + &mscm->response. + openLogicalChannelAck); + } + DEBUGP("nf_ct_h323: H.245 Response %d\n", + mscm->response.choice); + break; + default: + DEBUGP("nf_ct_h323: H.245 signal %d\n", mscm->choice); + break; + } + + return 0; +} + +/****************************************************************************/ +static int h245_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + static MultimediaSystemControlMessage mscm; + unsigned char *data = NULL; + int datalen; + int dataoff; + int ret; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + return NF_ACCEPT; + } + DEBUGP("nf_ct_h245: skblen = %u\n", (*pskb)->len); + + spin_lock_bh(&nf_h323_lock); + + /* Process each TPKT */ + while (get_tpkt_data(pskb, protoff, ct, ctinfo, + &data, &datalen, &dataoff)) { + DEBUGP("nf_ct_h245: TPKT len=%d ", datalen); + NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + + /* Decode H.245 signal */ + ret = DecodeMultimediaSystemControlMessage(data, datalen, + &mscm); + if (ret < 0) { + if (net_ratelimit()) + printk("nf_ct_h245: decoding error: %s\n", + ret == H323_ERROR_BOUND ? + "out of bound" : "out of range"); + /* We don't drop when decoding error */ + break; + } + + /* Process H.245 signal */ + if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0) + goto drop; + } + + spin_unlock_bh(&nf_h323_lock); + return NF_ACCEPT; + + drop: + spin_unlock_bh(&nf_h323_lock); + if (net_ratelimit()) + printk("nf_ct_h245: packet dropped\n"); + return NF_DROP; +} + +/****************************************************************************/ +static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = { + .name = "H.245", + .me = THIS_MODULE, + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */, + .timeout = 240, + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = h245_help +}; + +/****************************************************************************/ +int get_h225_addr(struct nf_conn *ct, unsigned char *data, + TransportAddress *taddr, + union nf_conntrack_address *addr, __be16 *port) +{ + unsigned char *p; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int len; + + switch (taddr->choice) { + case eTransportAddress_ipAddress: + if (family != AF_INET) + return 0; + p = data + taddr->ipAddress.ip; + len = 4; + break; + case eTransportAddress_ip6Address: + if (family != AF_INET6) + return 0; + p = data + taddr->ip6Address.ip6; + len = 16; + break; + default: + return 0; + } + + memcpy(addr, p, len); + memset((void *)addr + len, 0, sizeof(*addr) - len); + memcpy(port, p + len, sizeof(__be16)); + + return 1; +} + +/****************************************************************************/ +static int expect_h245(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_h245_hook) nat_h245; + + /* Read h245Address */ + if (!get_h225_addr(ct, *data, taddr, &addr, &port) || + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) || + port == 0) + return 0; + + /* Create expect for h245 connection */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); + exp->helper = &nf_conntrack_helper_h245; + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_h245 = rcu_dereference(nat_h245_hook)) && + ct->status & IPS_NAT_MASK) { + /* NAT needed */ + ret = nat_h245(pskb, ct, ctinfo, data, dataoff, taddr, + port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_q931: expect H.245 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/* If the calling party is on the same side of the forward-to party, + * we don't need to track the second call */ +static int callforward_do_filter(union nf_conntrack_address *src, + union nf_conntrack_address *dst, + int family) +{ + struct flowi fl1, fl2; + int ret = 0; + + memset(&fl1, 0, sizeof(fl1)); + memset(&fl2, 0, sizeof(fl2)); + + switch (family) { + case AF_INET: { + struct rtable *rt1, *rt2; + + fl1.fl4_dst = src->ip; + fl2.fl4_dst = dst->ip; + if (ip_route_output_key(&rt1, &fl1) == 0) { + if (ip_route_output_key(&rt2, &fl2) == 0) { + if (rt1->rt_gateway == rt2->rt_gateway && + rt1->u.dst.dev == rt2->u.dst.dev) + ret = 1; + dst_release(&rt2->u.dst); + } + dst_release(&rt1->u.dst); + } + break; + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: { + struct rt6_info *rt1, *rt2; + + memcpy(&fl1.fl6_dst, src, sizeof(fl1.fl6_dst)); + memcpy(&fl2.fl6_dst, dst, sizeof(fl2.fl6_dst)); + rt1 = (struct rt6_info *)ip6_route_output(NULL, &fl1); + if (rt1) { + rt2 = (struct rt6_info *)ip6_route_output(NULL, &fl2); + if (rt2) { + if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway, + sizeof(rt1->rt6i_gateway)) && + rt1->u.dst.dev == rt2->u.dst.dev) + ret = 1; + dst_release(&rt2->u.dst); + } + dst_release(&rt1->u.dst); + } + break; + } +#endif + } + return ret; + +} + +/****************************************************************************/ +static int expect_callforwarding(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress *taddr) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_callforwarding_hook) nat_callforwarding; + + /* Read alternativeAddress */ + if (!get_h225_addr(ct, *data, taddr, &addr, &port) || port == 0) + return 0; + + /* If the calling party is on the same side of the forward-to party, + * we don't need to track the second call */ + if (callforward_filter && + callforward_do_filter(&addr, &ct->tuplehash[!dir].tuple.src.u3, + ct->tuplehash[!dir].tuple.src.l3num)) { + DEBUGP("nf_ct_q931: Call Forwarding not tracked\n"); + return 0; + } + + /* Create expect for the second call leg */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->helper = nf_conntrack_helper_q931; + + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + sizeof(ct->tuplehash[dir].tuple.src.u3)) && + (nat_callforwarding = rcu_dereference(nat_callforwarding_hook)) && + ct->status & IPS_NAT_MASK) { + /* Need NAT */ + ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff, + taddr, port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_q931: expect Call Forwarding "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_setup(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Setup_UUIE *setup) +{ + int dir = CTINFO2DIR(ctinfo); + int ret; + int i; + __be16 port; + union nf_conntrack_address addr; + typeof(set_h225_addr_hook) set_h225_addr; + + DEBUGP("nf_ct_q931: Setup\n"); + + if (setup->options & eSetup_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &setup->h245Address); + if (ret < 0) + return -1; + } + + set_h225_addr = rcu_dereference(set_h225_addr_hook); + if ((setup->options & eSetup_UUIE_destCallSignalAddress) && + (set_h225_addr) && ct->status && IPS_NAT_MASK && + get_h225_addr(ct, *data, &setup->destCallSignalAddress, + &addr, &port) && + memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) { + DEBUGP("nf_ct_q931: set destCallSignalAddress " + NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n", + NIP6(*(struct in6_addr *)&addr), ntohs(port), + NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.src.u3), + ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); + ret = set_h225_addr(pskb, data, dataoff, + &setup->destCallSignalAddress, + &ct->tuplehash[!dir].tuple.src.u3, + ct->tuplehash[!dir].tuple.src.u.tcp.port); + if (ret < 0) + return -1; + } + + if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) && + (set_h225_addr) && ct->status & IPS_NAT_MASK && + get_h225_addr(ct, *data, &setup->sourceCallSignalAddress, + &addr, &port) && + memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) { + DEBUGP("nf_ct_q931: set sourceCallSignalAddress " + NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n", + NIP6(*(struct in6_addr *)&addr), ntohs(port), + NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.dst.u3), + ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); + ret = set_h225_addr(pskb, data, dataoff, + &setup->sourceCallSignalAddress, + &ct->tuplehash[!dir].tuple.dst.u3, + ct->tuplehash[!dir].tuple.dst.u.tcp.port); + if (ret < 0) + return -1; + } + + if (setup->options & eSetup_UUIE_fastStart) { + for (i = 0; i < setup->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &setup->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_callproceeding(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + CallProceeding_UUIE *callproc) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: CallProceeding\n"); + + if (callproc->options & eCallProceeding_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &callproc->h245Address); + if (ret < 0) + return -1; + } + + if (callproc->options & eCallProceeding_UUIE_fastStart) { + for (i = 0; i < callproc->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &callproc->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_connect(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Connect_UUIE *connect) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Connect\n"); + + if (connect->options & eConnect_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &connect->h245Address); + if (ret < 0) + return -1; + } + + if (connect->options & eConnect_UUIE_fastStart) { + for (i = 0; i < connect->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &connect->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_alerting(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Alerting_UUIE *alert) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Alerting\n"); + + if (alert->options & eAlerting_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &alert->h245Address); + if (ret < 0) + return -1; + } + + if (alert->options & eAlerting_UUIE_fastStart) { + for (i = 0; i < alert->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &alert->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_information(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Information_UUIE *info) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Information\n"); + + if (info->options & eInformation_UUIE_fastStart) { + for (i = 0; i < info->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &info->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_facility(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Facility_UUIE *facility) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Facility\n"); + + if (facility->reason.choice == eFacilityReason_callForwarded) { + if (facility->options & eFacility_UUIE_alternativeAddress) + return expect_callforwarding(pskb, ct, ctinfo, data, + dataoff, + &facility-> + alternativeAddress); + return 0; + } + + if (facility->options & eFacility_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &facility->h245Address); + if (ret < 0) + return -1; + } + + if (facility->options & eFacility_UUIE_fastStart) { + for (i = 0; i < facility->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &facility->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_progress(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + Progress_UUIE *progress) +{ + int ret; + int i; + + DEBUGP("nf_ct_q931: Progress\n"); + + if (progress->options & eProgress_UUIE_h245Address) { + ret = expect_h245(pskb, ct, ctinfo, data, dataoff, + &progress->h245Address); + if (ret < 0) + return -1; + } + + if (progress->options & eProgress_UUIE_fastStart) { + for (i = 0; i < progress->fastStart.count; i++) { + ret = process_olc(pskb, ct, ctinfo, data, dataoff, + &progress->fastStart.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int process_q931(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, Q931 *q931) +{ + H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu; + int i; + int ret = 0; + + switch (pdu->h323_message_body.choice) { + case eH323_UU_PDU_h323_message_body_setup: + ret = process_setup(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.setup); + break; + case eH323_UU_PDU_h323_message_body_callProceeding: + ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body. + callProceeding); + break; + case eH323_UU_PDU_h323_message_body_connect: + ret = process_connect(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.connect); + break; + case eH323_UU_PDU_h323_message_body_alerting: + ret = process_alerting(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.alerting); + break; + case eH323_UU_PDU_h323_message_body_information: + ret = process_information(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body. + information); + break; + case eH323_UU_PDU_h323_message_body_facility: + ret = process_facility(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.facility); + break; + case eH323_UU_PDU_h323_message_body_progress: + ret = process_progress(pskb, ct, ctinfo, data, dataoff, + &pdu->h323_message_body.progress); + break; + default: + DEBUGP("nf_ct_q931: Q.931 signal %d\n", + pdu->h323_message_body.choice); + break; + } + + if (ret < 0) + return -1; + + if (pdu->options & eH323_UU_PDU_h245Control) { + for (i = 0; i < pdu->h245Control.count; i++) { + ret = process_h245(pskb, ct, ctinfo, data, dataoff, + &pdu->h245Control.item[i]); + if (ret < 0) + return -1; + } + } + + return 0; +} + +/****************************************************************************/ +static int q931_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + static Q931 q931; + unsigned char *data = NULL; + int datalen; + int dataoff; + int ret; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + return NF_ACCEPT; + } + DEBUGP("nf_ct_q931: skblen = %u\n", (*pskb)->len); + + spin_lock_bh(&nf_h323_lock); + + /* Process each TPKT */ + while (get_tpkt_data(pskb, protoff, ct, ctinfo, + &data, &datalen, &dataoff)) { + DEBUGP("nf_ct_q931: TPKT len=%d ", datalen); + NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + + /* Decode Q.931 signal */ + ret = DecodeQ931(data, datalen, &q931); + if (ret < 0) { + if (net_ratelimit()) + printk("nf_ct_q931: decoding error: %s\n", + ret == H323_ERROR_BOUND ? + "out of bound" : "out of range"); + /* We don't drop when decoding error */ + break; + } + + /* Process Q.931 signal */ + if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0) + goto drop; + } + + spin_unlock_bh(&nf_h323_lock); + return NF_ACCEPT; + + drop: + spin_unlock_bh(&nf_h323_lock); + if (net_ratelimit()) + printk("nf_ct_q931: packet dropped\n"); + return NF_DROP; +} + +/****************************************************************************/ +static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = { + { + .name = "Q.931", + .me = THIS_MODULE, + /* T.120 and H.245 */ + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, + .timeout = 240, + .tuple.src.l3num = AF_INET, + .tuple.src.u.tcp.port = __constant_htons(Q931_PORT), + .tuple.dst.protonum = IPPROTO_TCP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.tcp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = q931_help + }, + { + .name = "Q.931", + .me = THIS_MODULE, + /* T.120 and H.245 */ + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, + .timeout = 240, + .tuple.src.l3num = AF_INET6, + .tuple.src.u.tcp.port = __constant_htons(Q931_PORT), + .tuple.dst.protonum = IPPROTO_TCP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.tcp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = q931_help + }, +}; + +/****************************************************************************/ +static unsigned char *get_udp_data(struct sk_buff **pskb, unsigned int protoff, + int *datalen) +{ + struct udphdr _uh, *uh; + int dataoff; + + uh = skb_header_pointer(*pskb, protoff, sizeof(_uh), &_uh); + if (uh == NULL) + return NULL; + dataoff = protoff + sizeof(_uh); + if (dataoff >= (*pskb)->len) + return NULL; + *datalen = (*pskb)->len - dataoff; + return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer); +} + +/****************************************************************************/ +static struct nf_conntrack_expect *find_expect(struct nf_conn *ct, + union nf_conntrack_address *addr, + __be16 port) +{ + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple tuple; + + memset(&tuple.src.u3, 0, sizeof(tuple.src.u3)); + tuple.src.u.tcp.port = 0; + memcpy(&tuple.dst.u3, addr, sizeof(tuple.dst.u3)); + tuple.dst.u.tcp.port = port; + tuple.dst.protonum = IPPROTO_TCP; + + exp = __nf_conntrack_expect_find(&tuple); + if (exp && exp->master == ct) + return exp; + return NULL; +} + +/****************************************************************************/ +static int set_expect_timeout(struct nf_conntrack_expect *exp, + unsigned timeout) +{ + if (!exp || !del_timer(&exp->timeout)) + return 0; + + exp->timeout.expires = jiffies + timeout * HZ; + add_timer(&exp->timeout); + + return 1; +} + +/****************************************************************************/ +static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress *taddr, int count) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + int i; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(nat_q931_hook) nat_q931; + + /* Look for the first related address */ + for (i = 0; i < count; i++) { + if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && + memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, + sizeof(addr)) == 0 && port != 0) + break; + } + + if (i >= count) /* Not found */ + return 0; + + /* Create expect for Q.931 */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + gkrouted_only ? /* only accept calls from GK? */ + &ct->tuplehash[!dir].tuple.src.u3 : + NULL, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); + exp->helper = nf_conntrack_helper_q931; + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */ + + nat_q931 = rcu_dereference(nat_q931_hook); + if (nat_q931 && ct->status & IPS_NAT_MASK) { /* Need NAT */ + ret = nat_q931(pskb, ct, ctinfo, data, taddr, i, port, exp); + } else { /* Conntrack only */ + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect Q.931 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + + /* Save port for looking up expect in processing RCF */ + info->sig_port[dir] = port; + } else + ret = -1; + } + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_grq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, GatekeeperRequest *grq) +{ + typeof(set_ras_addr_hook) set_ras_addr; + + DEBUGP("nf_ct_ras: GRQ\n"); + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) /* NATed */ + return set_ras_addr(pskb, ct, ctinfo, data, + &grq->rasAddress, 1); + return 0; +} + +/****************************************************************************/ +static int process_gcf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, GatekeeperConfirm *gcf) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + + DEBUGP("nf_ct_ras: GCF\n"); + + if (!get_h225_addr(ct, *data, &gcf->rasAddress, &addr, &port)) + return 0; + + /* Registration port is the same as discovery port */ + if (!memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && + port == ct->tuplehash[dir].tuple.src.u.udp.port) + return 0; + + /* Avoid RAS expectation loops. A GCF is never expected. */ + if (test_bit(IPS_EXPECTED_BIT, &ct->status)) + return 0; + + /* Need new expect */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_UDP, NULL, &port); + exp->helper = nf_conntrack_helper_ras; + + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect RAS "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, RegistrationRequest *rrq) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int ret; + typeof(set_ras_addr_hook) set_ras_addr; + + DEBUGP("nf_ct_ras: RRQ\n"); + + ret = expect_q931(pskb, ct, ctinfo, data, + rrq->callSignalAddress.item, + rrq->callSignalAddress.count); + if (ret < 0) + return -1; + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) { + ret = set_ras_addr(pskb, ct, ctinfo, data, + rrq->rasAddress.item, + rrq->rasAddress.count); + if (ret < 0) + return -1; + } + + if (rrq->options & eRegistrationRequest_timeToLive) { + DEBUGP("nf_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive); + info->timeout = rrq->timeToLive; + } else + info->timeout = default_rrq_ttl; + + return 0; +} + +/****************************************************************************/ +static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, RegistrationConfirm *rcf) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int ret; + struct nf_conntrack_expect *exp; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: RCF\n"); + + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + rcf->callSignalAddress.item, + rcf->callSignalAddress.count); + if (ret < 0) + return -1; + } + + if (rcf->options & eRegistrationConfirm_timeToLive) { + DEBUGP("nf_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive); + info->timeout = rcf->timeToLive; + } + + if (info->timeout > 0) { + DEBUGP + ("nf_ct_ras: set RAS connection timeout to %u seconds\n", + info->timeout); + nf_ct_refresh(ct, *pskb, info->timeout * HZ); + + /* Set expect timeout */ + read_lock_bh(&nf_conntrack_lock); + exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3, + info->sig_port[!dir]); + if (exp) { + DEBUGP("nf_ct_ras: set Q.931 expect " + "timeout to %u seconds for", + info->timeout); + NF_CT_DUMP_TUPLE(&exp->tuple); + set_expect_timeout(exp, info->timeout); + } + read_unlock_bh(&nf_conntrack_lock); + } + + return 0; +} + +/****************************************************************************/ +static int process_urq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, UnregistrationRequest *urq) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + int ret; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: URQ\n"); + + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + urq->callSignalAddress.item, + urq->callSignalAddress.count); + if (ret < 0) + return -1; + } + + /* Clear old expect */ + nf_ct_remove_expectations(ct); + info->sig_port[dir] = 0; + info->sig_port[!dir] = 0; + + /* Give it 30 seconds for UCF or URJ */ + nf_ct_refresh(ct, *pskb, 30 * HZ); + + return 0; +} + +/****************************************************************************/ +static int process_arq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, AdmissionRequest *arq) +{ + struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; + int dir = CTINFO2DIR(ctinfo); + __be16 port; + union nf_conntrack_address addr; + typeof(set_h225_addr_hook) set_h225_addr; + + DEBUGP("nf_ct_ras: ARQ\n"); + + set_h225_addr = rcu_dereference(set_h225_addr_hook); + if ((arq->options & eAdmissionRequest_destCallSignalAddress) && + get_h225_addr(ct, *data, &arq->destCallSignalAddress, + &addr, &port) && + !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && + port == info->sig_port[dir] && + set_h225_addr && ct->status & IPS_NAT_MASK) { + /* Answering ARQ */ + return set_h225_addr(pskb, data, 0, + &arq->destCallSignalAddress, + &ct->tuplehash[!dir].tuple.dst.u3, + info->sig_port[!dir]); + } + + if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && + get_h225_addr(ct, *data, &arq->srcCallSignalAddress, + &addr, &port) && + !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && + set_h225_addr && ct->status & IPS_NAT_MASK) { + /* Calling ARQ */ + return set_h225_addr(pskb, data, 0, + &arq->srcCallSignalAddress, + &ct->tuplehash[!dir].tuple.dst.u3, + port); + } + + return 0; +} + +/****************************************************************************/ +static int process_acf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, AdmissionConfirm *acf) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: ACF\n"); + + if (!get_h225_addr(ct, *data, &acf->destCallSignalAddress, + &addr, &port)) + return 0; + + if (!memcmp(&addr, &ct->tuplehash[dir].tuple.dst.u3, sizeof(addr))) { + /* Answering ACF */ + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) + return set_sig_addr(pskb, ct, ctinfo, data, + &acf->destCallSignalAddress, 1); + return 0; + } + + /* Need new expect */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->helper = nf_conntrack_helper_q931; + + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect Q.931 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + + nf_conntrack_expect_put(exp); + + return ret; +} + +/****************************************************************************/ +static int process_lrq(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, LocationRequest *lrq) +{ + typeof(set_ras_addr_hook) set_ras_addr; + + DEBUGP("nf_ct_ras: LRQ\n"); + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) + return set_ras_addr(pskb, ct, ctinfo, data, + &lrq->replyAddress, 1); + return 0; +} + +/****************************************************************************/ +static int process_lcf(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, LocationConfirm *lcf) +{ + int dir = CTINFO2DIR(ctinfo); + int ret = 0; + __be16 port; + union nf_conntrack_address addr; + struct nf_conntrack_expect *exp; + + DEBUGP("nf_ct_ras: LCF\n"); + + if (!get_h225_addr(ct, *data, &lcf->callSignalAddress, + &addr, &port)) + return 0; + + /* Need new expect for call signal */ + if ((exp = nf_conntrack_expect_alloc(ct)) == NULL) + return -1; + nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->helper = nf_conntrack_helper_q931; + + if (nf_conntrack_expect_related(exp) == 0) { + DEBUGP("nf_ct_ras: expect Q.931 "); + NF_CT_DUMP_TUPLE(&exp->tuple); + } else + ret = -1; + + nf_conntrack_expect_put(exp); + + /* Ignore rasAddress */ + + return ret; +} + +/****************************************************************************/ +static int process_irr(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, InfoRequestResponse *irr) +{ + int ret; + typeof(set_ras_addr_hook) set_ras_addr; + typeof(set_sig_addr_hook) set_sig_addr; + + DEBUGP("nf_ct_ras: IRR\n"); + + set_ras_addr = rcu_dereference(set_ras_addr_hook); + if (set_ras_addr && ct->status & IPS_NAT_MASK) { + ret = set_ras_addr(pskb, ct, ctinfo, data, + &irr->rasAddress, 1); + if (ret < 0) + return -1; + } + + set_sig_addr = rcu_dereference(set_sig_addr_hook); + if (set_sig_addr && ct->status & IPS_NAT_MASK) { + ret = set_sig_addr(pskb, ct, ctinfo, data, + irr->callSignalAddress.item, + irr->callSignalAddress.count); + if (ret < 0) + return -1; + } + + return 0; +} + +/****************************************************************************/ +static int process_ras(struct sk_buff **pskb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, RasMessage *ras) +{ + switch (ras->choice) { + case eRasMessage_gatekeeperRequest: + return process_grq(pskb, ct, ctinfo, data, + &ras->gatekeeperRequest); + case eRasMessage_gatekeeperConfirm: + return process_gcf(pskb, ct, ctinfo, data, + &ras->gatekeeperConfirm); + case eRasMessage_registrationRequest: + return process_rrq(pskb, ct, ctinfo, data, + &ras->registrationRequest); + case eRasMessage_registrationConfirm: + return process_rcf(pskb, ct, ctinfo, data, + &ras->registrationConfirm); + case eRasMessage_unregistrationRequest: + return process_urq(pskb, ct, ctinfo, data, + &ras->unregistrationRequest); + case eRasMessage_admissionRequest: + return process_arq(pskb, ct, ctinfo, data, + &ras->admissionRequest); + case eRasMessage_admissionConfirm: + return process_acf(pskb, ct, ctinfo, data, + &ras->admissionConfirm); + case eRasMessage_locationRequest: + return process_lrq(pskb, ct, ctinfo, data, + &ras->locationRequest); + case eRasMessage_locationConfirm: + return process_lcf(pskb, ct, ctinfo, data, + &ras->locationConfirm); + case eRasMessage_infoRequestResponse: + return process_irr(pskb, ct, ctinfo, data, + &ras->infoRequestResponse); + default: + DEBUGP("nf_ct_ras: RAS message %d\n", ras->choice); + break; + } + + return 0; +} + +/****************************************************************************/ +static int ras_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + static RasMessage ras; + unsigned char *data; + int datalen = 0; + int ret; + + DEBUGP("nf_ct_ras: skblen = %u\n", (*pskb)->len); + + spin_lock_bh(&nf_h323_lock); + + /* Get UDP data */ + data = get_udp_data(pskb, protoff, &datalen); + if (data == NULL) + goto accept; + DEBUGP("nf_ct_ras: RAS message len=%d ", datalen); + NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + + /* Decode RAS message */ + ret = DecodeRasMessage(data, datalen, &ras); + if (ret < 0) { + if (net_ratelimit()) + printk("nf_ct_ras: decoding error: %s\n", + ret == H323_ERROR_BOUND ? + "out of bound" : "out of range"); + goto accept; + } + + /* Process RAS message */ + if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0) + goto drop; + + accept: + spin_unlock_bh(&nf_h323_lock); + return NF_ACCEPT; + + drop: + spin_unlock_bh(&nf_h323_lock); + if (net_ratelimit()) + printk("nf_ct_ras: packet dropped\n"); + return NF_DROP; +} + +/****************************************************************************/ +static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = { + { + .name = "RAS", + .me = THIS_MODULE, + .max_expected = 32, + .timeout = 240, + .tuple.src.l3num = AF_INET, + .tuple.src.u.udp.port = __constant_htons(RAS_PORT), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = ras_help, + }, + { + .name = "RAS", + .me = THIS_MODULE, + .max_expected = 32, + .timeout = 240, + .tuple.src.l3num = AF_INET6, + .tuple.src.u.udp.port = __constant_htons(RAS_PORT), + .tuple.dst.protonum = IPPROTO_UDP, + .mask.src.l3num = 0xFFFF, + .mask.src.u.udp.port = __constant_htons(0xFFFF), + .mask.dst.protonum = 0xFF, + .help = ras_help, + }, +}; + +/****************************************************************************/ +static void __exit nf_conntrack_h323_fini(void) +{ + nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[1]); + nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[0]); + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]); + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]); + kfree(h323_buffer); + DEBUGP("nf_ct_h323: fini\n"); +} + +/****************************************************************************/ +static int __init nf_conntrack_h323_init(void) +{ + int ret; + + h323_buffer = kmalloc(65536, GFP_KERNEL); + if (!h323_buffer) + return -ENOMEM; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_q931[0]); + if (ret < 0) + goto err1; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_q931[1]); + if (ret < 0) + goto err2; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_ras[0]); + if (ret < 0) + goto err3; + ret = nf_conntrack_helper_register(&nf_conntrack_helper_ras[1]); + if (ret < 0) + goto err4; + DEBUGP("nf_ct_h323: init success\n"); + return 0; + +err4: + nf_conntrack_helper_unregister(&nf_conntrack_helper_ras[0]); +err3: + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]); +err2: + nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]); +err1: + return ret; +} + +/****************************************************************************/ +module_init(nf_conntrack_h323_init); +module_exit(nf_conntrack_h323_fini); + +EXPORT_SYMBOL_GPL(get_h225_addr); +EXPORT_SYMBOL_GPL(set_h245_addr_hook); +EXPORT_SYMBOL_GPL(set_h225_addr_hook); +EXPORT_SYMBOL_GPL(set_sig_addr_hook); +EXPORT_SYMBOL_GPL(set_ras_addr_hook); +EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook); +EXPORT_SYMBOL_GPL(nat_t120_hook); +EXPORT_SYMBOL_GPL(nat_h245_hook); +EXPORT_SYMBOL_GPL(nat_callforwarding_hook); +EXPORT_SYMBOL_GPL(nat_q931_hook); + +MODULE_AUTHOR("Jing Min Zhao "); +MODULE_DESCRIPTION("H.323 connection tracking helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_h323"); diff --git a/net/netfilter/nf_conntrack_h323_types.c b/net/netfilter/nf_conntrack_h323_types.c new file mode 100644 index 000000000000..4c6f8b3b1208 --- /dev/null +++ b/net/netfilter/nf_conntrack_h323_types.c @@ -0,0 +1,1927 @@ +/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 + * + * Copyright (c) 2006 Jing Min Zhao + * + * This source code is licensed under General Public License version 2. + */ + +static field_t _TransportAddress_ipAddress[] = { /* SEQUENCE */ + {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE, + offsetof(TransportAddress_ipAddress, ip), NULL}, + {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ipSourceRoute_route[] = { /* SEQUENCE OF */ + {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ipSourceRoute_routing[] = { /* CHOICE */ + {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ipSourceRoute[] = { /* SEQUENCE */ + {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, + _TransportAddress_ipSourceRoute_route}, + {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _TransportAddress_ipSourceRoute_routing}, +}; + +static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ + {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, + {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ + {FNAME("ip") OCTSTR, FIXD, 16, 0, DECODE, + offsetof(TransportAddress_ip6Address, ip6), NULL}, + {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H221NonStandard[] = { /* SEQUENCE */ + {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _NonStandardIdentifier[] = { /* CHOICE */ + {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0, + _H221NonStandard}, +}; + +static field_t _NonStandardParameter[] = { /* SEQUENCE */ + {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _NonStandardIdentifier}, + {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TransportAddress[] = { /* CHOICE */ + {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE, + offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress}, + {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0, + _TransportAddress_ipSourceRoute}, + {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, + _TransportAddress_ipxAddress}, + {FNAME("ip6Address") SEQ, 0, 2, 2, DECODE | EXT, + offsetof(TransportAddress, ip6Address), _TransportAddress_ip6Address}, + {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, + {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, + _NonStandardParameter}, +}; + +static field_t _AliasAddress[] = { /* CHOICE */ + {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL}, + {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL}, + {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL}, +}; + +static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _VendorIdentifier[] = { /* SEQUENCE */ + {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard}, + {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _GatekeeperInfo[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, +}; + +static field_t _H310Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H320Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H321Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H322Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H323Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H324Caps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _VoiceCaps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _T120OnlyCaps[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _SupportedProtocols[] = { /* CHOICE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0, + _NonStandardParameter}, + {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps}, + {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps}, + {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps}, + {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps}, + {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps}, + {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps}, + {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps}, + {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps}, + {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL}, +}; + +static field_t _GatewayInfo_protocol[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols}, +}; + +static field_t _GatewayInfo[] = { /* SEQUENCE */ + {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _GatewayInfo_protocol}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, +}; + +static field_t _McuInfo[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _TerminalInfo[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, +}; + +static field_t _EndpointType[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0, + _VendorIdentifier}, + {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, + _GatekeeperInfo}, + {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo}, + {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo}, + {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo}, + {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, + 0, NULL}, +}; + +static field_t _Setup_UUIE_destinationAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _Setup_UUIE_destExtraCallInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _Setup_UUIE_destExtraCRV[] = { /* SEQUENCE OF */ + {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _Setup_UUIE_conferenceGoal[] = { /* CHOICE */ + {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP, + 0, NULL}, +}; + +static field_t _Q954Details[] = { /* SEQUENCE */ + {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _QseriesOptions[] = { /* SEQUENCE */ + {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details}, +}; + +static field_t _CallType[] = { /* CHOICE */ + {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H245_NonStandardIdentifier_h221NonStandard[] = { /* SEQUENCE */ + {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H245_NonStandardIdentifier[] = { /* CHOICE */ + {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0, + _H245_NonStandardIdentifier_h221NonStandard}, +}; + +static field_t _H245_NonStandardParameter[] = { /* SEQUENCE */ + {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0, + _H245_NonStandardIdentifier}, + {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H261VideoCapability[] = { /* SEQUENCE */ + {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, + NULL}, + {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H262VideoCapability[] = { /* SEQUENCE */ + {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0, + NULL}, + {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H263VideoCapability[] = { /* SEQUENCE */ + {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL}, + {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, + NULL}, + {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _IS11172VideoCapability[] = { /* SEQUENCE */ + {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _VideoCapability[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0, + _H261VideoCapability}, + {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0, + _H262VideoCapability}, + {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0, + _H263VideoCapability}, + {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0, + _IS11172VideoCapability}, + {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, +}; + +static field_t _AudioCapability_g7231[] = { /* SEQUENCE */ + {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _IS11172AudioCapability[] = { /* SEQUENCE */ + {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, +}; + +static field_t _IS13818AudioCapability[] = { /* SEQUENCE */ + {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, +}; + +static field_t _AudioCapability[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231}, + {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0, + _IS11172AudioCapability}, + {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0, + _IS13818AudioCapability}, + {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, + {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, + {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL}, +}; + +static field_t _DataProtocolCapability[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL}, + {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */ + {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _T84Profile[] = { /* CHOICE */ + {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0, + _T84Profile_t84Restricted}, +}; + +static field_t _DataApplicationCapability_application_t84[] = { /* SEQUENCE */ + {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile}, +}; + +static field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */ + {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _DataApplicationCapability_application[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT, + offsetof(DataApplicationCapability_application, t120), + _DataProtocolCapability}, + {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0, + _DataApplicationCapability_application_t84}, + {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0, + _DataApplicationCapability_application_nlpid}, + {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0, + _DataProtocolCapability}, + {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, + {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, + {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL}, + {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, +}; + +static field_t _DataApplicationCapability[] = { /* SEQUENCE */ + {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT, + offsetof(DataApplicationCapability, application), + _DataApplicationCapability_application}, + {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _EncryptionMode[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _DataType[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability}, + {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0, + _AudioCapability}, + {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data), + _DataApplicationCapability}, + {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _EncryptionMode}, + {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL}, + {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, + {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, +}; + +static field_t _H222LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = { /* SEQUENCE */ + {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL}, + {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, + _H245_NonStandardParameter}, + {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0, + _H223LogicalChannelParameters_adaptationLayerType_al3}, + {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL}, + {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, + {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL}, +}; + +static field_t _H223LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0, + _H223LogicalChannelParameters_adaptationLayerType}, + {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CRCLength[] = { /* CHOICE */ + {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76HDLCParameters[] = { /* SEQUENCE */ + {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength}, + {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters_suspendResume[] = { /* CHOICE */ + {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = { /* CHOICE */ + {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters_mode_eRM[] = { /* SEQUENCE */ + {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _V76LogicalChannelParameters_mode_eRM_recovery}, +}; + +static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */ + {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0, + _V76LogicalChannelParameters_mode_eRM}, + {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V75Parameters[] = { /* SEQUENCE */ + {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0, + _V76HDLCParameters}, + {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _V76LogicalChannelParameters_suspendResume}, + {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _V76LogicalChannelParameters_mode}, + {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters}, +}; + +static field_t _H2250LogicalChannelParameters_nonStandard[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, +}; + +static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE, + offsetof(UnicastAddress_iPAddress, network), NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ + {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, + {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */ + {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPSourceRouteAddress_route[] = { /* SEQUENCE OF */ + {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, +}; + +static field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */ + {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0, + _UnicastAddress_iPSourceRouteAddress_routing}, + {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, + _UnicastAddress_iPSourceRouteAddress_route}, +}; + +static field_t _UnicastAddress[] = { /* CHOICE */ + {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT, + offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, + {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, + _UnicastAddress_iPXAddress}, + {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, + _UnicastAddress_iP6Address}, + {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, + _UnicastAddress_iPSourceRouteAddress}, + {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, + {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, +}; + +static field_t _MulticastAddress_iPAddress[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */ + {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _MulticastAddress[] = { /* CHOICE */ + {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0, + _MulticastAddress_iPAddress}, + {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, + _MulticastAddress_iP6Address}, + {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, + {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, +}; + +static field_t _H245_TransportAddress[] = { /* CHOICE */ + {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT, + offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress}, + {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0, + _MulticastAddress}, +}; + +static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _H2250LogicalChannelParameters_nonStandard}, + {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelParameters, mediaChannel), + _H245_TransportAddress}, + {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelParameters, mediaControlChannel), + _H245_TransportAddress}, + {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT, + 0, NULL}, + {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL}, + {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, + NULL}, + {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ + {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, + _H222LogicalChannelParameters}, + {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, + _H223LogicalChannelParameters}, + {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, + _V76LogicalChannelParameters}, + {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, + offsetof + (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters, + h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, + {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT, + offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, + dataType), _DataType}, + {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT, + offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, + multiplexParameters), + _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters}, + {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, + 0, NULL}, + {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ + {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, + _H223LogicalChannelParameters}, + {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, + _V76LogicalChannelParameters}, + {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, + offsetof + (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters, + h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, +}; + +static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType}, + {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT, + offsetof(OpenLogicalChannel_reverseLogicalChannelParameters, + multiplexParameters), + _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters}, + {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, + 0, NULL}, + {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _NetworkAccessParameters_distribution[] = { /* CHOICE */ + {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _Q2931Address_address[] = { /* CHOICE */ + {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL}, + {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, +}; + +static field_t _Q2931Address[] = { /* SEQUENCE */ + {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0, + _Q2931Address_address}, + {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _NetworkAccessParameters_networkAddress[] = { /* CHOICE */ + {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address}, + {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT, + offsetof(NetworkAccessParameters_networkAddress, localAreaAddress), + _H245_TransportAddress}, +}; + +static field_t _NetworkAccessParameters[] = { /* SEQUENCE */ + {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, + _NetworkAccessParameters_distribution}, + {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT, + offsetof(NetworkAccessParameters, networkAddress), + _NetworkAccessParameters_networkAddress}, + {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, +}; + +static field_t _OpenLogicalChannel[] = { /* SEQUENCE */ + {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT, + offsetof(OpenLogicalChannel, forwardLogicalChannelParameters), + _OpenLogicalChannel_forwardLogicalChannelParameters}, + {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4, + DECODE | EXT | OPT, offsetof(OpenLogicalChannel, + reverseLogicalChannelParameters), + _OpenLogicalChannel_reverseLogicalChannelParameters}, + {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, + offsetof(OpenLogicalChannel, separateStack), + _NetworkAccessParameters}, + {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _Setup_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Setup_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Setup_UUIE, h245Address), _TransportAddress}, + {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_sourceAddress}, + {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, + {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_destinationAddress}, + {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_destExtraCallInfo}, + {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Setup_UUIE_destExtraCRV}, + {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0, + _Setup_UUIE_conferenceGoal}, + {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0, + _QseriesOptions}, + {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, + {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress}, + {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart}, + {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, + {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + NULL}, +}; + +static field_t _CallProceeding_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(CallProceeding_UUIE, h245Address), _TransportAddress}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(CallProceeding_UUIE, fastStart), + _CallProceeding_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Connect_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Connect_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Connect_UUIE, h245Address), _TransportAddress}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Alerting_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Alerting_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Alerting_UUIE, h245Address), _TransportAddress}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Information_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _ReleaseCompleteReason[] = { /* CHOICE */ + {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL}, + {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0, + NULL}, + {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _ReleaseComplete_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0, + _ReleaseCompleteReason}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, +}; + +static field_t _Facility_UUIE_alternativeAliasAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _FacilityReason[] = { /* CHOICE */ + {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Facility_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Facility_UUIE, alternativeAddress), _TransportAddress}, + {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Facility_UUIE_alternativeAliasAddress}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, + {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT, + offsetof(Facility_UUIE, reason), _FacilityReason}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Facility_UUIE, h245Address), _TransportAddress}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + NULL}, +}; + +static field_t _CallIdentifier[] = { /* SEQUENCE */ + {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, +}; + +static field_t _SecurityServiceMode[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, + {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _SecurityCapabilities[] = { /* SEQUENCE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _SecurityServiceMode}, + {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _SecurityServiceMode}, + {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0, + _SecurityServiceMode}, +}; + +static field_t _H245Security[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, + {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, + {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, +}; + +static field_t _DHset[] = { /* SEQUENCE */ + {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, + {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _TypedCertificate[] = { /* SEQUENCE */ + {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _H235_NonStandardParameter[] = { /* SEQUENCE */ + {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _ClearToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset}, + {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL}, + {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, + _TypedCertificate}, + {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, + _H235_NonStandardParameter}, + {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL}, + {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _Progress_UUIE_tokens[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, +}; + +static field_t _Params[] = { /* SEQUENCE */ + {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL}, + {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoEPPwdHash[] = { /* SEQUENCE */ + {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, + {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoEPPwdHash_token}, +}; + +static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoGKPwdHash[] = { /* SEQUENCE */ + {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoGKPwdHash_token}, +}; + +static field_t _CryptoH323Token_cryptoEPPwdEncr[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoGKPwdEncr[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoEPCert[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoGKCert[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoH323Token_cryptoFastStart[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoEncryptedToken_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoEncryptedToken_token}, +}; + +static field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */ + {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoSignedToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("token") SEQ, 0, 4, 4, SKIP, 0, + _CryptoToken_cryptoSignedToken_token}, +}; + +static field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken_cryptoHashedToken[] = { /* SEQUENCE */ + {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, + {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoHashedToken_token}, +}; + +static field_t _CryptoToken_cryptoPwdEncr[] = { /* SEQUENCE */ + {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, + {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _CryptoToken[] = { /* CHOICE */ + {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0, + _CryptoToken_cryptoEncryptedToken}, + {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0, + _CryptoToken_cryptoSignedToken}, + {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoHashedToken}, + {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0, + _CryptoToken_cryptoPwdEncr}, +}; + +static field_t _CryptoH323Token[] = { /* CHOICE */ + {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoEPPwdHash}, + {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoGKPwdHash}, + {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoEPPwdEncr}, + {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0, + _CryptoH323Token_cryptoGKPwdEncr}, + {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0, + _CryptoH323Token_cryptoEPCert}, + {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0, + _CryptoH323Token_cryptoGKCert}, + {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0, + _CryptoH323Token_cryptoFastStart}, + {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0, + _CryptoToken}, +}; + +static field_t _Progress_UUIE_cryptoTokens[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token}, +}; + +static field_t _Progress_UUIE_fastStart[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, + sizeof(OpenLogicalChannel), _OpenLogicalChannel} + , +}; + +static field_t _Progress_UUIE[] = { /* SEQUENCE */ + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, + _EndpointType}, + {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(Progress_UUIE, h245Address), _TransportAddress}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, + _CallIdentifier}, + {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, + _H245Security}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Progress_UUIE_tokens}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _Progress_UUIE_cryptoTokens}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, + offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ + {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE}, + {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, callProceeding), + _CallProceeding_UUIE}, + {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, + {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, + {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, information), + _Information_UUIE}, + {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, + _ReleaseComplete_UUIE}, + {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE}, + {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT, + offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE}, + {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, + {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, + {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, + {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, +}; + +static field_t _RequestMessage[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT, + offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel}, + {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL}, + {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL}, + {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL}, + {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, + {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0, + NULL}, +}; + +static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ + {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, + _H222LogicalChannelParameters}, + {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, + offsetof + (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters, + h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, +}; + +static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = { /* SEQUENCE */ + {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT, + offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters, + multiplexParameters), + _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters}, + {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _H2250LogicalChannelAckParameters_nonStandard[] = { /* SEQUENCE OF */ + {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, +}; + +static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */ + {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _H2250LogicalChannelAckParameters_nonStandard}, + {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelAckParameters, mediaChannel), + _H245_TransportAddress}, + {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, + offsetof(H2250LogicalChannelAckParameters, mediaControlChannel), + _H245_TransportAddress}, + {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL}, + {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, +}; + +static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */ + {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT, + offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters, + h2250LogicalChannelAckParameters), + _H2250LogicalChannelAckParameters}, +}; + +static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ + {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4, + DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, + reverseLogicalChannelParameters), + _OpenLogicalChannelAck_reverseLogicalChannelParameters}, + {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, + {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, + DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, + forwardMultiplexAckParameters), + _OpenLogicalChannelAck_forwardMultiplexAckParameters}, + {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _ResponseMessage[] = { /* CHOICE */ + {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0, + NULL}, + {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0, + NULL}, + {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0, + NULL}, + {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT, + offsetof(ResponseMessage, openLogicalChannelAck), + _OpenLogicalChannelAck}, + {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0, + NULL}, + {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0, + NULL}, + {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, + {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0, + NULL}, + {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, + {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0, + NULL}, + {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL}, +}; + +static field_t _MultimediaSystemControlMessage[] = { /* CHOICE */ + {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT, + offsetof(MultimediaSystemControlMessage, request), _RequestMessage}, + {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT, + offsetof(MultimediaSystemControlMessage, response), + _ResponseMessage}, + {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL}, + {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL}, +}; + +static field_t _H323_UU_PDU_h245Control[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT, + sizeof(MultimediaSystemControlMessage), + _MultimediaSystemControlMessage} + , +}; + +static field_t _H323_UU_PDU[] = { /* SEQUENCE */ + {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT, + offsetof(H323_UU_PDU, h323_message_body), + _H323_UU_PDU_h323_message_body}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + NULL}, + {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT, + offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control}, + {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT, + 0, NULL}, + {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT, + 0, NULL}, + {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _H323_UserInformation[] = { /* SEQUENCE */ + {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT, + offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU}, + {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _GatekeeperRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(GatekeeperRequest, rasAddress), _TransportAddress}, + {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, + {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _GatekeeperConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(GatekeeperConfirm, rasAddress), _TransportAddress}, + {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0, + NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _RegistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _RegistrationRequest_rasAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _RegistrationRequest_terminalAlias[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _RegistrationRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(RegistrationRequest, callSignalAddress), + _RegistrationRequest_callSignalAddress}, + {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(RegistrationRequest, rasAddress), + _RegistrationRequest_rasAddress}, + {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, + {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _RegistrationRequest_terminalAlias}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0, + _VendorIdentifier}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, + offsetof(RegistrationRequest, timeToLive), NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, + NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _RegistrationConfirm_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _RegistrationConfirm_terminalAlias[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _RegistrationConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(RegistrationConfirm, callSignalAddress), + _RegistrationConfirm_callSignalAddress}, + {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _RegistrationConfirm_terminalAlias}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, + {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, + offsetof(RegistrationConfirm, timeToLive), NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL}, + {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0, + NULL}, + {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0, + NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _UnregistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _UnregistrationRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(UnregistrationRequest, callSignalAddress), + _UnregistrationRequest_callSignalAddress}, + {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL}, + {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _CallModel[] = { /* CHOICE */ + {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL}, + {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, +}; + +static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _AdmissionRequest_destExtraCallInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _AdmissionRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, + {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _AdmissionRequest_destinationInfo}, + {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(AdmissionRequest, destCallSignalAddress), + _TransportAddress}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, + _AdmissionRequest_destExtraCallInfo}, + {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0, + _AdmissionRequest_srcInfo}, + {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, + offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress}, + {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL}, + {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, + {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL}, + {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, + {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _AdmissionConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL}, + {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel}, + {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(AdmissionConfirm, destCallSignalAddress), + _TransportAddress}, + {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, + {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL}, + {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _LocationRequest_destinationInfo[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, +}; + +static field_t _LocationRequest[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0, + _LocationRequest_destinationInfo}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(LocationRequest, replyAddress), _TransportAddress}, + {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, + NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, +}; + +static field_t _LocationConfirm[] = { /* SEQUENCE */ + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(LocationConfirm, callSignalAddress), _TransportAddress}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(LocationConfirm, rasAddress), _TransportAddress}, + {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, + {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, + NULL}, + {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, + 0, NULL}, + {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, + {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _InfoRequestResponse_callSignalAddress[] = { /* SEQUENCE OF */ + {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, + sizeof(TransportAddress), _TransportAddress} + , +}; + +static field_t _InfoRequestResponse[] = { /* SEQUENCE */ + {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, + _NonStandardParameter}, + {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, + {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, + {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, + {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, + offsetof(InfoRequestResponse, rasAddress), _TransportAddress}, + {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, + offsetof(InfoRequestResponse, callSignalAddress), + _InfoRequestResponse_callSignalAddress}, + {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, + {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, + {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, + {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, + {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL}, + {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, +}; + +static field_t _RasMessage[] = { /* CHOICE */ + {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT, + offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest}, + {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT, + offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm}, + {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, + {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT, + offsetof(RasMessage, registrationRequest), _RegistrationRequest}, + {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT, + offsetof(RasMessage, registrationConfirm), _RegistrationConfirm}, + {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, + {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT, + offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest}, + {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL}, + {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, + {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT, + offsetof(RasMessage, admissionRequest), _AdmissionRequest}, + {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT, + offsetof(RasMessage, admissionConfirm), _AdmissionConfirm}, + {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL}, + {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL}, + {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, + {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL}, + {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL}, + {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL}, + {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, + {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT, + offsetof(RasMessage, locationRequest), _LocationRequest}, + {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT, + offsetof(RasMessage, locationConfirm), _LocationConfirm}, + {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL}, + {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL}, + {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT, + offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse}, + {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL}, + {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL}, + {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL}, + {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0, + NULL}, + {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0, + NULL}, + {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL}, + {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL}, + {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0, + NULL}, + {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL}, +}; -- cgit v1.2.3-71-gd317 From 869f37d8e48f3911eb70f38a994feaa8f8380008 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:06 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add IRC helper port Add nf_conntrack port of the IRC conntrack/NAT helper. Since DCC doesn't support IPv6 yet, the helper is still IPv4 only. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_irc.h | 15 ++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_irc.c | 101 +++++++++++ net/netfilter/Kconfig | 15 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_irc.c | 281 +++++++++++++++++++++++++++++ 7 files changed, 419 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_irc.h create mode 100644 net/ipv4/netfilter/nf_nat_irc.c create mode 100644 net/netfilter/nf_conntrack_irc.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_irc.h b/include/linux/netfilter/nf_conntrack_irc.h new file mode 100644 index 000000000000..2ab6b8255911 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_irc.h @@ -0,0 +1,15 @@ +#ifndef _NF_CONNTRACK_IRC_H +#define _NF_CONNTRACK_IRC_H + +#ifdef __KERNEL__ + +#define IRC_PORT 6667 + +extern unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp); + +#endif /* __KERNEL__ */ +#endif /* _NF_CONNTRACK_IRC_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index e14156d1122e..4555f721dfc1 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -500,6 +500,11 @@ config IP_NF_NAT_IRC default IP_NF_NAT if IP_NF_IRC=y default m if IP_NF_IRC=m +config NF_NAT_IRC + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_IRC + config IP_NF_NAT_TFTP tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index bdaba4700e3b..56733c370327 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o +obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c new file mode 100644 index 000000000000..9b8c0daea744 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_irc.c @@ -0,0 +1,101 @@ +/* IRC extension for TCP NAT alteration. + * + * (C) 2000-2001 by Harald Welte + * (C) 2004 Rusty Russell IBM Corporation + * based on a copy of RR's ip_nat_ftp.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IRC (DCC) NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_irc"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) +{ + char buffer[sizeof("4294967296 65635")]; + u_int32_t ip; + u_int16_t port; + unsigned int ret; + + DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", + expect->seq, exp_irc_info->len, ntohl(tcph->seq)); + + /* Reply comes from server. */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = IP_CT_DIR_REPLY; + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { + exp->tuple.dst.u.tcp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip); + sprintf(buffer, "%u %u", ip, port); + DEBUGP("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n", + buffer, NIPQUAD(ip), port); + + ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, + matchoff, matchlen, buffer, + strlen(buffer)); + if (ret != NF_ACCEPT) + nf_conntrack_unexpect_related(exp); + return ret; +} + +static void __exit nf_nat_irc_fini(void) +{ + rcu_assign_pointer(nf_nat_irc_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_irc_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_irc_hook)); + rcu_assign_pointer(nf_nat_irc_hook, help); + return 0; +} + +/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ +static int warn_set(const char *val, struct kernel_param *kp) +{ + printk(KERN_INFO KBUILD_MODNAME + ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + return 0; +} +module_param_call(ports, warn_set, NULL, NULL, 0); + +module_init(nf_nat_irc_init); +module_exit(nf_nat_irc_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index d8f3451c95b6..bd50897d8fbb 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -179,6 +179,21 @@ config NF_CONNTRACK_H323 To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_IRC + tristate "IRC protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + There is a commonly-used extension to IRC called + Direct Client-to-Client Protocol (DCC). This enables users to send + files to each other, and also chat to each other without the need + of a server. DCC Sending is used anywhere you send files over IRC, + and DCC Chat is most commonly used by Eggdrop bots. If you are + using NAT, this extension will enable you to send files and initiate + chats. Note that you do NOT need this extension to get files or + have others initiate chats, or everything else in IRC. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 69b554576b6b..343fd4896406 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -25,6 +25,7 @@ nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o +obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c new file mode 100644 index 000000000000..ed01db634399 --- /dev/null +++ b/net/netfilter/nf_conntrack_irc.c @@ -0,0 +1,281 @@ +/* IRC extension for IP connection tracking, Version 1.21 + * (C) 2000-2002 by Harald Welte + * based on RR's ip_conntrack_ftp.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PORTS 8 +static unsigned short ports[MAX_PORTS]; +static int ports_c; +static unsigned int max_dcc_channels = 8; +static unsigned int dcc_timeout __read_mostly = 300; +/* This is slow, but it's simple. --RR */ +static char *irc_buffer; +static DEFINE_SPINLOCK(irc_buffer_lock); + +unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct nf_conntrack_expect *exp) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_irc_hook); + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_irc"); + +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "port numbers of IRC servers"); +module_param(max_dcc_channels, uint, 0400); +MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per " + "IRC session"); +module_param(dcc_timeout, uint, 0400); +MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); + +static const char *dccprotos[] = { + "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " +}; + +#define MINMATCHLEN 5 + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \ + __FILE__, __FUNCTION__ , ## args) +#else +#define DEBUGP(format, args...) +#endif + +/* tries to get the ip_addr and port out of a dcc command + * return value: -1 on failure, 0 on success + * data pointer to first byte of DCC command data + * data_end pointer to last byte of dcc command data + * ip returns parsed ip of dcc command + * port returns parsed port of dcc command + * ad_beg_p returns pointer to first byte of addr data + * ad_end_p returns pointer to last byte of addr data + */ +static int parse_dcc(char *data, char *data_end, u_int32_t *ip, + u_int16_t *port, char **ad_beg_p, char **ad_end_p) +{ + /* at least 12: "AAAAAAAA P\1\n" */ + while (*data++ != ' ') + if (data > data_end - 12) + return -1; + + *ad_beg_p = data; + *ip = simple_strtoul(data, &data, 10); + + /* skip blanks between ip and port */ + while (*data == ' ') { + if (data >= data_end) + return -1; + data++; + } + + *port = simple_strtoul(data, &data, 10); + *ad_end_p = data; + + return 0; +} + +static int help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + unsigned int dataoff; + struct tcphdr _tcph, *th; + char *data, *data_limit, *ib_ptr; + int dir = CTINFO2DIR(ctinfo); + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple *tuple; + u_int32_t dcc_ip; + u_int16_t dcc_port; + __be16 port; + int i, ret = NF_ACCEPT; + char *addr_beg_p, *addr_end_p; + typeof(nf_nat_irc_hook) nf_nat_irc; + + /* If packet is coming from IRC server */ + if (dir == IP_CT_DIR_REPLY) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) + return NF_ACCEPT; + + /* Not a full tcp header? */ + th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); + if (th == NULL) + return NF_ACCEPT; + + /* No data? */ + dataoff = protoff + th->doff*4; + if (dataoff >= (*pskb)->len) + return NF_ACCEPT; + + spin_lock_bh(&irc_buffer_lock); + ib_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, + irc_buffer); + BUG_ON(ib_ptr == NULL); + + data = ib_ptr; + data_limit = ib_ptr + (*pskb)->len - dataoff; + + /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 + * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ + while (data < data_limit - (19 + MINMATCHLEN)) { + if (memcmp(data, "\1DCC ", 5)) { + data++; + continue; + } + data += 5; + /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ + + DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", + NIPQUAD(iph->saddr), ntohs(th->source), + NIPQUAD(iph->daddr), ntohs(th->dest)); + + for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { + if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { + /* no match */ + continue; + } + data += strlen(dccprotos[i]); + DEBUGP("DCC %s detected\n", dccprotos[i]); + + /* we have at least + * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid + * data left (== 14/13 bytes) */ + if (parse_dcc((char *)data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + DEBUGP("unable to parse dcc command\n"); + continue; + } + DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", + HIPQUAD(dcc_ip), dcc_port); + + /* dcc_ip can be the internal OR external (NAT'ed) IP */ + tuple = &ct->tuplehash[dir].tuple; + if (tuple->src.u3.ip != htonl(dcc_ip) && + tuple->dst.u3.ip != htonl(dcc_ip)) { + if (net_ratelimit()) + printk(KERN_WARNING + "Forged DCC command from " + "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", + NIPQUAD(tuple->src.u3.ip), + HIPQUAD(dcc_ip), dcc_port); + continue; + } + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) { + ret = NF_DROP; + goto out; + } + tuple = &ct->tuplehash[!dir].tuple; + port = htons(dcc_port); + nf_conntrack_expect_init(exp, tuple->src.l3num, + NULL, &tuple->dst.u3, + IPPROTO_TCP, NULL, &port); + + nf_nat_irc = rcu_dereference(nf_nat_irc_hook); + if (nf_nat_irc && ct->status & IPS_NAT_MASK) + ret = nf_nat_irc(pskb, ctinfo, + addr_beg_p - ib_ptr, + addr_end_p - addr_beg_p, + exp); + else if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + nf_conntrack_expect_put(exp); + goto out; + } + } + out: + spin_unlock_bh(&irc_buffer_lock); + return ret; +} + +static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly; +static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly; + +static void nf_conntrack_irc_fini(void); + +static int __init nf_conntrack_irc_init(void) +{ + int i, ret; + char *tmpname; + + if (max_dcc_channels < 1) { + printk("nf_ct_irc: max_dcc_channels must not be zero\n"); + return -EINVAL; + } + + irc_buffer = kmalloc(65536, GFP_KERNEL); + if (!irc_buffer) + return -ENOMEM; + + /* If no port given, default to standard irc port */ + if (ports_c == 0) + ports[ports_c++] = IRC_PORT; + + for (i = 0; i < ports_c; i++) { + irc[i].tuple.src.l3num = AF_INET; + irc[i].tuple.src.u.tcp.port = htons(ports[i]); + irc[i].tuple.dst.protonum = IPPROTO_TCP; + irc[i].mask.src.l3num = 0xFFFF; + irc[i].mask.src.u.tcp.port = htons(0xFFFF); + irc[i].mask.dst.protonum = 0xFF; + irc[i].max_expected = max_dcc_channels; + irc[i].timeout = dcc_timeout; + irc[i].me = THIS_MODULE; + irc[i].help = help; + + tmpname = &irc_names[i][0]; + if (ports[i] == IRC_PORT) + sprintf(tmpname, "irc"); + else + sprintf(tmpname, "irc-%u", i); + irc[i].name = tmpname; + + ret = nf_conntrack_helper_register(&irc[i]); + if (ret) { + printk("nf_ct_irc: failed to register helper " + "for pf: %u port: %u\n", + irc[i].tuple.src.l3num, ports[i]); + nf_conntrack_irc_fini(); + return ret; + } + } + return 0; +} + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void nf_conntrack_irc_fini(void) +{ + int i; + + for (i = 0; i < ports_c; i++) + nf_conntrack_helper_unregister(&irc[i]); + kfree(irc_buffer); +} + +module_init(nf_conntrack_irc_init); +module_exit(nf_conntrack_irc_fini); -- cgit v1.2.3-71-gd317 From f09943fefe6b702e40893d35b4f10fd1064037fe Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:41 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add PPTP helper port Add nf_conntrack port of the PPtP conntrack/NAT helper. Since there seems to be no IPv6-capable PPtP implementation the helper only support IPv4. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_pptp.h | 321 ++++++++++++ include/linux/netfilter/nf_conntrack_proto_gre.h | 112 +++++ include/net/netfilter/ipv4/nf_conntrack_ipv4.h | 2 + include/net/netfilter/nf_conntrack.h | 4 + include/net/netfilter/nf_conntrack_helper.h | 2 + include/net/netfilter/nf_conntrack_tuple.h | 6 + net/ipv4/netfilter/Kconfig | 10 + net/ipv4/netfilter/Makefile | 4 + net/ipv4/netfilter/nf_nat_pptp.c | 315 ++++++++++++ net/ipv4/netfilter/nf_nat_proto_gre.c | 179 +++++++ net/netfilter/Kconfig | 23 + net/netfilter/Makefile | 2 + net/netfilter/nf_conntrack_core.c | 4 + net/netfilter/nf_conntrack_pptp.c | 607 +++++++++++++++++++++++ net/netfilter/nf_conntrack_proto_gre.c | 305 ++++++++++++ 15 files changed, 1896 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_pptp.h create mode 100644 include/linux/netfilter/nf_conntrack_proto_gre.h create mode 100644 net/ipv4/netfilter/nf_nat_pptp.c create mode 100644 net/ipv4/netfilter/nf_nat_proto_gre.c create mode 100644 net/netfilter/nf_conntrack_pptp.c create mode 100644 net/netfilter/nf_conntrack_proto_gre.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_pptp.h b/include/linux/netfilter/nf_conntrack_pptp.h new file mode 100644 index 000000000000..fb049ec11ff2 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_pptp.h @@ -0,0 +1,321 @@ +/* PPTP constants and structs */ +#ifndef _NF_CONNTRACK_PPTP_H +#define _NF_CONNTRACK_PPTP_H + +/* state of the control session */ +enum pptp_ctrlsess_state { + PPTP_SESSION_NONE, /* no session present */ + PPTP_SESSION_ERROR, /* some session error */ + PPTP_SESSION_STOPREQ, /* stop_sess request seen */ + PPTP_SESSION_REQUESTED, /* start_sess request seen */ + PPTP_SESSION_CONFIRMED, /* session established */ +}; + +/* state of the call inside the control session */ +enum pptp_ctrlcall_state { + PPTP_CALL_NONE, + PPTP_CALL_ERROR, + PPTP_CALL_OUT_REQ, + PPTP_CALL_OUT_CONF, + PPTP_CALL_IN_REQ, + PPTP_CALL_IN_REP, + PPTP_CALL_IN_CONF, + PPTP_CALL_CLEAR_REQ, +}; + +/* conntrack private data */ +struct nf_ct_pptp_master { + enum pptp_ctrlsess_state sstate; /* session state */ + enum pptp_ctrlcall_state cstate; /* call state */ + __be16 pac_call_id; /* call id of PAC */ + __be16 pns_call_id; /* call id of PNS */ + + /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack + * and therefore imposes a fixed limit on the number of maps */ + struct nf_ct_gre_keymap *keymap[IP_CT_DIR_MAX]; +}; + +struct nf_nat_pptp { + __be16 pns_call_id; /* NAT'ed PNS call id */ + __be16 pac_call_id; /* NAT'ed PAC call id */ +}; + +#ifdef __KERNEL__ + +#define PPTP_CONTROL_PORT 1723 + +#define PPTP_PACKET_CONTROL 1 +#define PPTP_PACKET_MGMT 2 + +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d + +struct pptp_pkt_hdr { + __u16 packetLength; + __be16 packetType; + __be32 magicCookie; +}; + +/* PptpControlMessageType values */ +#define PPTP_START_SESSION_REQUEST 1 +#define PPTP_START_SESSION_REPLY 2 +#define PPTP_STOP_SESSION_REQUEST 3 +#define PPTP_STOP_SESSION_REPLY 4 +#define PPTP_ECHO_REQUEST 5 +#define PPTP_ECHO_REPLY 6 +#define PPTP_OUT_CALL_REQUEST 7 +#define PPTP_OUT_CALL_REPLY 8 +#define PPTP_IN_CALL_REQUEST 9 +#define PPTP_IN_CALL_REPLY 10 +#define PPTP_IN_CALL_CONNECT 11 +#define PPTP_CALL_CLEAR_REQUEST 12 +#define PPTP_CALL_DISCONNECT_NOTIFY 13 +#define PPTP_WAN_ERROR_NOTIFY 14 +#define PPTP_SET_LINK_INFO 15 + +#define PPTP_MSG_MAX 15 + +/* PptpGeneralError values */ +#define PPTP_ERROR_CODE_NONE 0 +#define PPTP_NOT_CONNECTED 1 +#define PPTP_BAD_FORMAT 2 +#define PPTP_BAD_VALUE 3 +#define PPTP_NO_RESOURCE 4 +#define PPTP_BAD_CALLID 5 +#define PPTP_REMOVE_DEVICE_ERROR 6 + +struct PptpControlHeader { + __be16 messageType; + __u16 reserved; +}; + +/* FramingCapability Bitmap Values */ +#define PPTP_FRAME_CAP_ASYNC 0x1 +#define PPTP_FRAME_CAP_SYNC 0x2 + +/* BearerCapability Bitmap Values */ +#define PPTP_BEARER_CAP_ANALOG 0x1 +#define PPTP_BEARER_CAP_DIGITAL 0x2 + +struct PptpStartSessionRequest { + __be16 protocolVersion; + __u16 reserved1; + __be32 framingCapability; + __be32 bearerCapability; + __be16 maxChannels; + __be16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStartSessionResultCode Values */ +#define PPTP_START_OK 1 +#define PPTP_START_GENERAL_ERROR 2 +#define PPTP_START_ALREADY_CONNECTED 3 +#define PPTP_START_NOT_AUTHORIZED 4 +#define PPTP_START_UNKNOWN_PROTOCOL 5 + +struct PptpStartSessionReply { + __be16 protocolVersion; + __u8 resultCode; + __u8 generalErrorCode; + __be32 framingCapability; + __be32 bearerCapability; + __be16 maxChannels; + __be16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStopReasons */ +#define PPTP_STOP_NONE 1 +#define PPTP_STOP_PROTOCOL 2 +#define PPTP_STOP_LOCAL_SHUTDOWN 3 + +struct PptpStopSessionRequest { + __u8 reason; + __u8 reserved1; + __u16 reserved2; +}; + +/* PptpStopSessionResultCode */ +#define PPTP_STOP_OK 1 +#define PPTP_STOP_GENERAL_ERROR 2 + +struct PptpStopSessionReply { + __u8 resultCode; + __u8 generalErrorCode; + __u16 reserved1; +}; + +struct PptpEchoRequest { + __be32 identNumber; +}; + +/* PptpEchoReplyResultCode */ +#define PPTP_ECHO_OK 1 +#define PPTP_ECHO_GENERAL_ERROR 2 + +struct PptpEchoReply { + __be32 identNumber; + __u8 resultCode; + __u8 generalErrorCode; + __u16 reserved; +}; + +/* PptpFramingType */ +#define PPTP_ASYNC_FRAMING 1 +#define PPTP_SYNC_FRAMING 2 +#define PPTP_DONT_CARE_FRAMING 3 + +/* PptpCallBearerType */ +#define PPTP_ANALOG_TYPE 1 +#define PPTP_DIGITAL_TYPE 2 +#define PPTP_DONT_CARE_BEARER_TYPE 3 + +struct PptpOutCallRequest { + __be16 callID; + __be16 callSerialNumber; + __be32 minBPS; + __be32 maxBPS; + __be32 bearerType; + __be32 framingType; + __be16 packetWindow; + __be16 packetProcDelay; + __be16 phoneNumberLength; + __u16 reserved1; + __u8 phoneNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpCallResultCode */ +#define PPTP_OUTCALL_CONNECT 1 +#define PPTP_OUTCALL_GENERAL_ERROR 2 +#define PPTP_OUTCALL_NO_CARRIER 3 +#define PPTP_OUTCALL_BUSY 4 +#define PPTP_OUTCALL_NO_DIAL_TONE 5 +#define PPTP_OUTCALL_TIMEOUT 6 +#define PPTP_OUTCALL_DONT_ACCEPT 7 + +struct PptpOutCallReply { + __be16 callID; + __be16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 causeCode; + __be32 connectSpeed; + __be16 packetWindow; + __be16 packetProcDelay; + __be32 physChannelID; +}; + +struct PptpInCallRequest { + __be16 callID; + __be16 callSerialNumber; + __be32 callBearerType; + __be32 physChannelID; + __be16 dialedNumberLength; + __be16 dialingNumberLength; + __u8 dialedNumber[64]; + __u8 dialingNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpInCallResultCode */ +#define PPTP_INCALL_ACCEPT 1 +#define PPTP_INCALL_GENERAL_ERROR 2 +#define PPTP_INCALL_DONT_ACCEPT 3 + +struct PptpInCallReply { + __be16 callID; + __be16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 packetWindow; + __be16 packetProcDelay; + __u16 reserved; +}; + +struct PptpInCallConnected { + __be16 peersCallID; + __u16 reserved; + __be32 connectSpeed; + __be16 packetWindow; + __be16 packetProcDelay; + __be32 callFramingType; +}; + +struct PptpClearCallRequest { + __be16 callID; + __u16 reserved; +}; + +struct PptpCallDisconnectNotify { + __be16 callID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 causeCode; + __u16 reserved; + __u8 callStatistics[128]; +}; + +struct PptpWanErrorNotify { + __be16 peersCallID; + __u16 reserved; + __be32 crcErrors; + __be32 framingErrors; + __be32 hardwareOverRuns; + __be32 bufferOverRuns; + __be32 timeoutErrors; + __be32 alignmentErrors; +}; + +struct PptpSetLinkInfo { + __be16 peersCallID; + __u16 reserved; + __be32 sendAccm; + __be32 recvAccm; +}; + +union pptp_ctrl_union { + struct PptpStartSessionRequest sreq; + struct PptpStartSessionReply srep; + struct PptpStopSessionRequest streq; + struct PptpStopSessionReply strep; + struct PptpOutCallRequest ocreq; + struct PptpOutCallReply ocack; + struct PptpInCallRequest icreq; + struct PptpInCallReply icack; + struct PptpInCallConnected iccon; + struct PptpClearCallRequest clrreq; + struct PptpCallDisconnectNotify disc; + struct PptpWanErrorNotify wanerr; + struct PptpSetLinkInfo setlink; +}; + +/* crap needed for nf_conntrack_compat.h */ +struct nf_conn; +struct nf_conntrack_expect; +enum ip_conntrack_info; + +extern int +(*nf_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern int +(*nf_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern void +(*nf_nat_pptp_hook_exp_gre)(struct nf_conntrack_expect *exp_orig, + struct nf_conntrack_expect *exp_reply); + +extern void +(*nf_nat_pptp_hook_expectfn)(struct nf_conn *ct, + struct nf_conntrack_expect *exp); + +#endif /* __KERNEL__ */ +#endif /* _NF_CONNTRACK_PPTP_H */ diff --git a/include/linux/netfilter/nf_conntrack_proto_gre.h b/include/linux/netfilter/nf_conntrack_proto_gre.h new file mode 100644 index 000000000000..4e6bbce04ff8 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_proto_gre.h @@ -0,0 +1,112 @@ +#ifndef _CONNTRACK_PROTO_GRE_H +#define _CONNTRACK_PROTO_GRE_H +#include + +/* GRE PROTOCOL HEADER */ + +/* GRE Version field */ +#define GRE_VERSION_1701 0x0 +#define GRE_VERSION_PPTP 0x1 + +/* GRE Protocol field */ +#define GRE_PROTOCOL_PPTP 0x880B + +/* GRE Flags */ +#define GRE_FLAG_C 0x80 +#define GRE_FLAG_R 0x40 +#define GRE_FLAG_K 0x20 +#define GRE_FLAG_S 0x10 +#define GRE_FLAG_A 0x80 + +#define GRE_IS_C(f) ((f)&GRE_FLAG_C) +#define GRE_IS_R(f) ((f)&GRE_FLAG_R) +#define GRE_IS_K(f) ((f)&GRE_FLAG_K) +#define GRE_IS_S(f) ((f)&GRE_FLAG_S) +#define GRE_IS_A(f) ((f)&GRE_FLAG_A) + +/* GRE is a mess: Four different standards */ +struct gre_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 rec:3, + srr:1, + seq:1, + key:1, + routing:1, + csum:1, + version:3, + reserved:4, + ack:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 csum:1, + routing:1, + key:1, + seq:1, + srr:1, + rec:3, + ack:1, + reserved:4, + version:3; +#else +#error "Adjust your defines" +#endif + __be16 protocol; +}; + +/* modified GRE header for PPTP */ +struct gre_hdr_pptp { + __u8 flags; /* bitfield */ + __u8 version; /* should be GRE_VERSION_PPTP */ + __be16 protocol; /* should be GRE_PROTOCOL_PPTP */ + __be16 payload_len; /* size of ppp payload, not inc. gre header */ + __be16 call_id; /* peer's call_id for this session */ + __be32 seq; /* sequence number. Present if S==1 */ + __be32 ack; /* seq number of highest packet recieved by */ + /* sender in this session */ +}; + +struct nf_ct_gre { + unsigned int stream_timeout; + unsigned int timeout; +}; + +#ifdef __KERNEL__ +#include + +struct nf_conn; + +/* structure for original <-> reply keymap */ +struct nf_ct_gre_keymap { + struct list_head list; + struct nf_conntrack_tuple tuple; +}; + +/* add new tuple->key_reply pair to keymap */ +int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, + struct nf_conntrack_tuple *t); + +/* delete keymap entries */ +void nf_ct_gre_keymap_destroy(struct nf_conn *ct); + +/* get pointer to gre key, if present */ +static inline __be32 *gre_key(struct gre_hdr *greh) +{ + if (!greh->key) + return NULL; + if (greh->csum || greh->routing) + return (__be32 *)(greh+sizeof(*greh)+4); + return (__be32 *)(greh+sizeof(*greh)); +} + +/* get pointer ot gre csum, if present */ +static inline __sum16 *gre_csum(struct gre_hdr *greh) +{ + if (!greh->csum) + return NULL; + return (__sum16 *)(greh+sizeof(*greh)); +} + +extern void nf_ct_gre_keymap_flush(void); +extern void nf_nat_need_gre(void); + +#endif /* __KERNEL__ */ +#endif /* _CONNTRACK_PROTO_GRE_H */ diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h index a1c57ee0a4fa..1401ccc051c4 100644 --- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -11,10 +11,12 @@ #ifdef CONFIG_NF_NAT_NEEDED #include +#include /* per conntrack: nat application helper private data */ union nf_conntrack_nat_help { /* insert nat helper private data here */ + struct nf_nat_pptp nat_pptp_info; }; struct nf_conn_nat { diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 1646076933b1..032b36a0e378 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -33,6 +34,7 @@ union nf_conntrack_proto { struct ip_ct_tcp tcp; struct ip_ct_icmp icmp; struct nf_ct_icmpv6 icmpv6; + struct nf_ct_gre gre; }; union nf_conntrack_expect_proto { @@ -41,12 +43,14 @@ union nf_conntrack_expect_proto { /* Add protocol helper include file here */ #include +#include #include /* per conntrack: application helper private data */ union nf_conntrack_help { /* insert conntrack helper private data (master) here */ struct nf_ct_ftp_master ct_ftp_info; + struct nf_ct_pptp_master ct_pptp_info; struct nf_ct_h323_master ct_h323_info; }; diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index fbba9e8b95fc..8c72ac9f0ab8 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -34,6 +34,8 @@ struct nf_conntrack_helper struct nf_conn *ct, enum ip_conntrack_info conntrackinfo); + void (*destroy)(struct nf_conn *ct); + int (*to_nfattr)(struct sk_buff *skb, const struct nf_conn *ct); }; diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index c96a9c576736..5d72b16e876f 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -49,6 +49,9 @@ union nf_conntrack_man_proto struct { __be16 port; } sctp; + struct { + __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */ + } gre; }; /* The manipulable part of the tuple. */ @@ -84,6 +87,9 @@ struct nf_conntrack_tuple struct { __be16 port; } sctp; + struct { + __be16 key; + } gre; } u; /* The protocol. */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 4555f721dfc1..c3327ac024de 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -484,6 +484,10 @@ config IP_NF_NAT_SNMP_BASIC # '&&' (6) # # (6) Returns the result of min(/expr/, /expr/). +config NF_NAT_PROTO_GRE + tristate + depends on NF_NAT && NF_CT_PROTO_GRE + config IP_NF_NAT_FTP tristate depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT @@ -528,6 +532,12 @@ config IP_NF_NAT_PPTP default IP_NF_NAT if IP_NF_PPTP=y default m if IP_NF_PPTP=m +config NF_NAT_PPTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_PPTP + select NF_NAT_PROTO_GRE + config IP_NF_NAT_H323 tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 56733c370327..ef33ff2cdda9 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -54,6 +54,10 @@ obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o +obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o + +# NAT protocols (nf_nat) +obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c new file mode 100644 index 000000000000..0ae45b79a4eb --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_pptp.c @@ -0,0 +1,315 @@ +/* + * nf_nat_pptp.c + * + * NAT support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * TODO: - NAT to a unique tuple, not to TCP source port + * (needs netfilter tuple reservation) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NF_NAT_PPTP_VERSION "3.0" + +#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off))) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); +MODULE_ALIAS("ip_nat_pptp"); + +#if 0 +extern const char *pptp_msg_name[]; +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(format, args...) +#endif + +static void pptp_nat_expected(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_conn *master = ct->master; + struct nf_conntrack_expect *other_exp; + struct nf_conntrack_tuple t; + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + struct ip_nat_range range; + + ct_pptp_info = &nfct_help(master)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; + + /* And here goes the grand finale of corrosion... */ + if (exp->dir == IP_CT_DIR_ORIGINAL) { + DEBUGP("we are PNS->PAC\n"); + /* therefore, build tuple for PAC->PNS */ + t.src.l3num = AF_INET; + t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip; + t.src.u.gre.key = ct_pptp_info->pac_call_id; + t.dst.u3.ip = master->tuplehash[!exp->dir].tuple.dst.u3.ip; + t.dst.u.gre.key = ct_pptp_info->pns_call_id; + t.dst.protonum = IPPROTO_GRE; + } else { + DEBUGP("we are PAC->PNS\n"); + /* build tuple for PNS->PAC */ + t.src.l3num = AF_INET; + t.src.u3.ip = master->tuplehash[exp->dir].tuple.src.u3.ip; + t.src.u.gre.key = nat_pptp_info->pns_call_id; + t.dst.u3.ip = master->tuplehash[exp->dir].tuple.dst.u3.ip; + t.dst.u.gre.key = nat_pptp_info->pac_call_id; + t.dst.protonum = IPPROTO_GRE; + } + + DEBUGP("trying to unexpect other dir: "); + NF_CT_DUMP_TUPLE(&t); + other_exp = nf_conntrack_expect_find_get(&t); + if (other_exp) { + nf_conntrack_unexpect_related(other_exp); + nf_conntrack_expect_put(other_exp); + DEBUGP("success\n"); + } else { + DEBUGP("not found!\n"); + } + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + if (exp->dir == IP_CT_DIR_ORIGINAL) { + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.min = range.max = exp->saved_proto; + } + /* hook doesn't matter, but it has to do source manip */ + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + + /* For DST manip, map port here to where it's expected. */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; + if (exp->dir == IP_CT_DIR_REPLY) { + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.min = range.max = exp->saved_proto; + } + /* hook doesn't matter, but it has to do destination manip */ + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); +} + +/* outbound packets == from PNS to PAC */ +static int +pptp_outbound_pkt(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) + +{ + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + u_int16_t msg; + __be16 new_callid; + unsigned int cid_off; + + ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + + new_callid = ct_pptp_info->pns_call_id; + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REQUEST: + cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); + /* FIXME: ideally we would want to reserve a call ID + * here. current netfilter NAT core is not able to do + * this :( For now we use TCP source port. This breaks + * multiple calls within one control session */ + + /* save original call ID in nat_info */ + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; + + /* don't use tcph->source since we are at a DSTmanip + * hook (e.g. PREROUTING) and pkt is not mangled yet */ + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; + + /* save new call ID in ct info */ + ct_pptp_info->pns_call_id = new_callid; + break; + case PPTP_IN_CALL_REPLY: + cid_off = offsetof(union pptp_ctrl_union, icack.callID); + break; + case PPTP_CALL_CLEAR_REQUEST: + cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); + break; + default: + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, + (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + case PPTP_SET_LINK_INFO: + /* only need to NAT in case PAC is behind NAT box */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass + * down to here */ + DEBUGP("altering call id from 0x%04x to 0x%04x\n", + ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid)); + + /* mangle packet */ + if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + cid_off + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader), + sizeof(new_callid), (char *)&new_callid, + sizeof(new_callid)) == 0) + return NF_DROP; + return NF_ACCEPT; +} + +static void +pptp_exp_gre(struct nf_conntrack_expect *expect_orig, + struct nf_conntrack_expect *expect_reply) +{ + struct nf_conn *ct = expect_orig->master; + struct nf_ct_pptp_master *ct_pptp_info; + struct nf_nat_pptp *nat_pptp_info; + + ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + + /* save original PAC call ID in nat_info */ + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; + + /* alter expectation for PNS->PAC direction */ + expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; + expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; + expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; + expect_orig->dir = IP_CT_DIR_ORIGINAL; + + /* alter expectation for PAC->PNS direction */ + expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; + expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; + expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; + expect_reply->dir = IP_CT_DIR_REPLY; +} + +/* inbound packets == from PAC to PNS */ +static int +pptp_inbound_pkt(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) +{ + struct nf_nat_pptp *nat_pptp_info; + u_int16_t msg; + __be16 new_pcid; + unsigned int pcid_off; + + nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; + new_pcid = nat_pptp_info->pns_call_id; + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REPLY: + pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); + break; + case PPTP_IN_CALL_CONNECT: + pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); + break; + case PPTP_IN_CALL_REQUEST: + /* only need to nat in case PAC is behind NAT box */ + return NF_ACCEPT; + case PPTP_WAN_ERROR_NOTIFY: + pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID); + break; + case PPTP_CALL_DISCONNECT_NOTIFY: + pcid_off = offsetof(union pptp_ctrl_union, disc.callID); + break; + case PPTP_SET_LINK_INFO: + pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID); + break; + default: + DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, + * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ + + /* mangle packet */ + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", + ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid)); + + if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, + pcid_off + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader), + sizeof(new_pcid), (char *)&new_pcid, + sizeof(new_pcid)) == 0) + return NF_DROP; + return NF_ACCEPT; +} + +static int __init nf_nat_helper_pptp_init(void) +{ + nf_nat_need_gre(); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_outbound)); + rcu_assign_pointer(nf_nat_pptp_hook_outbound, pptp_outbound_pkt); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_inbound)); + rcu_assign_pointer(nf_nat_pptp_hook_inbound, pptp_inbound_pkt); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_exp_gre)); + rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, pptp_exp_gre); + + BUG_ON(rcu_dereference(nf_nat_pptp_hook_expectfn)); + rcu_assign_pointer(nf_nat_pptp_hook_expectfn, pptp_nat_expected); + return 0; +} + +static void __exit nf_nat_helper_pptp_fini(void) +{ + rcu_assign_pointer(nf_nat_pptp_hook_expectfn, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_inbound, NULL); + rcu_assign_pointer(nf_nat_pptp_hook_outbound, NULL); + synchronize_rcu(); +} + +module_init(nf_nat_helper_pptp_init); +module_exit(nf_nat_helper_pptp_fini); diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c new file mode 100644 index 000000000000..d3de579e09d2 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -0,0 +1,179 @@ +/* + * nf_nat_proto_gre.c + * + * NAT protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(x, args...) +#endif + +/* is key in given range between min and max */ +static int +gre_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 key; + + if (maniptype == IP_NAT_MANIP_SRC) + key = tuple->src.u.gre.key; + else + key = tuple->dst.u.gre.key; + + return ntohs(key) >= ntohs(min->gre.key) && + ntohs(key) <= ntohs(max->gre.key); +} + +/* generate unique tuple ... */ +static int +gre_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *conntrack) +{ + static u_int16_t key; + __be16 *keyptr; + unsigned int min, i, range_size; + + if (maniptype == IP_NAT_MANIP_SRC) + keyptr = &tuple->src.u.gre.key; + else + keyptr = &tuple->dst.u.gre.key; + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + DEBUGP("%p: NATing GRE PPTP\n", conntrack); + min = 1; + range_size = 0xffff; + } else { + min = ntohs(range->min.gre.key); + range_size = ntohs(range->max.gre.key) - min + 1; + } + + DEBUGP("min = %u, range_size = %u\n", min, range_size); + + for (i = 0; i < range_size; i++, key++) { + *keyptr = htons(min + key % range_size); + if (!nf_nat_used_tuple(tuple, conntrack)) + return 1; + } + + DEBUGP("%p: no NAT mapping\n", conntrack); + return 0; +} + +/* manipulate a GRE packet according to maniptype */ +static int +gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct gre_hdr *greh; + struct gre_hdr_pptp *pgreh; + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + unsigned int hdroff = iphdroff + iph->ihl * 4; + + /* pgreh includes two optional 32bit fields which are not required + * to be there. That's where the magic '8' comes from */ + if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh) - 8)) + return 0; + + greh = (void *)(*pskb)->data + hdroff; + pgreh = (struct gre_hdr_pptp *)greh; + + /* we only have destination manip of a packet, since 'source key' + * is not present in the packet itself */ + if (maniptype != IP_NAT_MANIP_DST) + return 1; + switch (greh->version) { + case 0: + if (!greh->key) { + DEBUGP("can't nat GRE w/o key\n"); + break; + } + if (greh->csum) { + /* FIXME: Never tested this code... */ + nf_proto_csum_replace4(gre_csum(greh), *pskb, + *(gre_key(greh)), + tuple->dst.u.gre.key, 0); + } + *(gre_key(greh)) = tuple->dst.u.gre.key; + break; + case GRE_VERSION_PPTP: + DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key)); + pgreh->call_id = tuple->dst.u.gre.key; + break; + default: + DEBUGP("can't nat unknown GRE version\n"); + return 0; + } + return 1; +} + +static struct nf_nat_protocol gre __read_mostly = { + .name = "GRE", + .protonum = IPPROTO_GRE, + .manip_pkt = gre_manip_pkt, + .in_range = gre_in_range, + .unique_tuple = gre_unique_tuple, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = nf_nat_port_range_to_nfattr, + .nfattr_to_range = nf_nat_port_nfattr_to_range, +#endif +}; + +int __init nf_nat_proto_gre_init(void) +{ + return nf_nat_protocol_register(&gre); +} + +void __exit nf_nat_proto_gre_fini(void) +{ + nf_nat_protocol_unregister(&gre); +} + +module_init(nf_nat_proto_gre_init); +module_exit(nf_nat_proto_gre_fini); + +void nf_nat_need_gre(void) +{ + return; +} +EXPORT_SYMBOL_GPL(nf_nat_need_gre); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index d1a365d83c53..6b2eb26ae03f 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -120,6 +120,10 @@ config NF_CONNTRACK_EVENTS If unsure, say `N'. +config NF_CT_PROTO_GRE + tristate + depends on EXPERIMENTAL && NF_CONNTRACK + config NF_CT_PROTO_SCTP tristate 'SCTP protocol on new connection tracking support (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK @@ -213,6 +217,25 @@ config NF_CONNTRACK_NETBIOS_NS To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_PPTP + tristate "PPtP protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + select NF_CT_PROTO_GRE + help + This module adds support for PPTP (Point to Point Tunnelling + Protocol, RFC2637) connection tracking and NAT. + + If you are running PPTP sessions over a stateful firewall or NAT + box, you may want to enable this feature. + + Please note that not all PPTP modes of operation are supported yet. + Specifically these limitations exist: + - Blindy assumes that control connections are always established + in PNS->PAC direction. This is a violation of RFC2637. + - Only supports a single call within each session + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 67144b2af647..897bed4cbd79 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o # SCTP protocol connection tracking +obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o # netlink interface for nf_conntrack @@ -27,6 +28,7 @@ obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o +obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index aa8beabfeebb..ed756c928bc4 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -300,6 +300,7 @@ static void destroy_conntrack(struct nf_conntrack *nfct) { struct nf_conn *ct = (struct nf_conn *)nfct; + struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; @@ -310,6 +311,9 @@ destroy_conntrack(struct nf_conntrack *nfct) nf_conntrack_event(IPCT_DESTROY, ct); set_bit(IPS_DYING_BIT, &ct->status); + if (help && help->helper && help->helper->destroy) + help->helper->destroy(ct); + /* To make sure we don't get any weird locking issues here: * destroy_conntrack() MUST NOT be called with a write lock * to nf_conntrack_lock!!! -HW */ diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c new file mode 100644 index 000000000000..f0ff00e0d052 --- /dev/null +++ b/net/netfilter/nf_conntrack_pptp.c @@ -0,0 +1,607 @@ +/* + * Connection tracking support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * Limitations: + * - We blindly assume that control connections are always + * established in PNS->PAC direction. This is a violation + * of RFFC2673 + * - We can only support one single call within each session + * TODO: + * - testing of incoming PPTP calls + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define NF_CT_PPTP_VERSION "3.1" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); +MODULE_ALIAS("ip_conntrack_pptp"); + +static DEFINE_SPINLOCK(nf_pptp_lock); + +int +(*nf_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_outbound); + +int +(*nf_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_inbound); + +void +(*nf_nat_pptp_hook_exp_gre)(struct nf_conntrack_expect *expect_orig, + struct nf_conntrack_expect *expect_reply) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_exp_gre); + +void +(*nf_nat_pptp_hook_expectfn)(struct nf_conn *ct, + struct nf_conntrack_expect *exp) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn); + +#if 0 +/* PptpControlMessageType names */ +const char *pptp_msg_name[] = { + "UNKNOWN_MESSAGE", + "START_SESSION_REQUEST", + "START_SESSION_REPLY", + "STOP_SESSION_REQUEST", + "STOP_SESSION_REPLY", + "ECHO_REQUEST", + "ECHO_REPLY", + "OUT_CALL_REQUEST", + "OUT_CALL_REPLY", + "IN_CALL_REQUEST", + "IN_CALL_REPLY", + "IN_CALL_CONNECT", + "CALL_CLEAR_REQUEST", + "CALL_DISCONNECT_NOTIFY", + "WAN_ERROR_NOTIFY", + "SET_LINK_INFO" +}; +EXPORT_SYMBOL(pptp_msg_name); +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) +#else +#define DEBUGP(format, args...) +#endif + +#define SECS *HZ +#define MINS * 60 SECS +#define HOURS * 60 MINS + +#define PPTP_GRE_TIMEOUT (10 MINS) +#define PPTP_GRE_STREAM_TIMEOUT (5 HOURS) + +static void pptp_expectfn(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + typeof(nf_nat_pptp_hook_expectfn) nf_nat_pptp_expectfn; + DEBUGP("increasing timeouts\n"); + + /* increase timeout of GRE data channel conntrack entry */ + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; + + /* Can you see how rusty this code is, compared with the pre-2.6.11 + * one? That's what happened to my shiny newnat of 2002 ;( -HW */ + + rcu_read_lock(); + nf_nat_pptp_expectfn = rcu_dereference(nf_nat_pptp_hook_expectfn); + if (nf_nat_pptp_expectfn && ct->status & IPS_NAT_MASK) + nf_nat_pptp_expectfn(ct, exp); + else { + struct nf_conntrack_tuple inv_t; + struct nf_conntrack_expect *exp_other; + + /* obviously this tuple inversion only works until you do NAT */ + nf_ct_invert_tuplepr(&inv_t, &exp->tuple); + DEBUGP("trying to unexpect other dir: "); + NF_CT_DUMP_TUPLE(&inv_t); + + exp_other = nf_conntrack_expect_find_get(&inv_t); + if (exp_other) { + /* delete other expectation. */ + DEBUGP("found\n"); + nf_conntrack_unexpect_related(exp_other); + nf_conntrack_expect_put(exp_other); + } else { + DEBUGP("not found\n"); + } + } + rcu_read_unlock(); +} + +static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conntrack_expect *exp; + struct nf_conn *sibling; + + DEBUGP("trying to timeout ct or exp for tuple "); + NF_CT_DUMP_TUPLE(t); + + h = nf_conntrack_find_get(t, NULL); + if (h) { + sibling = nf_ct_tuplehash_to_ctrack(h); + DEBUGP("setting timeout of conntrack %p to 0\n", sibling); + sibling->proto.gre.timeout = 0; + sibling->proto.gre.stream_timeout = 0; + if (del_timer(&sibling->timeout)) + sibling->timeout.function((unsigned long)sibling); + nf_ct_put(sibling); + return 1; + } else { + exp = nf_conntrack_expect_find_get(t); + if (exp) { + DEBUGP("unexpect_related of expect %p\n", exp); + nf_conntrack_unexpect_related(exp); + nf_conntrack_expect_put(exp); + return 1; + } + } + return 0; +} + +/* timeout GRE data connections */ +static void pptp_destroy_siblings(struct nf_conn *ct) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_tuple t; + + nf_ct_gre_keymap_destroy(ct); + + /* try original (pns->pac) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id; + t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id; + if (!destroy_sibling_or_exp(&t)) + DEBUGP("failed to timeout original pns->pac ct/exp\n"); + + /* try reply (pac->pns) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id; + t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id; + if (!destroy_sibling_or_exp(&t)) + DEBUGP("failed to timeout reply pac->pns ct/exp\n"); +} + +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ +static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid) +{ + struct nf_conntrack_expect *exp_orig, *exp_reply; + enum ip_conntrack_dir dir; + int ret = 1; + typeof(nf_nat_pptp_hook_exp_gre) nf_nat_pptp_exp_gre; + + exp_orig = nf_conntrack_expect_alloc(ct); + if (exp_orig == NULL) + goto out; + + exp_reply = nf_conntrack_expect_alloc(ct); + if (exp_reply == NULL) + goto out_put_orig; + + /* original direction, PNS->PAC */ + dir = IP_CT_DIR_ORIGINAL; + nf_conntrack_expect_init(exp_orig, ct->tuplehash[dir].tuple.src.l3num, + &ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[dir].tuple.dst.u3, + IPPROTO_GRE, &peer_callid, &callid); + exp_orig->expectfn = pptp_expectfn; + + /* reply direction, PAC->PNS */ + dir = IP_CT_DIR_REPLY; + nf_conntrack_expect_init(exp_reply, ct->tuplehash[dir].tuple.src.l3num, + &ct->tuplehash[dir].tuple.src.u3, + &ct->tuplehash[dir].tuple.dst.u3, + IPPROTO_GRE, &callid, &peer_callid); + exp_reply->expectfn = pptp_expectfn; + + nf_nat_pptp_exp_gre = rcu_dereference(nf_nat_pptp_hook_exp_gre); + if (nf_nat_pptp_exp_gre && ct->status & IPS_NAT_MASK) + nf_nat_pptp_exp_gre(exp_orig, exp_reply); + if (nf_conntrack_expect_related(exp_orig) != 0) + goto out_put_both; + if (nf_conntrack_expect_related(exp_reply) != 0) + goto out_unexpect_orig; + + /* Add GRE keymap entries */ + if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_ORIGINAL, &exp_orig->tuple) != 0) + goto out_unexpect_both; + if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_REPLY, &exp_reply->tuple) != 0) { + nf_ct_gre_keymap_destroy(ct); + goto out_unexpect_both; + } + ret = 0; + +out_put_both: + nf_conntrack_expect_put(exp_reply); +out_put_orig: + nf_conntrack_expect_put(exp_orig); +out: + return ret; + +out_unexpect_both: + nf_conntrack_unexpect_related(exp_reply); +out_unexpect_orig: + nf_conntrack_unexpect_related(exp_orig); + goto out_put_both; +} + +static inline int +pptp_inbound_pkt(struct sk_buff **pskb, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq, + unsigned int reqlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; + u_int16_t msg; + __be16 cid = 0, pcid = 0; + typeof(nf_nat_pptp_hook_inbound) nf_nat_pptp_inbound; + + msg = ntohs(ctlh->messageType); + DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); + + switch (msg) { + case PPTP_START_SESSION_REPLY: + /* server confirms new control session */ + if (info->sstate < PPTP_SESSION_REQUESTED) + goto invalid; + if (pptpReq->srep.resultCode == PPTP_START_OK) + info->sstate = PPTP_SESSION_CONFIRMED; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_STOP_SESSION_REPLY: + /* server confirms end of control session */ + if (info->sstate > PPTP_SESSION_STOPREQ) + goto invalid; + if (pptpReq->strep.resultCode == PPTP_STOP_OK) + info->sstate = PPTP_SESSION_NONE; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_OUT_CALL_REPLY: + /* server accepted call, we now expect GRE frames */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + if (info->cstate != PPTP_CALL_OUT_REQ && + info->cstate != PPTP_CALL_OUT_CONF) + goto invalid; + + cid = pptpReq->ocack.callID; + pcid = pptpReq->ocack.peersCallID; + if (info->pns_call_id != pcid) + goto invalid; + DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], + ntohs(cid), ntohs(pcid)); + + if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) { + info->cstate = PPTP_CALL_OUT_CONF; + info->pac_call_id = cid; + exp_gre(ct, cid, pcid); + } else + info->cstate = PPTP_CALL_NONE; + break; + + case PPTP_IN_CALL_REQUEST: + /* server tells us about incoming call request */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + + cid = pptpReq->icreq.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); + info->cstate = PPTP_CALL_IN_REQ; + info->pac_call_id = cid; + break; + + case PPTP_IN_CALL_CONNECT: + /* server tells us about incoming call established */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + if (info->cstate != PPTP_CALL_IN_REP && + info->cstate != PPTP_CALL_IN_CONF) + goto invalid; + + pcid = pptpReq->iccon.peersCallID; + cid = info->pac_call_id; + + if (info->pns_call_id != pcid) + goto invalid; + + DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid)); + info->cstate = PPTP_CALL_IN_CONF; + + /* we expect a GRE connection from PAC to PNS */ + exp_gre(ct, cid, pcid); + break; + + case PPTP_CALL_DISCONNECT_NOTIFY: + /* server confirms disconnect */ + cid = pptpReq->disc.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); + info->cstate = PPTP_CALL_NONE; + + /* untrack this call id, unexpect GRE packets */ + pptp_destroy_siblings(ct); + break; + + case PPTP_WAN_ERROR_NOTIFY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + + default: + goto invalid; + } + + nf_nat_pptp_inbound = rcu_dereference(nf_nat_pptp_hook_inbound); + if (nf_nat_pptp_inbound && ct->status & IPS_NAT_MASK) + return nf_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq); + return NF_ACCEPT; + +invalid: + DEBUGP("invalid %s: type=%d cid=%u pcid=%u " + "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", + msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], + msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, + ntohs(info->pns_call_id), ntohs(info->pac_call_id)); + return NF_ACCEPT; +} + +static inline int +pptp_outbound_pkt(struct sk_buff **pskb, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq, + unsigned int reqlen, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; + u_int16_t msg; + __be16 cid = 0, pcid = 0; + typeof(nf_nat_pptp_hook_outbound) nf_nat_pptp_outbound; + + msg = ntohs(ctlh->messageType); + DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); + + switch (msg) { + case PPTP_START_SESSION_REQUEST: + /* client requests for new control session */ + if (info->sstate != PPTP_SESSION_NONE) + goto invalid; + info->sstate = PPTP_SESSION_REQUESTED; + break; + + case PPTP_STOP_SESSION_REQUEST: + /* client requests end of control session */ + info->sstate = PPTP_SESSION_STOPREQ; + break; + + case PPTP_OUT_CALL_REQUEST: + /* client initiating connection to server */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + info->cstate = PPTP_CALL_OUT_REQ; + /* track PNS call id */ + cid = pptpReq->ocreq.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); + info->pns_call_id = cid; + break; + + case PPTP_IN_CALL_REPLY: + /* client answers incoming call */ + if (info->cstate != PPTP_CALL_IN_REQ && + info->cstate != PPTP_CALL_IN_REP) + goto invalid; + + cid = pptpReq->icack.callID; + pcid = pptpReq->icack.peersCallID; + if (info->pac_call_id != pcid) + goto invalid; + DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg], + ntohs(cid), ntohs(pcid)); + + if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) { + /* part two of the three-way handshake */ + info->cstate = PPTP_CALL_IN_REP; + info->pns_call_id = cid; + } else + info->cstate = PPTP_CALL_NONE; + break; + + case PPTP_CALL_CLEAR_REQUEST: + /* client requests hangup of call */ + if (info->sstate != PPTP_SESSION_CONFIRMED) + goto invalid; + /* FUTURE: iterate over all calls and check if + * call ID is valid. We don't do this without newnat, + * because we only know about last call */ + info->cstate = PPTP_CALL_CLEAR_REQ; + break; + + case PPTP_SET_LINK_INFO: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + + default: + goto invalid; + } + + nf_nat_pptp_outbound = rcu_dereference(nf_nat_pptp_hook_outbound); + if (nf_nat_pptp_outbound && ct->status & IPS_NAT_MASK) + return nf_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq); + return NF_ACCEPT; + +invalid: + DEBUGP("invalid %s: type=%d cid=%u pcid=%u " + "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", + msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], + msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, + ntohs(info->pns_call_id), ntohs(info->pac_call_id)); + return NF_ACCEPT; +} + +static const unsigned int pptp_msg_size[] = { + [PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest), + [PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply), + [PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest), + [PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply), + [PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest), + [PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply), + [PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest), + [PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply), + [PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected), + [PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest), + [PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify), + [PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify), + [PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo), +}; + +/* track caller id inside control connection, call expect_related */ +static int +conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) + +{ + int dir = CTINFO2DIR(ctinfo); + struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; + struct tcphdr _tcph, *tcph; + struct pptp_pkt_hdr _pptph, *pptph; + struct PptpControlHeader _ctlh, *ctlh; + union pptp_ctrl_union _pptpReq, *pptpReq; + unsigned int tcplen = (*pskb)->len - protoff; + unsigned int datalen, reqlen, nexthdr_off; + int oldsstate, oldcstate; + int ret; + u_int16_t msg; + + /* don't do any tracking before tcp handshake complete */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) + return NF_ACCEPT; + + nexthdr_off = protoff; + tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); + BUG_ON(!tcph); + nexthdr_off += tcph->doff * 4; + datalen = tcplen - tcph->doff * 4; + + pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); + if (!pptph) { + DEBUGP("no full PPTP header, can't track\n"); + return NF_ACCEPT; + } + nexthdr_off += sizeof(_pptph); + datalen -= sizeof(_pptph); + + /* if it's not a control message we can't do anything with it */ + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { + DEBUGP("not a control packet\n"); + return NF_ACCEPT; + } + + ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); + if (!ctlh) + return NF_ACCEPT; + nexthdr_off += sizeof(_ctlh); + datalen -= sizeof(_ctlh); + + reqlen = datalen; + msg = ntohs(ctlh->messageType); + if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg]) + return NF_ACCEPT; + if (reqlen > sizeof(*pptpReq)) + reqlen = sizeof(*pptpReq); + + pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); + if (!pptpReq) + return NF_ACCEPT; + + oldsstate = info->sstate; + oldcstate = info->cstate; + + spin_lock_bh(&nf_pptp_lock); + + /* FIXME: We just blindly assume that the control connection is always + * established from PNS->PAC. However, RFC makes no guarantee */ + if (dir == IP_CT_DIR_ORIGINAL) + /* client -> server (PNS -> PAC) */ + ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, + ctinfo); + else + /* server -> client (PAC -> PNS) */ + ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, + ctinfo); + DEBUGP("sstate: %d->%d, cstate: %d->%d\n", + oldsstate, info->sstate, oldcstate, info->cstate); + spin_unlock_bh(&nf_pptp_lock); + + return ret; +} + +/* control protocol helper */ +static struct nf_conntrack_helper pptp __read_mostly = { + .name = "pptp", + .me = THIS_MODULE, + .max_expected = 2, + .timeout = 5 * 60, + .tuple.src.l3num = AF_INET, + .tuple.src.u.tcp.port = __constant_htons(PPTP_CONTROL_PORT), + .tuple.dst.protonum = IPPROTO_TCP, + .mask.src.l3num = 0xffff, + .mask.src.u.tcp.port = __constant_htons(0xffff), + .mask.dst.protonum = 0xff, + .help = conntrack_pptp_help, + .destroy = pptp_destroy_siblings, +}; + +static int __init nf_conntrack_pptp_init(void) +{ + return nf_conntrack_helper_register(&pptp); +} + +static void __exit nf_conntrack_pptp_fini(void) +{ + nf_conntrack_helper_unregister(&pptp); + nf_ct_gre_keymap_flush(); +} + +module_init(nf_conntrack_pptp_init); +module_exit(nf_conntrack_pptp_fini); diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c new file mode 100644 index 000000000000..ac193ce70249 --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -0,0 +1,305 @@ +/* + * ip_conntrack_proto_gre.c - Version 3.0 + * + * Connection tracking protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define GRE_TIMEOUT (30 * HZ) +#define GRE_STREAM_TIMEOUT (180 * HZ) + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) +#else +#define DEBUGP(x, args...) +#endif + +static DEFINE_RWLOCK(nf_ct_gre_lock); +static LIST_HEAD(gre_keymap_list); + +void nf_ct_gre_keymap_flush(void) +{ + struct list_head *pos, *n; + + write_lock_bh(&nf_ct_gre_lock); + list_for_each_safe(pos, n, &gre_keymap_list) { + list_del(pos); + kfree(pos); + } + write_unlock_bh(&nf_ct_gre_lock); +} +EXPORT_SYMBOL(nf_ct_gre_keymap_flush); + +static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, + const struct nf_conntrack_tuple *t) +{ + return km->tuple.src.l3num == t->src.l3num && + !memcmp(&km->tuple.src.u3, &t->src.u3, sizeof(t->src.u3)) && + !memcmp(&km->tuple.dst.u3, &t->dst.u3, sizeof(t->dst.u3)) && + km->tuple.dst.protonum == t->dst.protonum && + km->tuple.dst.u.all == t->dst.u.all; +} + +/* look up the source key for a given tuple */ +static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t) +{ + struct nf_ct_gre_keymap *km; + __be16 key = 0; + + read_lock_bh(&nf_ct_gre_lock); + list_for_each_entry(km, &gre_keymap_list, list) { + if (gre_key_cmpfn(km, t)) { + key = km->tuple.src.u.gre.key; + break; + } + } + read_unlock_bh(&nf_ct_gre_lock); + + DEBUGP("lookup src key 0x%x for ", key); + NF_CT_DUMP_TUPLE(t); + + return key; +} + +/* add a single keymap entry, associate with specified master ct */ +int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, + struct nf_conntrack_tuple *t) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_ct_gre_keymap **kmp, *km; + + BUG_ON(strcmp(help->helper->name, "pptp")); + kmp = &help->help.ct_pptp_info.keymap[dir]; + if (*kmp) { + /* check whether it's a retransmission */ + list_for_each_entry(km, &gre_keymap_list, list) { + if (gre_key_cmpfn(km, t) && km == *kmp) + return 0; + } + DEBUGP("trying to override keymap_%s for ct %p\n", + dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); + return -EEXIST; + } + + km = kmalloc(sizeof(*km), GFP_ATOMIC); + if (!km) + return -ENOMEM; + memcpy(&km->tuple, t, sizeof(*t)); + *kmp = km; + + DEBUGP("adding new entry %p: ", km); + NF_CT_DUMP_TUPLE(&km->tuple); + + write_lock_bh(&nf_ct_gre_lock); + list_add_tail(&km->list, &gre_keymap_list); + write_unlock_bh(&nf_ct_gre_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add); + +/* destroy the keymap entries associated with specified master ct */ +void nf_ct_gre_keymap_destroy(struct nf_conn *ct) +{ + struct nf_conn_help *help = nfct_help(ct); + enum ip_conntrack_dir dir; + + DEBUGP("entering for ct %p\n", ct); + BUG_ON(strcmp(help->helper->name, "pptp")); + + write_lock_bh(&nf_ct_gre_lock); + for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { + if (help->help.ct_pptp_info.keymap[dir]) { + DEBUGP("removing %p from list\n", + help->help.ct_pptp_info.keymap[dir]); + list_del(&help->help.ct_pptp_info.keymap[dir]->list); + kfree(help->help.ct_pptp_info.keymap[dir]); + help->help.ct_pptp_info.keymap[dir] = NULL; + } + } + write_unlock_bh(&nf_ct_gre_lock); +} +EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); + +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ + +/* invert gre part of tuple */ +static int gre_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) +{ + tuple->dst.u.gre.key = orig->src.u.gre.key; + tuple->src.u.gre.key = orig->dst.u.gre.key; + return 1; +} + +/* gre hdr info to tuple */ +static int gre_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct nf_conntrack_tuple *tuple) +{ + struct gre_hdr_pptp _pgrehdr, *pgrehdr; + __be16 srckey; + struct gre_hdr _grehdr, *grehdr; + + /* first only delinearize old RFC1701 GRE header */ + grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); + if (!grehdr || grehdr->version != GRE_VERSION_PPTP) { + /* try to behave like "nf_conntrack_proto_generic" */ + tuple->src.u.all = 0; + tuple->dst.u.all = 0; + return 1; + } + + /* PPTP header is variable length, only need up to the call_id field */ + pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); + if (!pgrehdr) + return 1; + + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { + DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); + return 0; + } + + tuple->dst.u.gre.key = pgrehdr->call_id; + srckey = gre_keymap_lookup(tuple); + tuple->src.u.gre.key = srckey; + + return 1; +} + +/* print gre part of tuple */ +static int gre_print_tuple(struct seq_file *s, + const struct nf_conntrack_tuple *tuple) +{ + return seq_printf(s, "srckey=0x%x dstkey=0x%x ", + ntohs(tuple->src.u.gre.key), + ntohs(tuple->dst.u.gre.key)); +} + +/* print private data for conntrack */ +static int gre_print_conntrack(struct seq_file *s, + const struct nf_conn *ct) +{ + return seq_printf(s, "timeout=%u, stream_timeout=%u ", + (ct->proto.gre.timeout / HZ), + (ct->proto.gre.stream_timeout / HZ)); +} + +/* Returns verdict for packet, and may modify conntrack */ +static int gre_packet(struct nf_conn *ct, + const struct sk_buff *skb, + unsigned int dataoff, + enum ip_conntrack_info ctinfo, + int pf, + unsigned int hooknum) +{ + /* If we've seen traffic both ways, this is a GRE connection. + * Extend timeout. */ + if (ct->status & IPS_SEEN_REPLY) { + nf_ct_refresh_acct(ct, ctinfo, skb, + ct->proto.gre.stream_timeout); + /* Also, more likely to be important, and not a probe. */ + set_bit(IPS_ASSURED_BIT, &ct->status); + nf_conntrack_event_cache(IPCT_STATUS, skb); + } else + nf_ct_refresh_acct(ct, ctinfo, skb, + ct->proto.gre.timeout); + + return NF_ACCEPT; +} + +/* Called when a new connection for this protocol found. */ +static int gre_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) +{ + DEBUGP(": "); + NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + + /* initialize to sane value. Ideally a conntrack helper + * (e.g. in case of pptp) is increasing them */ + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; + ct->proto.gre.timeout = GRE_TIMEOUT; + + return 1; +} + +/* Called when a conntrack entry has already been removed from the hashes + * and is about to be deleted from memory */ +static void gre_destroy(struct nf_conn *ct) +{ + struct nf_conn *master = ct->master; + DEBUGP(" entering\n"); + + if (!master) + DEBUGP("no master !?!\n"); + else + nf_ct_gre_keymap_destroy(master); +} + +/* protocol helper struct */ +static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = { + .l3proto = AF_INET, + .l4proto = IPPROTO_GRE, + .name = "gre", + .pkt_to_tuple = gre_pkt_to_tuple, + .invert_tuple = gre_invert_tuple, + .print_tuple = gre_print_tuple, + .print_conntrack = gre_print_conntrack, + .packet = gre_packet, + .new = gre_new, + .destroy = gre_destroy, + .me = THIS_MODULE, +#if defined(CONFIG_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_NF_CONNTRACK_NETLINK_MODULE) + .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, + .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, +#endif +}; + +static int __init nf_ct_proto_gre_init(void) +{ + return nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4); +} + +static void nf_ct_proto_gre_fini(void) +{ + nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); + nf_ct_gre_keymap_flush(); +} + +module_init(nf_ct_proto_gre_init); +module_exit(nf_ct_proto_gre_fini); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3-71-gd317 From 9fafcd7b203229c3f3893a475741afc27e276306 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:09:57 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add SIP helper port Add IPv4 and IPv6 capable nf_conntrack port of the SIP conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 41 +++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_sip.c | 283 +++++++++++++++ net/netfilter/Kconfig | 12 + net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_sip.c | 530 +++++++++++++++++++++++++++++ 7 files changed, 873 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_sip.h create mode 100644 net/ipv4/netfilter/nf_nat_sip.c create mode 100644 net/netfilter/nf_conntrack_sip.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h new file mode 100644 index 000000000000..bb7f2041db74 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -0,0 +1,41 @@ +#ifndef __NF_CONNTRACK_SIP_H__ +#define __NF_CONNTRACK_SIP_H__ +#ifdef __KERNEL__ + +#define SIP_PORT 5060 +#define SIP_TIMEOUT 3600 + +enum sip_header_pos { + POS_REG_REQ_URI, + POS_REQ_URI, + POS_FROM, + POS_TO, + POS_VIA, + POS_CONTACT, + POS_CONTENT, + POS_MEDIA, + POS_OWNER_IP4, + POS_CONNECTION_IP4, + POS_OWNER_IP6, + POS_CONNECTION_IP6, + POS_SDP_HEADER, +}; + +extern unsigned int (*nf_nat_sip_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr); +extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp, + const char *dptr); + +extern int ct_sip_get_info(struct nf_conn *ct, const char *dptr, size_t dlen, + unsigned int *matchoff, unsigned int *matchlen, + enum sip_header_pos pos); +extern int ct_sip_lnlen(const char *line, const char *limit); +extern const char *ct_sip_search(const char *needle, const char *haystack, + size_t needle_len, size_t haystack_len, + int case_sensitive); +#endif /* __KERNEL__ */ +#endif /* __NF_CONNTRACK_SIP_H__ */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index c3327ac024de..83e83f553ccb 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -555,6 +555,11 @@ config IP_NF_NAT_SIP default IP_NF_NAT if IP_NF_SIP=y default m if IP_NF_SIP=m +config NF_NAT_SIP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_SIP + # mangle + specific targets config IP_NF_MANGLE tristate "Packet mangling" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index ef33ff2cdda9..167b65e89aca 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o +obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o # NAT protocols (nf_nat) obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c new file mode 100644 index 000000000000..3d524b957310 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -0,0 +1,283 @@ +/* SIP extension for UDP NAT alteration. + * + * (C) 2005 by Christian Hentschel + * based on RR's ip_nat_ftp.c and other modules. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hentschel "); +MODULE_DESCRIPTION("SIP NAT helper"); +MODULE_ALIAS("ip_nat_sip"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +struct addr_map { + struct { + char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int srclen, srciplen; + unsigned int dstlen, dstiplen; + } addr[IP_CT_DIR_MAX]; +}; + +static void addr_map_init(struct nf_conn *ct, struct addr_map *map) +{ + struct nf_conntrack_tuple *t; + enum ip_conntrack_dir dir; + unsigned int n; + + for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { + t = &ct->tuplehash[dir].tuple; + + n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", + NIPQUAD(t->src.u3.ip)); + map->addr[dir].srciplen = n; + n += sprintf(map->addr[dir].src + n, ":%u", + ntohs(t->src.u.udp.port)); + map->addr[dir].srclen = n; + + n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", + NIPQUAD(t->dst.u3.ip)); + map->addr[dir].dstiplen = n; + n += sprintf(map->addr[dir].dst + n, ":%u", + ntohs(t->dst.u.udp.port)); + map->addr[dir].dstlen = n; + } +} + +static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, + struct nf_conn *ct, const char **dptr, size_t dlen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned int matchlen, matchoff, addrlen; + char *addr; + + if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + return 1; + + if ((matchlen == map->addr[dir].srciplen || + matchlen == map->addr[dir].srclen) && + memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { + addr = map->addr[!dir].dst; + addrlen = map->addr[!dir].dstlen; + } else if ((matchlen == map->addr[dir].dstiplen || + matchlen == map->addr[dir].dstlen) && + memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { + addr = map->addr[!dir].src; + addrlen = map->addr[!dir].srclen; + } else + return 1; + + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, addr, addrlen)) + return 0; + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; + +} + +static unsigned int ip_nat_sip(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr) +{ + enum sip_header_pos pos; + struct addr_map map; + int dataoff, datalen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0") - 1) + return NF_DROP; + + addr_map_init(ct, &map); + + /* Basic rules: requests and responses. */ + if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { + /* 10.2: Constructing the REGISTER Request: + * + * The "userinfo" and "@" components of the SIP URI MUST NOT + * be present. + */ + if (datalen >= sizeof("REGISTER") - 1 && + strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) + pos = POS_REG_REQ_URI; + else + pos = POS_REQ_URI; + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) + return NF_DROP; + } + + if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + return NF_DROP; + return NF_ACCEPT; +} + +static unsigned int mangle_sip_packet(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr, size_t dlen, + char *buffer, int bufflen, + enum sip_header_pos pos) +{ + unsigned int matchlen, matchoff; + + if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + return 0; + + if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, buffer, bufflen)) + return 0; + + /* We need to reload this. Thanks Patrick. */ + *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + return 1; +} + +static int mangle_content_len(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char *dptr) +{ + unsigned int dataoff, matchoff, matchlen; + char buffer[sizeof("65536")]; + int bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Get actual SDP lenght */ + if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, POS_SDP_HEADER) > 0) { + + /* since ct_sip_get_info() give us a pointer passing 'v=' + we need to add 2 bytes in this count. */ + int c_len = (*pskb)->len - dataoff - matchoff + 2; + + /* Now, update SDP length */ + if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, + &matchlen, POS_CONTENT) > 0) { + + bufflen = sprintf(buffer, "%u", c_len); + return nf_nat_mangle_udp_packet(pskb, ct, ctinfo, + matchoff, matchlen, + buffer, bufflen); + } + } + return 0; +} + +static unsigned int mangle_sdp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + __be32 newip, u_int16_t port, + const char *dptr) +{ + char buffer[sizeof("nnn.nnn.nnn.nnn")]; + unsigned int dataoff, bufflen; + + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); + + /* Mangle owner and contact info. */ + bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_OWNER_IP4)) + return 0; + + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_CONNECTION_IP4)) + return 0; + + /* Mangle media port. */ + bufflen = sprintf(buffer, "%u", port); + if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, + buffer, bufflen, POS_MEDIA)) + return 0; + + return mangle_content_len(pskb, ctinfo, ct, dptr); +} + +/* So, this packet has hit the connection tracking matching code. + Mangle it, and change the expectation to match the new version. */ +static unsigned int ip_nat_sdp(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp, + const char *dptr) +{ + struct nf_conn *ct = exp->master; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + __be32 newip; + u_int16_t port; + + DEBUGP("ip_nat_sdp():\n"); + + /* Connection will come from reply */ + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + + exp->tuple.dst.u3.ip = newip; + exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; + exp->dir = !dir; + + /* When you see the packet, we need to NAT it the same as the + this one. */ + exp->expectfn = nf_nat_follow_master; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { + exp->tuple.dst.u.udp.port = htons(port); + if (nf_conntrack_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { + nf_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static void __exit nf_nat_sip_fini(void) +{ + rcu_assign_pointer(nf_nat_sip_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_sip_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_sip_hook)); + BUG_ON(rcu_dereference(nf_nat_sdp_hook)); + rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); + rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); + return 0; +} + +module_init(nf_nat_sip_init); +module_exit(nf_nat_sip_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 6b2eb26ae03f..e73891194b31 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -236,6 +236,18 @@ config NF_CONNTRACK_PPTP To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_SIP + tristate "SIP protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + SIP is an application-layer control protocol that can establish, + modify, and terminate multimedia sessions (conferences) such as + Internet telephony calls. With the ip_conntrack_sip and + the nf_nat_sip modules you can support the protocol on a connection + tracking/NATing firewall. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 897bed4cbd79..86da21700aa3 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o +obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c new file mode 100644 index 000000000000..e0c06795a943 --- /dev/null +++ b/net/netfilter/nf_conntrack_sip.c @@ -0,0 +1,530 @@ +/* SIP extension for IP connection tracking. + * + * (C) 2005 by Christian Hentschel + * based on RR's ip_conntrack_ftp.c and other modules. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hentschel "); +MODULE_DESCRIPTION("SIP connection tracking helper"); +MODULE_ALIAS("ip_conntrack_sip"); + +#define MAX_PORTS 8 +static unsigned short ports[MAX_PORTS]; +static int ports_c; +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "port numbers of SIP servers"); + +static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT; +module_param(sip_timeout, uint, 0600); +MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); + +unsigned int (*nf_nat_sip_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conn *ct, + const char **dptr) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sip_hook); + +unsigned int (*nf_nat_sdp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp, + const char *dptr) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); + +static int digits_len(struct nf_conn *, const char *, const char *, int *); +static int epaddr_len(struct nf_conn *, const char *, const char *, int *); +static int skp_digits_len(struct nf_conn *, const char *, const char *, int *); +static int skp_epaddr_len(struct nf_conn *, const char *, const char *, int *); + +struct sip_header_nfo { + const char *lname; + const char *sname; + const char *ln_str; + size_t lnlen; + size_t snlen; + size_t ln_strlen; + int case_sensitive; + int (*match_len)(struct nf_conn *, const char *, + const char *, int *); +}; + +static const struct sip_header_nfo ct_sip_hdrs[] = { + [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .ln_str = ":", + .ln_strlen = sizeof(":") - 1, + .match_len = epaddr_len, + }, + [POS_REQ_URI] = { /* SIP request URI */ + .lname = "sip:", + .lnlen = sizeof("sip:") - 1, + .ln_str = "@", + .ln_strlen = sizeof("@") - 1, + .match_len = epaddr_len, + }, + [POS_FROM] = { /* SIP From header */ + .lname = "From:", + .lnlen = sizeof("From:") - 1, + .sname = "\r\nf:", + .snlen = sizeof("\r\nf:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len, + }, + [POS_TO] = { /* SIP To header */ + .lname = "To:", + .lnlen = sizeof("To:") - 1, + .sname = "\r\nt:", + .snlen = sizeof("\r\nt:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len + }, + [POS_VIA] = { /* SIP Via header */ + .lname = "Via:", + .lnlen = sizeof("Via:") - 1, + .sname = "\r\nv:", + .snlen = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */ + .ln_str = "UDP ", + .ln_strlen = sizeof("UDP ") - 1, + .match_len = epaddr_len, + }, + [POS_CONTACT] = { /* SIP Contact header */ + .lname = "Contact:", + .lnlen = sizeof("Contact:") - 1, + .sname = "\r\nm:", + .snlen = sizeof("\r\nm:") - 1, + .ln_str = "sip:", + .ln_strlen = sizeof("sip:") - 1, + .match_len = skp_epaddr_len + }, + [POS_CONTENT] = { /* SIP Content length header */ + .lname = "Content-Length:", + .lnlen = sizeof("Content-Length:") - 1, + .sname = "\r\nl:", + .snlen = sizeof("\r\nl:") - 1, + .ln_str = ":", + .ln_strlen = sizeof(":") - 1, + .match_len = skp_digits_len + }, + [POS_MEDIA] = { /* SDP media info */ + .case_sensitive = 1, + .lname = "\nm=", + .lnlen = sizeof("\nm=") - 1, + .sname = "\rm=", + .snlen = sizeof("\rm=") - 1, + .ln_str = "audio ", + .ln_strlen = sizeof("audio ") - 1, + .match_len = digits_len + }, + [POS_OWNER_IP4] = { /* SDP owner address*/ + .case_sensitive = 1, + .lname = "\no=", + .lnlen = sizeof("\no=") - 1, + .sname = "\ro=", + .snlen = sizeof("\ro=") - 1, + .ln_str = "IN IP4 ", + .ln_strlen = sizeof("IN IP4 ") - 1, + .match_len = epaddr_len + }, + [POS_CONNECTION_IP4] = {/* SDP connection info */ + .case_sensitive = 1, + .lname = "\nc=", + .lnlen = sizeof("\nc=") - 1, + .sname = "\rc=", + .snlen = sizeof("\rc=") - 1, + .ln_str = "IN IP4 ", + .ln_strlen = sizeof("IN IP4 ") - 1, + .match_len = epaddr_len + }, + [POS_OWNER_IP6] = { /* SDP owner address*/ + .case_sensitive = 1, + .lname = "\no=", + .lnlen = sizeof("\no=") - 1, + .sname = "\ro=", + .snlen = sizeof("\ro=") - 1, + .ln_str = "IN IP6 ", + .ln_strlen = sizeof("IN IP6 ") - 1, + .match_len = epaddr_len + }, + [POS_CONNECTION_IP6] = {/* SDP connection info */ + .case_sensitive = 1, + .lname = "\nc=", + .lnlen = sizeof("\nc=") - 1, + .sname = "\rc=", + .snlen = sizeof("\rc=") - 1, + .ln_str = "IN IP6 ", + .ln_strlen = sizeof("IN IP6 ") - 1, + .match_len = epaddr_len + }, + [POS_SDP_HEADER] = { /* SDP version header */ + .case_sensitive = 1, + .lname = "\nv=", + .lnlen = sizeof("\nv=") - 1, + .sname = "\rv=", + .snlen = sizeof("\rv=") - 1, + .ln_str = "=", + .ln_strlen = sizeof("=") - 1, + .match_len = digits_len + } +}; + +/* get line lenght until first CR or LF seen. */ +int ct_sip_lnlen(const char *line, const char *limit) +{ + const char *k = line; + + while ((line <= limit) && (*line == '\r' || *line == '\n')) + line++; + + while (line <= limit) { + if (*line == '\r' || *line == '\n') + break; + line++; + } + return line - k; +} +EXPORT_SYMBOL_GPL(ct_sip_lnlen); + +/* Linear string search, case sensitive. */ +const char *ct_sip_search(const char *needle, const char *haystack, + size_t needle_len, size_t haystack_len, + int case_sensitive) +{ + const char *limit = haystack + (haystack_len - needle_len); + + while (haystack <= limit) { + if (case_sensitive) { + if (strncmp(haystack, needle, needle_len) == 0) + return haystack; + } else { + if (strnicmp(haystack, needle, needle_len) == 0) + return haystack; + } + haystack++; + } + return NULL; +} +EXPORT_SYMBOL_GPL(ct_sip_search); + +static int digits_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int len = 0; + while (dptr <= limit && isdigit(*dptr)) { + dptr++; + len++; + } + return len; +} + +/* get digits lenght, skiping blank spaces. */ +static int skp_digits_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + for (; dptr <= limit && *dptr == ' '; dptr++) + (*shift)++; + + return digits_len(ct, dptr, limit, shift); +} + +static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp, + union nf_conntrack_address *addr, const char *limit) +{ + const char *end; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + int ret = 0; + + switch (family) { + case AF_INET: + ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); + break; + case AF_INET6: + ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); + break; + default: + BUG(); + } + + if (ret == 0 || end == cp) + return 0; + if (endp) + *endp = end; + return 1; +} + +/* skip ip address. returns its length. */ +static int epaddr_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + union nf_conntrack_address addr; + const char *aux = dptr; + + if (!parse_addr(ct, dptr, &dptr, &addr, limit)) { + DEBUGP("ip: %s parse failed.!\n", dptr); + return 0; + } + + /* Port number */ + if (*dptr == ':') { + dptr++; + dptr += digits_len(ct, dptr, limit, shift); + } + return dptr - aux; +} + +/* get address length, skiping user info. */ +static int skp_epaddr_len(struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int s = *shift; + + for (; dptr <= limit && *dptr != '@'; dptr++) + (*shift)++; + + if (*dptr == '@') { + dptr++; + (*shift)++; + } else + *shift = s; + + return epaddr_len(ct, dptr, limit, shift); +} + +/* Returns 0 if not found, -1 error parsing. */ +int ct_sip_get_info(struct nf_conn *ct, + const char *dptr, size_t dlen, + unsigned int *matchoff, + unsigned int *matchlen, + enum sip_header_pos pos) +{ + const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; + const char *limit, *aux, *k = dptr; + int shift = 0; + + limit = dptr + (dlen - hnfo->lnlen); + + while (dptr <= limit) { + if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && + (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { + dptr++; + continue; + } + aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, + ct_sip_lnlen(dptr, limit), + hnfo->case_sensitive); + if (!aux) { + DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, + hnfo->lname); + return -1; + } + aux += hnfo->ln_strlen; + + *matchlen = hnfo->match_len(ct, aux, limit, &shift); + if (!*matchlen) + return -1; + + *matchoff = (aux - k) + shift; + + DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname, + *matchlen); + return 1; + } + DEBUGP("%s header not found.\n", hnfo->lname); + return 0; +} +EXPORT_SYMBOL_GPL(ct_sip_get_info); + +static int set_expected_rtp(struct sk_buff **pskb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + union nf_conntrack_address *addr, + __be16 port, + const char *dptr) +{ + struct nf_conntrack_expect *exp; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + int family = ct->tuplehash[!dir].tuple.src.l3num; + int ret; + typeof(nf_nat_sdp_hook) nf_nat_sdp; + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) + return NF_DROP; + nf_conntrack_expect_init(exp, family, + &ct->tuplehash[!dir].tuple.src.u3, addr, + IPPROTO_UDP, NULL, &port); + + nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); + if (nf_nat_sdp && ct->status & IPS_NAT_MASK) + ret = nf_nat_sdp(pskb, ctinfo, exp, dptr); + else { + if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + else + ret = NF_ACCEPT; + } + nf_conntrack_expect_put(exp); + + return ret; +} + +static int sip_help(struct sk_buff **pskb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + union nf_conntrack_address addr; + unsigned int dataoff, datalen; + const char *dptr; + int ret = NF_ACCEPT; + int matchoff, matchlen; + u_int16_t port; + enum sip_header_pos pos; + typeof(nf_nat_sip_hook) nf_nat_sip; + + /* No Data ? */ + dataoff = protoff + sizeof(struct udphdr); + if (dataoff >= (*pskb)->len) + return NF_ACCEPT; + + nf_ct_refresh(ct, *pskb, sip_timeout * HZ); + + if (!skb_is_nonlinear(*pskb)) + dptr = (*pskb)->data + dataoff; + else { + DEBUGP("Copy of skbuff not supported yet.\n"); + goto out; + } + + nf_nat_sip = rcu_dereference(nf_nat_sip_hook); + if (nf_nat_sip && ct->status & IPS_NAT_MASK) { + if (!nf_nat_sip(pskb, ctinfo, ct, &dptr)) { + ret = NF_DROP; + goto out; + } + } + + datalen = (*pskb)->len - dataoff; + if (datalen < sizeof("SIP/2.0 200") - 1) + goto out; + + /* RTP info only in some SDP pkts */ + if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 && + memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) { + goto out; + } + /* Get address and port from SDP packet. */ + pos = family == AF_INET ? POS_CONNECTION_IP4 : POS_CONNECTION_IP6; + if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, pos) > 0) { + + /* We'll drop only if there are parse problems. */ + if (!parse_addr(ct, dptr + matchoff, NULL, &addr, + dptr + datalen)) { + ret = NF_DROP; + goto out; + } + if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, + POS_MEDIA) > 0) { + + port = simple_strtoul(dptr + matchoff, NULL, 10); + if (port < 1024) { + ret = NF_DROP; + goto out; + } + ret = set_expected_rtp(pskb, ct, ctinfo, &addr, + htons(port), dptr); + } + } +out: + return ret; +} + +static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; +static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; + +static void nf_conntrack_sip_fini(void) +{ + int i, j; + + for (i = 0; i < ports_c; i++) { + for (j = 0; j < 2; j++) { + if (sip[i][j].me == NULL) + continue; + nf_conntrack_helper_unregister(&sip[i][j]); + } + } +} + +static int __init nf_conntrack_sip_init(void) +{ + int i, j, ret; + char *tmpname; + + if (ports_c == 0) + ports[ports_c++] = SIP_PORT; + + for (i = 0; i < ports_c; i++) { + memset(&sip[i], 0, sizeof(sip[i])); + + sip[i][0].tuple.src.l3num = AF_INET; + sip[i][1].tuple.src.l3num = AF_INET6; + for (j = 0; j < 2; j++) { + sip[i][j].tuple.dst.protonum = IPPROTO_UDP; + sip[i][j].tuple.src.u.udp.port = htons(ports[i]); + sip[i][j].mask.src.l3num = 0xFFFF; + sip[i][j].mask.src.u.udp.port = htons(0xFFFF); + sip[i][j].mask.dst.protonum = 0xFF; + sip[i][j].max_expected = 2; + sip[i][j].timeout = 3 * 60; /* 3 minutes */ + sip[i][j].me = THIS_MODULE; + sip[i][j].help = sip_help; + + tmpname = &sip_names[i][j][0]; + if (ports[i] == SIP_PORT) + sprintf(tmpname, "sip"); + else + sprintf(tmpname, "sip-%u", i); + sip[i][j].name = tmpname; + + DEBUGP("port #%u: %u\n", i, ports[i]); + + ret = nf_conntrack_helper_register(&sip[i][j]); + if (ret) { + printk("nf_ct_sip: failed to register helper " + "for pf: %u port: %u\n", + sip[i][j].tuple.src.l3num, ports[i]); + nf_conntrack_sip_fini(); + return ret; + } + } + } + return 0; +} + +module_init(nf_conntrack_sip_init); +module_exit(nf_conntrack_sip_fini); -- cgit v1.2.3-71-gd317 From a536df35b3a58caa9015bf7887a374b20f658368 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 2 Dec 2006 22:10:18 -0800 Subject: [NETFILTER]: nf_conntrack/nf_nat: add TFTP helper port Add IPv4 and IPv6 capable nf_conntrack port of the TFTP conntrack/NAT helper. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_tftp.h | 20 ++++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_tftp.c | 52 +++++++++ net/netfilter/Kconfig | 11 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_tftp.c | 159 ++++++++++++++++++++++++++++ 7 files changed, 249 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_tftp.h create mode 100644 net/ipv4/netfilter/nf_nat_tftp.c create mode 100644 net/netfilter/nf_conntrack_tftp.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_tftp.h b/include/linux/netfilter/nf_conntrack_tftp.h new file mode 100644 index 000000000000..0d79b7ae051f --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_tftp.h @@ -0,0 +1,20 @@ +#ifndef _NF_CONNTRACK_TFTP_H +#define _NF_CONNTRACK_TFTP_H + +#define TFTP_PORT 69 + +struct tftphdr { + __be16 opcode; +}; + +#define TFTP_OPCODE_READ 1 +#define TFTP_OPCODE_WRITE 2 +#define TFTP_OPCODE_DATA 3 +#define TFTP_OPCODE_ACK 4 +#define TFTP_OPCODE_ERROR 5 + +extern unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp); + +#endif /* _NF_CONNTRACK_TFTP_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 83e83f553ccb..1c0018b6bea4 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -515,6 +515,11 @@ config IP_NF_NAT_TFTP default IP_NF_NAT if IP_NF_TFTP=y default m if IP_NF_TFTP=m +config NF_NAT_TFTP + tristate + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT + default NF_NAT && NF_CONNTRACK_TFTP + config IP_NF_NAT_AMANDA tristate depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 167b65e89aca..3ca0af0ed5f0 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o +obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o # NAT protocols (nf_nat) obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c new file mode 100644 index 000000000000..2566b79de224 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_tftp.c @@ -0,0 +1,52 @@ +/* (C) 2001-2002 Magnus Boden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Magnus Boden "); +MODULE_DESCRIPTION("TFTP NAT helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_nat_tftp"); + +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp) +{ + struct nf_conn *ct = exp->master; + + exp->saved_proto.udp.port + = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; + exp->dir = IP_CT_DIR_REPLY; + exp->expectfn = nf_nat_follow_master; + if (nf_conntrack_expect_related(exp) != 0) + return NF_DROP; + return NF_ACCEPT; +} + +static void __exit nf_nat_tftp_fini(void) +{ + rcu_assign_pointer(nf_nat_tftp_hook, NULL); + synchronize_rcu(); +} + +static int __init nf_nat_tftp_init(void) +{ + BUG_ON(rcu_dereference(nf_nat_tftp_hook)); + rcu_assign_pointer(nf_nat_tftp_hook, help); + return 0; +} + +module_init(nf_nat_tftp_init); +module_exit(nf_nat_tftp_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index e73891194b31..e0deac17df12 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -248,6 +248,17 @@ config NF_CONNTRACK_SIP To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_TFTP + tristate "TFTP protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + TFTP connection tracking helper, this is required depending + on how restrictive your ruleset is. + If you are using a tftp client behind -j SNAT or -j MASQUERADING + you will need this. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CT_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 86da21700aa3..5dc5574f7e99 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o +obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c new file mode 100644 index 000000000000..d46a1263fcb5 --- /dev/null +++ b/net/netfilter/nf_conntrack_tftp.c @@ -0,0 +1,159 @@ +/* (C) 2001-2002 Magnus Boden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Magnus Boden "); +MODULE_DESCRIPTION("TFTP connection tracking helper"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ip_conntrack_tftp"); + +#define MAX_PORTS 8 +static unsigned short ports[MAX_PORTS]; +static int ports_c; +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "Port numbers of TFTP servers"); + +#if 0 +#define DEBUGP(format, args...) printk("%s:%s:" format, \ + __FILE__, __FUNCTION__ , ## args) +#else +#define DEBUGP(format, args...) +#endif + +unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct nf_conntrack_expect *exp) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_tftp_hook); + +static int tftp_help(struct sk_buff **pskb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + struct tftphdr _tftph, *tfh; + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple *tuple; + unsigned int ret = NF_ACCEPT; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + typeof(nf_nat_tftp_hook) nf_nat_tftp; + + tfh = skb_header_pointer(*pskb, protoff + sizeof(struct udphdr), + sizeof(_tftph), &_tftph); + if (tfh == NULL) + return NF_ACCEPT; + + switch (ntohs(tfh->opcode)) { + case TFTP_OPCODE_READ: + case TFTP_OPCODE_WRITE: + /* RRQ and WRQ works the same way */ + DEBUGP(""); + NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) + return NF_DROP; + tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + nf_conntrack_expect_init(exp, family, + &tuple->src.u3, &tuple->dst.u3, + IPPROTO_UDP, + NULL, &tuple->dst.u.udp.port); + + DEBUGP("expect: "); + NF_CT_DUMP_TUPLE(&exp->tuple); + NF_CT_DUMP_TUPLE(&exp->mask); + + nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook); + if (nf_nat_tftp && ct->status & IPS_NAT_MASK) + ret = nf_nat_tftp(pskb, ctinfo, exp); + else if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + nf_conntrack_expect_put(exp); + break; + case TFTP_OPCODE_DATA: + case TFTP_OPCODE_ACK: + DEBUGP("Data/ACK opcode\n"); + break; + case TFTP_OPCODE_ERROR: + DEBUGP("Error opcode\n"); + break; + default: + DEBUGP("Unknown opcode\n"); + } + return ret; +} + +static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly; +static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly; + +static void nf_conntrack_tftp_fini(void) +{ + int i, j; + + for (i = 0; i < ports_c; i++) { + for (j = 0; j < 2; j++) + nf_conntrack_helper_unregister(&tftp[i][j]); + } +} + +static int __init nf_conntrack_tftp_init(void) +{ + int i, j, ret; + char *tmpname; + + if (ports_c == 0) + ports[ports_c++] = TFTP_PORT; + + for (i = 0; i < ports_c; i++) { + memset(&tftp[i], 0, sizeof(tftp[i])); + + tftp[i][0].tuple.src.l3num = AF_INET; + tftp[i][1].tuple.src.l3num = AF_INET6; + for (j = 0; j < 2; j++) { + tftp[i][j].tuple.dst.protonum = IPPROTO_UDP; + tftp[i][j].tuple.src.u.udp.port = htons(ports[i]); + tftp[i][j].mask.src.l3num = 0xFFFF; + tftp[i][j].mask.dst.protonum = 0xFF; + tftp[i][j].mask.src.u.udp.port = htons(0xFFFF); + tftp[i][j].max_expected = 1; + tftp[i][j].timeout = 5 * 60; /* 5 minutes */ + tftp[i][j].me = THIS_MODULE; + tftp[i][j].help = tftp_help; + + tmpname = &tftp_names[i][j][0]; + if (ports[i] == TFTP_PORT) + sprintf(tmpname, "tftp"); + else + sprintf(tmpname, "tftp-%u", i); + tftp[i][j].name = tmpname; + + ret = nf_conntrack_helper_register(&tftp[i][j]); + if (ret) { + printk("nf_ct_tftp: failed to register helper " + "for pf: %u port: %u\n", + tftp[i][j].tuple.src.l3num, ports[i]); + nf_conntrack_tftp_fini(); + return ret; + } + } + } + return 0; +} + +module_init(nf_conntrack_tftp_init); +module_exit(nf_conntrack_tftp_fini); -- cgit v1.2.3-71-gd317 From 2b5f6dcce5bf94b9b119e9ed8d537098ec61c3d2 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 2 Dec 2006 22:22:25 -0800 Subject: [XFRM]: Fix aevent structuring to be more complete. aevents can not uniquely identify an SA. We break the ABI with this patch, but consensus is that since it is not yet utilized by any (known) application then it is fine (better do it now than later). Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- Documentation/networking/xfrm_sync.txt | 5 ++++- include/linux/xfrm.h | 2 ++ net/xfrm/xfrm_user.c | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/xfrm_sync.txt b/Documentation/networking/xfrm_sync.txt index 8be626f7c0b8..d7aac9dedeb4 100644 --- a/Documentation/networking/xfrm_sync.txt +++ b/Documentation/networking/xfrm_sync.txt @@ -47,10 +47,13 @@ aevent_id structure looks like: struct xfrm_aevent_id { struct xfrm_usersa_id sa_id; + xfrm_address_t saddr; __u32 flags; + __u32 reqid; }; -xfrm_usersa_id in this message layout identifies the SA. +The unique SA is identified by the combination of xfrm_usersa_id, +reqid and saddr. flags are used to indicate different things. The possible flags are: diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 7907c42bd4e4..088ba8113f7e 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -289,7 +289,9 @@ struct xfrm_usersa_id { struct xfrm_aevent_id { struct xfrm_usersa_id sa_id; + xfrm_address_t saddr; __u32 flags; + __u32 reqid; }; struct xfrm_userspi_info { diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 055b72fb37bc..6f97665983d2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1281,10 +1281,12 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve id = NLMSG_DATA(nlh); nlh->nlmsg_flags = 0; - id->sa_id.daddr = x->id.daddr; + memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr)); id->sa_id.spi = x->id.spi; id->sa_id.family = x->props.family; id->sa_id.proto = x->id.proto; + memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr)); + id->reqid = x->props.reqid; id->flags = c->data.aevent; RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); -- cgit v1.2.3-71-gd317