Commit 1ac6fcb7 authored by Stephen Lord's avatar Stephen Lord

Merge kernel.bkbits.net:/home/repos/linux-2.5

into kernel.bkbits.net:/home/lord/xfs-2.6
parents 4b2b7a67 5e2995a5
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/processor.h>
#include <asm/spitfire.h>
static struct vm_struct * modvmlist = NULL; static struct vm_struct * modvmlist = NULL;
static void module_unmap(void * addr) static void module_unmap(void * addr)
...@@ -279,6 +282,16 @@ int module_finalize(const Elf_Ehdr *hdr, ...@@ -279,6 +282,16 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, const Elf_Shdr *sechdrs,
struct module *me) struct module *me)
{ {
/* Cheetah's I-cache is fully coherent. */
if (tlb_type == spitfire) {
unsigned long va;
flushw_all();
for (va = 0; va < (PAGE_SIZE << 1); va += 32)
spitfire_put_icache_tag(va, 0x0);
__asm__ __volatile__("flush %g6");
}
return 0; return 0;
} }
......
...@@ -118,7 +118,6 @@ void __init smp_callin(void) ...@@ -118,7 +118,6 @@ void __init smp_callin(void)
inherit_locked_prom_mappings(0); inherit_locked_prom_mappings(0);
__flush_cache_all();
__flush_tlb_all(); __flush_tlb_all();
smp_setup_percpu_timer(); smp_setup_percpu_timer();
...@@ -661,7 +660,6 @@ extern unsigned long xcall_flush_tlb_range; ...@@ -661,7 +660,6 @@ extern unsigned long xcall_flush_tlb_range;
extern unsigned long xcall_flush_tlb_kernel_range; extern unsigned long xcall_flush_tlb_kernel_range;
extern unsigned long xcall_flush_tlb_all_spitfire; extern unsigned long xcall_flush_tlb_all_spitfire;
extern unsigned long xcall_flush_tlb_all_cheetah; extern unsigned long xcall_flush_tlb_all_cheetah;
extern unsigned long xcall_flush_cache_all_spitfire;
extern unsigned long xcall_report_regs; extern unsigned long xcall_report_regs;
extern unsigned long xcall_receive_signal; extern unsigned long xcall_receive_signal;
extern unsigned long xcall_flush_dcache_page_cheetah; extern unsigned long xcall_flush_dcache_page_cheetah;
...@@ -776,15 +774,6 @@ void smp_report_regs(void) ...@@ -776,15 +774,6 @@ void smp_report_regs(void)
smp_cross_call(&xcall_report_regs, 0, 0, 0); smp_cross_call(&xcall_report_regs, 0, 0, 0);
} }
void smp_flush_cache_all(void)
{
/* Cheetah need do nothing. */
if (tlb_type == spitfire) {
smp_cross_call(&xcall_flush_cache_all_spitfire, 0, 0, 0);
__flush_cache_all();
}
}
void smp_flush_tlb_all(void) void smp_flush_tlb_all(void)
{ {
if (tlb_type == spitfire) if (tlb_type == spitfire)
......
...@@ -1025,19 +1025,6 @@ void __flush_dcache_range(unsigned long start, unsigned long end) ...@@ -1025,19 +1025,6 @@ void __flush_dcache_range(unsigned long start, unsigned long end)
} }
} }
void __flush_cache_all(void)
{
/* Cheetah should be fine here too. */
if (tlb_type == spitfire) {
unsigned long va;
flushw_all();
for (va = 0; va < (PAGE_SIZE << 1); va += 32)
spitfire_put_icache_tag(va, 0x0);
__asm__ __volatile__("flush %g6");
}
}
/* If not locked, zap it. */ /* If not locked, zap it. */
void __flush_tlb_all(void) void __flush_tlb_all(void)
{ {
......
...@@ -721,20 +721,6 @@ xcall_flush_tlb_all_cheetah: ...@@ -721,20 +721,6 @@ xcall_flush_tlb_all_cheetah:
stxa %g0, [%g2] ASI_IMMU_DEMAP stxa %g0, [%g2] ASI_IMMU_DEMAP
retry retry
.globl xcall_flush_cache_all_spitfire
xcall_flush_cache_all_spitfire:
sethi %hi(16383), %g2
or %g2, %lo(16383), %g2
clr %g3
1: stxa %g0, [%g3] ASI_IC_TAG
membar #Sync
add %g3, 32, %g3
cmp %g3, %g2
bleu,pt %xcc, 1b
nop
flush %g6
retry
/* These just get rescheduled to PIL vectors. */ /* These just get rescheduled to PIL vectors. */
.globl xcall_call_function .globl xcall_call_function
xcall_call_function: xcall_call_function:
......
...@@ -169,7 +169,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, ...@@ -169,7 +169,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
} }
/* Create the ELF interpreter info */ /* Create the ELF interpreter info */
elf_info = current->mm->saved_auxv; elf_info = (elf_addr_t *) current->mm->saved_auxv;
#define NEW_AUX_ENT(id, val) \ #define NEW_AUX_ENT(id, val) \
do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0) do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0)
...@@ -197,8 +197,13 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, ...@@ -197,8 +197,13 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
if (k_platform) { if (k_platform) {
NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform); NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform);
} }
NEW_AUX_ENT(AT_NULL, 0);
#undef NEW_AUX_ENT #undef NEW_AUX_ENT
/* AT_NULL is zero; clear the rest too */
memset(&elf_info[ei_index], 0,
sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]);
/* And advance past the AT_NULL entry. */
ei_index += 2;
sp = STACK_ADD(p, ei_index); sp = STACK_ADD(p, ei_index);
...@@ -1209,6 +1214,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1209,6 +1214,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
elf_fpxregset_t *xfpu = NULL; elf_fpxregset_t *xfpu = NULL;
#endif #endif
int thread_status_size = 0; int thread_status_size = 0;
elf_addr_t *auxv;
/* /*
* We no longer stop all VM operations. * We no longer stop all VM operations.
...@@ -1290,13 +1296,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1290,13 +1296,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
numnote = 3; numnote = 3;
auxv = (elf_addr_t *) current->mm->saved_auxv;
i = 0; i = 0;
do do
i += 2; i += 2;
while (current->mm->saved_auxv[i - 2] != AT_NULL); while (auxv[i - 2] != AT_NULL);
fill_note(&notes[numnote++], "CORE", NT_AUXV, fill_note(&notes[numnote++], "CORE", NT_AUXV,
i * sizeof current->mm->saved_auxv[0], i * sizeof (elf_addr_t), auxv);
current->mm->saved_auxv);
/* Try to dump the FPU. */ /* Try to dump the FPU. */
if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, fpu))) if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, fpu)))
......
...@@ -33,18 +33,6 @@ extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page); ...@@ -33,18 +33,6 @@ extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
extern void __flush_dcache_range(unsigned long start, unsigned long end); extern void __flush_dcache_range(unsigned long start, unsigned long end);
extern void __flush_cache_all(void);
#ifndef CONFIG_SMP
#define flush_cache_all() __flush_cache_all()
#else /* CONFIG_SMP */
extern void smp_flush_cache_all(void);
#endif /* ! CONFIG_SMP */
#define flush_icache_page(vma, pg) do { } while(0) #define flush_icache_page(vma, pg) do { } while(0)
#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) #define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
...@@ -55,7 +43,7 @@ extern void smp_flush_cache_all(void); ...@@ -55,7 +43,7 @@ extern void smp_flush_cache_all(void);
extern void flush_dcache_page(struct page *page); extern void flush_dcache_page(struct page *page);
#define flush_cache_vmap(start, end) flush_cache_all() #define flush_cache_vmap(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) flush_cache_all() #define flush_cache_vunmap(start, end) do { } while (0)
#endif /* _SPARC64_CACHEFLUSH_H */ #endif /* _SPARC64_CACHEFLUSH_H */
...@@ -70,7 +70,6 @@ extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, ...@@ -70,7 +70,6 @@ extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page); extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
#define flush_cache_all() smp_flush_cache_all()
#define flush_tlb_all() smp_flush_tlb_all() #define flush_tlb_all() smp_flush_tlb_all()
#define flush_tlb_mm(mm) smp_flush_tlb_mm(mm) #define flush_tlb_mm(mm) smp_flush_tlb_mm(mm)
#define flush_tlb_range(vma, start, end) \ #define flush_tlb_range(vma, start, end) \
......
...@@ -62,6 +62,14 @@ struct ip_conntrack_tuple ...@@ -62,6 +62,14 @@ struct ip_conntrack_tuple
} dst; } dst;
}; };
/* This is optimized opposed to a memset of the whole structure. Everything we
* really care about is the source/destination unions */
#define IP_CT_TUPLE_U_BLANK(tuple) \
do { \
(tuple)->src.u.all = 0; \
(tuple)->dst.u.all = 0; \
} while (0)
enum ip_conntrack_dir enum ip_conntrack_dir
{ {
IP_CT_DIR_ORIGINAL, IP_CT_DIR_ORIGINAL,
......
...@@ -14,5 +14,10 @@ extern int ip_nat_rule_find(struct sk_buff **pskb, ...@@ -14,5 +14,10 @@ extern int ip_nat_rule_find(struct sk_buff **pskb,
const struct net_device *out, const struct net_device *out,
struct ip_conntrack *ct, struct ip_conntrack *ct,
struct ip_nat_info *info); struct ip_nat_info *info);
extern unsigned int
alloc_null_binding(struct ip_conntrack *conntrack,
struct ip_nat_info *info,
unsigned int hooknum);
#endif #endif
#endif /* _IP_NAT_RULE_H */ #endif /* _IP_NAT_RULE_H */
...@@ -524,113 +524,4 @@ typedef struct sctp_addip_chunk { ...@@ -524,113 +524,4 @@ typedef struct sctp_addip_chunk {
sctp_addiphdr_t addip_hdr; sctp_addiphdr_t addip_hdr;
} sctp_addip_chunk_t __attribute__((packed)); } sctp_addip_chunk_t __attribute__((packed));
/* FIXME: Cleanup needs to continue below this line. */
/* ADDIP Section 3.1.1
*
* ASCONF-Request Correlation ID: 32 bits (unsigned integer)
*
* This is an opaque integer assigned by the sender to identify each
* request parameter. It is in host byte order and is only meaningful
* to the sender. The receiver of the ASCONF Chunk will copy this 32
* bit value into the ASCONF Correlation ID field of the
* ASCONF-ACK. The sender of the ASCONF can use this same value in the
* ASCONF-ACK to find which request the response is for.
*
* ASCONF Parameter: TLV format
*
* Each Address configuration change is represented by a TLV parameter
* as defined in Section 3.2. One or more requests may be present in
* an ASCONF Chunk.
*/
typedef struct {
__u32 correlation;
sctp_paramhdr_t p;
__u8 payload[0];
} sctpAsconfReq_t;
/* ADDIP
* 3.1.1 Address/Stream Configuration Change Chunk (ASCONF)
*
* This chunk is used to communicate to the remote endpoint one of the
* configuration change requests that MUST be acknowledged. The
* information carried in the ASCONF Chunk uses the form of a
* Tag-Length-Value (TLV), as described in "3.2.1
* Optional/Variable-length Parameter Format" in [RFC2960], for all
* variable parameters.
*/
typedef struct {
__u32 serial;
__u8 reserved[3];
__u8 addr_type;
__u32 addr[4];
sctpAsconfReq_t requests[0];
} sctpAsconf_t;
/* ADDIP
* 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK)
*
* ASCONF-Request Correlation ID: 32 bits (unsigned integer)
*
* This value is copied from the ASCONF Correlation ID received in the
* ASCONF Chunk. It is used by the receiver of the ASCONF-ACK to identify
* which ASCONF parameter this response is associated with.
*
* ASCONF Parameter Response : TLV format
*
* The ASCONF Parameter Response is used in the ASCONF-ACK to report
* status of ASCONF processing. By default, if a responding endpoint
* does not include any Error Cause, a success is indicated. Thus a
* sender of an ASCONF-ACK MAY indicate complete success of all TLVs in
* an ASCONF by returning only the Chunk Type, Chunk Flags, Chunk Length
* (set to 8) and the Serial Number.
*/
typedef union {
struct {
__u32 correlation;
sctp_paramhdr_t header; /* success report */
} success;
struct {
__u32 correlation;
sctp_paramhdr_t header; /* error cause indication */
sctp_paramhdr_t errcause;
uint8_t request[0]; /* original request from ASCONF */
} error;
#define __correlation success.correlation
#define __header success.header
#define __cause error.errcause
#define __request error.request
} sctpAsconfAckRsp_t;
/* ADDIP
* 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK)
*
* This chunk is used by the receiver of an ASCONF Chunk to
* acknowledge the reception. It carries zero or more results for any
* ASCONF Parameters that were processed by the receiver.
*/
typedef struct {
__u32 serial;
sctpAsconfAckRsp_t responses[0];
} sctpAsconfAck_t;
/*********************************************************************
* Internal structures
*
* These are data structures which never go out on the wire.
*********************************************************************/
/* What is this data structure for? The TLV isn't one--it is just a
* value. Perhaps this data structure ought to have a type--otherwise
* it is not unambigiously parseable. --piggy
*/
typedef struct {
struct list_head hook;
int length; /* length of the TLV */
/* the actually TLV to be copied into ASCONF_ACK */
sctpAsconfAckRsp_t TLV;
} sctpAsconfAckRspNode_t;
#endif /* __LINUX_SCTP_H__ */ #endif /* __LINUX_SCTP_H__ */
...@@ -885,7 +885,7 @@ static inline char *__skb_pull(struct sk_buff *skb, unsigned int len) ...@@ -885,7 +885,7 @@ static inline char *__skb_pull(struct sk_buff *skb, unsigned int len)
*/ */
static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
{ {
return (len > skb->len) ? NULL : __skb_pull(skb, len); return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
} }
extern unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta); extern unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta);
...@@ -901,7 +901,7 @@ static inline char *__pskb_pull(struct sk_buff *skb, unsigned int len) ...@@ -901,7 +901,7 @@ static inline char *__pskb_pull(struct sk_buff *skb, unsigned int len)
static inline unsigned char *pskb_pull(struct sk_buff *skb, unsigned int len) static inline unsigned char *pskb_pull(struct sk_buff *skb, unsigned int len)
{ {
return (len > skb->len) ? NULL : __pskb_pull(skb, len); return unlikely(len > skb->len) ? NULL : __pskb_pull(skb, len);
} }
static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len) static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
...@@ -1052,7 +1052,7 @@ static inline struct sk_buff *__dev_alloc_skb(unsigned int length, ...@@ -1052,7 +1052,7 @@ static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
int gfp_mask) int gfp_mask)
{ {
struct sk_buff *skb = alloc_skb(length + 16, gfp_mask); struct sk_buff *skb = alloc_skb(length + 16, gfp_mask);
if (skb) if (likely(skb))
skb_reserve(skb, 16); skb_reserve(skb, 16);
return skb; return skb;
} }
......
...@@ -244,6 +244,7 @@ enum ...@@ -244,6 +244,7 @@ enum
NET_IPV4_NEIGH=17, NET_IPV4_NEIGH=17,
NET_IPV4_ROUTE=18, NET_IPV4_ROUTE=18,
NET_IPV4_FIB_HASH=19, NET_IPV4_FIB_HASH=19,
NET_IPV4_NETFILTER=20,
NET_IPV4_TCP_TIMESTAMPS=33, NET_IPV4_TCP_TIMESTAMPS=33,
NET_IPV4_TCP_WINDOW_SCALING=34, NET_IPV4_TCP_WINDOW_SCALING=34,
...@@ -358,6 +359,24 @@ enum ...@@ -358,6 +359,24 @@ enum
NET_IPV4_CONF_NOPOLICY=16, NET_IPV4_CONF_NOPOLICY=16,
}; };
/* /proc/sys/net/ipv4/netfilter */
enum
{
NET_IPV4_NF_CONNTRACK_MAX=1,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8,
NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9,
NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=10,
NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11,
NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12,
NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13,
};
/* /proc/sys/net/ipv6 */ /* /proc/sys/net/ipv6 */
enum { enum {
NET_IPV6_CONF=16, NET_IPV6_CONF=16,
......
/* SCTP kernel reference Implementation Copyright (C) 1999-2001 /* SCTP kernel reference Implementation
* Cisco, Motorola, and IBM * (C) Copyright IBM Corp. 2001, 2003
* Copyright (C) 1999-2001 Cisco, Motorola
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -88,6 +89,7 @@ typedef enum { ...@@ -88,6 +89,7 @@ typedef enum {
SCTP_CMD_PART_DELIVER, /* Partial data delivery considerations. */ SCTP_CMD_PART_DELIVER, /* Partial data delivery considerations. */
SCTP_CMD_RENEGE, /* Renege data on an association. */ SCTP_CMD_RENEGE, /* Renege data on an association. */
SCTP_CMD_SETUP_T4, /* ADDIP, setup T4 RTO timer parms. */ SCTP_CMD_SETUP_T4, /* ADDIP, setup T4 RTO timer parms. */
SCTP_CMD_PROCESS_OPERR, /* Process an ERROR chunk. */
SCTP_CMD_LAST SCTP_CMD_LAST
} sctp_verb_t; } sctp_verb_t;
......
...@@ -116,6 +116,9 @@ ...@@ -116,6 +116,9 @@
#define SCTP_STATIC static #define SCTP_STATIC static
#endif #endif
#define MSECS_TO_JIFFIES(msec) (msec * HZ / 1000)
#define JIFFIES_TO_MSECS(jiff) (jiff * 1000 / HZ)
/* /*
* Function declarations. * Function declarations.
*/ */
...@@ -495,22 +498,19 @@ for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \ ...@@ -495,22 +498,19 @@ for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
#define tv_lt(s, t) \ #define tv_lt(s, t) \
(s.tv_sec < t.tv_sec || (s.tv_sec == t.tv_sec && s.tv_usec < t.tv_usec)) (s.tv_sec < t.tv_sec || (s.tv_sec == t.tv_sec && s.tv_usec < t.tv_usec))
/* Stolen from net/profile.h. Using it from there is more grief than /* Add tv1 to tv2. */
* it is worth. #define TIMEVAL_ADD(tv1, tv2) \
*/ ({ \
static inline void tv_add(const struct timeval *entered, struct timeval *leaved) suseconds_t usecs = (tv2).tv_usec + (tv1).tv_usec; \
{ time_t secs = (tv2).tv_sec + (tv1).tv_sec; \
time_t usecs = leaved->tv_usec + entered->tv_usec; \
time_t secs = leaved->tv_sec + entered->tv_sec; if (usecs >= 1000000) { \
usecs -= 1000000; \
if (usecs >= 1000000) { secs++; \
usecs -= 1000000; } \
secs++; (tv2).tv_sec = secs; \
} (tv2).tv_usec = usecs; \
leaved->tv_sec = secs; })
leaved->tv_usec = usecs;
}
/* External references. */ /* External references. */
......
...@@ -265,13 +265,19 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *, ...@@ -265,13 +265,19 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *,
struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
union sctp_addr *addr, union sctp_addr *addr,
int vparam_len); int vparam_len);
struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
union sctp_addr *,
struct sockaddr *,
int, int);
struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
union sctp_addr *addr);
struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc,
int serial, int vparam_len);
struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf, struct sctp_chunk *asconf,
int vparam_len); int vparam_len);
struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
union sctp_addr *addr);
void sctp_chunk_assign_tsn(struct sctp_chunk *); void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(struct sctp_chunk *); void sctp_chunk_assign_ssn(struct sctp_chunk *);
......
...@@ -1085,6 +1085,10 @@ int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, ...@@ -1085,6 +1085,10 @@ int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
struct sctp_opt *); struct sctp_opt *);
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
const union sctp_addr *addrs,
int addrcnt,
struct sctp_opt *opt);
union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
int *addrs_len, int gfp); int *addrs_len, int gfp);
int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len, int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len,
...@@ -1389,6 +1393,10 @@ struct sctp_association { ...@@ -1389,6 +1393,10 @@ struct sctp_association {
__u8 ipv4_address; /* Peer understands IPv4 addresses? */ __u8 ipv4_address; /* Peer understands IPv4 addresses? */
__u8 ipv6_address; /* Peer understands IPv6 addresses? */ __u8 ipv6_address; /* Peer understands IPv6 addresses? */
__u8 hostname_address;/* Peer understands DNS addresses? */ __u8 hostname_address;/* Peer understands DNS addresses? */
/* Does peer support ADDIP? */
__u8 asconf_capable;
struct sctp_inithdr i; struct sctp_inithdr i;
int cookie_len; int cookie_len;
void *cookie; void *cookie;
......
...@@ -1488,6 +1488,18 @@ static void net_tx_action(struct softirq_action *h) ...@@ -1488,6 +1488,18 @@ static void net_tx_action(struct softirq_action *h)
} }
} }
static __inline__ int deliver_skb(struct sk_buff *skb,
struct packet_type *pt_prev, int last)
{
if (unlikely(!pt_prev->data))
return deliver_to_old_ones(pt_prev, skb, last);
else {
atomic_inc(&skb->users);
return pt_prev->func(skb, skb->dev, pt_prev);
}
}
#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
int (*br_handle_frame_hook)(struct sk_buff *skb); int (*br_handle_frame_hook)(struct sk_buff *skb);
...@@ -1495,15 +1507,8 @@ static __inline__ int handle_bridge(struct sk_buff *skb, ...@@ -1495,15 +1507,8 @@ static __inline__ int handle_bridge(struct sk_buff *skb,
struct packet_type *pt_prev) struct packet_type *pt_prev)
{ {
int ret = NET_RX_DROP; int ret = NET_RX_DROP;
if (pt_prev)
if (pt_prev) { ret = deliver_skb(skb, pt_prev, 0);
if (!pt_prev->data)
ret = deliver_to_old_ones(pt_prev, skb, 0);
else {
atomic_inc(&skb->users);
ret = pt_prev->func(skb, skb->dev, pt_prev);
}
}
return ret; return ret;
} }
...@@ -1551,16 +1556,8 @@ int netif_receive_skb(struct sk_buff *skb) ...@@ -1551,16 +1556,8 @@ int netif_receive_skb(struct sk_buff *skb)
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(ptype, &ptype_all, list) { list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (!ptype->dev || ptype->dev == skb->dev) { if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev) { if (pt_prev)
if (!pt_prev->data) { ret = deliver_skb(skb, pt_prev, 0);
ret = deliver_to_old_ones(pt_prev,
skb, 0);
} else {
atomic_inc(&skb->users);
ret = pt_prev->func(skb, skb->dev,
pt_prev);
}
}
pt_prev = ptype; pt_prev = ptype;
} }
} }
...@@ -1573,27 +1570,15 @@ int netif_receive_skb(struct sk_buff *skb) ...@@ -1573,27 +1570,15 @@ int netif_receive_skb(struct sk_buff *skb)
list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) { list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
if (ptype->type == type && if (ptype->type == type &&
(!ptype->dev || ptype->dev == skb->dev)) { (!ptype->dev || ptype->dev == skb->dev)) {
if (pt_prev) { if (pt_prev)
if (!pt_prev->data) { ret = deliver_skb(skb, pt_prev, 0);
ret = deliver_to_old_ones(pt_prev,
skb, 0);
} else {
atomic_inc(&skb->users);
ret = pt_prev->func(skb, skb->dev,
pt_prev);
}
}
pt_prev = ptype; pt_prev = ptype;
} }
} }
if (pt_prev) { if (pt_prev)
if (!pt_prev->data) { ret = deliver_skb(skb, pt_prev, 1);
ret = deliver_to_old_ones(pt_prev, skb, 1); else {
} else {
ret = pt_prev->func(skb, skb->dev, pt_prev);
}
} else {
kfree_skb(skb); kfree_skb(skb);
/* Jamal, now you will not able to escape explaining /* Jamal, now you will not able to escape explaining
* me how you were going to use this. :-) * me how you were going to use this. :-)
......
...@@ -59,7 +59,7 @@ LIST_HEAD(ip_conntrack_expect_list); ...@@ -59,7 +59,7 @@ LIST_HEAD(ip_conntrack_expect_list);
LIST_HEAD(protocol_list); LIST_HEAD(protocol_list);
static LIST_HEAD(helpers); static LIST_HEAD(helpers);
unsigned int ip_conntrack_htable_size = 0; unsigned int ip_conntrack_htable_size = 0;
static int ip_conntrack_max; int ip_conntrack_max;
static atomic_t ip_conntrack_count = ATOMIC_INIT(0); static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
struct list_head *ip_conntrack_hash; struct list_head *ip_conntrack_hash;
static kmem_cache_t *ip_conntrack_cachep; static kmem_cache_t *ip_conntrack_cachep;
...@@ -301,7 +301,7 @@ clean_from_lists(struct ip_conntrack *ct) ...@@ -301,7 +301,7 @@ clean_from_lists(struct ip_conntrack *ct)
static void static void
destroy_conntrack(struct nf_conntrack *nfct) destroy_conntrack(struct nf_conntrack *nfct)
{ {
struct ip_conntrack *ct = (struct ip_conntrack *)nfct; struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
struct ip_conntrack_protocol *proto; struct ip_conntrack_protocol *proto;
DEBUGP("destroy_conntrack(%p)\n", ct); DEBUGP("destroy_conntrack(%p)\n", ct);
...@@ -328,12 +328,15 @@ destroy_conntrack(struct nf_conntrack *nfct) ...@@ -328,12 +328,15 @@ destroy_conntrack(struct nf_conntrack *nfct)
/* can't call __unexpect_related here, /* can't call __unexpect_related here,
* since it would screw up expect_list */ * since it would screw up expect_list */
list_del(&ct->master->expected_list); list_del(&ct->master->expected_list);
ip_conntrack_put(ct->master->expectant); master = ct->master->expectant;
} }
kfree(ct->master); kfree(ct->master);
} }
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
if (master)
ip_conntrack_put(master);
DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct); DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
kmem_cache_free(ip_conntrack_cachep, ct); kmem_cache_free(ip_conntrack_cachep, ct);
atomic_dec(&ip_conntrack_count); atomic_dec(&ip_conntrack_count);
...@@ -1276,11 +1279,14 @@ getorigdst(struct sock *sk, int optval, void *user, int *len) ...@@ -1276,11 +1279,14 @@ getorigdst(struct sock *sk, int optval, void *user, int *len)
{ {
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ip_conntrack_tuple_hash *h; struct ip_conntrack_tuple_hash *h;
struct ip_conntrack_tuple tuple = { { inet->rcv_saddr, struct ip_conntrack_tuple tuple;
{ .tcp = { inet->sport } } },
{ inet->daddr, IP_CT_TUPLE_U_BLANK(&tuple);
{ .tcp = { inet->dport } }, tuple.src.ip = inet->rcv_saddr;
IPPROTO_TCP } }; tuple.src.u.tcp.port = inet->sport;
tuple.dst.ip = inet->daddr;
tuple.dst.u.tcp.port = inet->dport;
tuple.dst.protonum = IPPROTO_TCP;
/* We only do TCP at the moment: is there a better way? */ /* We only do TCP at the moment: is there a better way? */
if (strcmp(sk->sk_prot->name, "TCP")) { if (strcmp(sk->sk_prot->name, "TCP")) {
...@@ -1325,45 +1331,6 @@ static struct nf_sockopt_ops so_getorigdst = { ...@@ -1325,45 +1331,6 @@ static struct nf_sockopt_ops so_getorigdst = {
.get = &getorigdst, .get = &getorigdst,
}; };
#define NET_IP_CONNTRACK_MAX 2089
#define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max"
#ifdef CONFIG_SYSCTL
static struct ctl_table_header *ip_conntrack_sysctl_header;
static ctl_table ip_conntrack_table[] = {
{
.ctl_name = NET_IP_CONNTRACK_MAX,
.procname = NET_IP_CONNTRACK_MAX_NAME,
.data = &ip_conntrack_max,
.maxlen = sizeof(ip_conntrack_max),
.mode = 0644,
.proc_handler = proc_dointvec
},
{ .ctl_name = 0 }
};
static ctl_table ip_conntrack_dir_table[] = {
{
.ctl_name = NET_IPV4,
.procname = "ipv4",
.mode = 0555,
.child = ip_conntrack_table
},
{ .ctl_name = 0 }
};
static ctl_table ip_conntrack_root_table[] = {
{
.ctl_name = CTL_NET,
.procname = "net",
.mode = 0555,
.child = ip_conntrack_dir_table
},
{ .ctl_name = 0 }
};
#endif /*CONFIG_SYSCTL*/
static int kill_all(const struct ip_conntrack *i, void *data) static int kill_all(const struct ip_conntrack *i, void *data)
{ {
return 1; return 1;
...@@ -1373,9 +1340,6 @@ static int kill_all(const struct ip_conntrack *i, void *data) ...@@ -1373,9 +1340,6 @@ static int kill_all(const struct ip_conntrack *i, void *data)
supposed to kill the mall. */ supposed to kill the mall. */
void ip_conntrack_cleanup(void) void ip_conntrack_cleanup(void)
{ {
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(ip_conntrack_sysctl_header);
#endif
ip_ct_attach = NULL; ip_ct_attach = NULL;
/* This makes sure all current packets have passed through /* This makes sure all current packets have passed through
netfilter framework. Roll on, two-stage module netfilter framework. Roll on, two-stage module
...@@ -1453,25 +1417,10 @@ int __init ip_conntrack_init(void) ...@@ -1453,25 +1417,10 @@ int __init ip_conntrack_init(void)
for (i = 0; i < ip_conntrack_htable_size; i++) for (i = 0; i < ip_conntrack_htable_size; i++)
INIT_LIST_HEAD(&ip_conntrack_hash[i]); INIT_LIST_HEAD(&ip_conntrack_hash[i]);
/* This is fucking braindead. There is NO WAY of doing this without
the CONFIG_SYSCTL unless you don't want to detect errors.
Grrr... --RR */
#ifdef CONFIG_SYSCTL
ip_conntrack_sysctl_header
= register_sysctl_table(ip_conntrack_root_table, 0);
if (ip_conntrack_sysctl_header == NULL) {
goto err_free_ct_cachep;
}
#endif /*CONFIG_SYSCTL*/
/* For use by ipt_REJECT */ /* For use by ipt_REJECT */
ip_ct_attach = ip_conntrack_attach; ip_ct_attach = ip_conntrack_attach;
return ret; return ret;
#ifdef CONFIG_SYSCTL
err_free_ct_cachep:
kmem_cache_destroy(ip_conntrack_cachep);
#endif /*CONFIG_SYSCTL*/
err_free_hash: err_free_hash:
vfree(ip_conntrack_hash); vfree(ip_conntrack_hash);
err_unreg_sockopt: err_unreg_sockopt:
......
...@@ -177,7 +177,10 @@ static int help(struct sk_buff *skb, ...@@ -177,7 +177,10 @@ static int help(struct sk_buff *skb,
DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
HIPQUAD(dcc_ip), dcc_port); HIPQUAD(dcc_ip), dcc_port);
if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) { /* dcc_ip can be the internal OR external (NAT'ed) IP
* Tiago Sousa <mirage@kaotik.org> */
if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)
&& ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING printk(KERN_WARNING
"Forged DCC command from " "Forged DCC command from "
...@@ -201,7 +204,7 @@ static int help(struct sk_buff *skb, ...@@ -201,7 +204,7 @@ static int help(struct sk_buff *skb,
exp->tuple = ((struct ip_conntrack_tuple) exp->tuple = ((struct ip_conntrack_tuple)
{ { 0, { 0 } }, { { 0, { 0 } },
{ htonl(dcc_ip), { .tcp = { htons(dcc_port) } }, { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } },
IPPROTO_TCP }}); IPPROTO_TCP }});
exp->mask = ((struct ip_conntrack_tuple) exp->mask = ((struct ip_conntrack_tuple)
{ { 0, { 0 } }, { { 0, { 0 } },
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#define GENERIC_TIMEOUT (600*HZ) unsigned long ip_ct_generic_timeout = 600*HZ;
static int generic_pkt_to_tuple(const struct sk_buff *skb, static int generic_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
...@@ -44,7 +44,7 @@ static int packet(struct ip_conntrack *conntrack, ...@@ -44,7 +44,7 @@ static int packet(struct ip_conntrack *conntrack,
const struct sk_buff *skb, const struct sk_buff *skb,
enum ip_conntrack_info conntrackinfo) enum ip_conntrack_info conntrackinfo)
{ {
ip_ct_refresh(conntrack, GENERIC_TIMEOUT); ip_ct_refresh(conntrack, ip_ct_generic_timeout);
return NF_ACCEPT; return NF_ACCEPT;
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include <linux/icmp.h> #include <linux/icmp.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#define ICMP_TIMEOUT (30*HZ) unsigned long ip_ct_icmp_timeout = 30*HZ;
#if 0 #if 0
#define DEBUGP printk #define DEBUGP printk
...@@ -86,7 +86,7 @@ static int icmp_packet(struct ip_conntrack *ct, ...@@ -86,7 +86,7 @@ static int icmp_packet(struct ip_conntrack *ct,
ct->timeout.function((unsigned long)ct); ct->timeout.function((unsigned long)ct);
} else { } else {
atomic_inc(&ct->proto.icmp.count); atomic_inc(&ct->proto.icmp.count);
ip_ct_refresh(ct, ICMP_TIMEOUT); ip_ct_refresh(ct, ip_ct_icmp_timeout);
} }
return NF_ACCEPT; return NF_ACCEPT;
......
...@@ -49,20 +49,28 @@ static const char *tcp_conntrack_names[] = { ...@@ -49,20 +49,28 @@ static const char *tcp_conntrack_names[] = {
#define HOURS * 60 MINS #define HOURS * 60 MINS
#define DAYS * 24 HOURS #define DAYS * 24 HOURS
unsigned long ip_ct_tcp_timeout_syn_sent = 2 MINS;
static unsigned long tcp_timeouts[] unsigned long ip_ct_tcp_timeout_syn_recv = 60 SECS;
= { 30 MINS, /* TCP_CONNTRACK_NONE, */ unsigned long ip_ct_tcp_timeout_established = 5 DAYS;
5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */ unsigned long ip_ct_tcp_timeout_fin_wait = 2 MINS;
2 MINS, /* TCP_CONNTRACK_SYN_SENT, */ unsigned long ip_ct_tcp_timeout_close_wait = 3 DAYS;
60 SECS, /* TCP_CONNTRACK_SYN_RECV, */ unsigned long ip_ct_tcp_timeout_last_ack = 30 SECS;
2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */ unsigned long ip_ct_tcp_timeout_time_wait = 2 MINS;
2 MINS, /* TCP_CONNTRACK_TIME_WAIT, */ unsigned long ip_ct_tcp_timeout_close = 10 SECS;
10 SECS, /* TCP_CONNTRACK_CLOSE, */
60 SECS, /* TCP_CONNTRACK_CLOSE_WAIT, */ static unsigned long * tcp_timeouts[]
30 SECS, /* TCP_CONNTRACK_LAST_ACK, */ = { 0, /* TCP_CONNTRACK_NONE */
2 MINS, /* TCP_CONNTRACK_LISTEN, */ &ip_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */
}; &ip_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */
&ip_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */
&ip_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */
&ip_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */
&ip_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */
&ip_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */
&ip_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */
0, /* TCP_CONNTRACK_LISTEN */
};
#define sNO TCP_CONNTRACK_NONE #define sNO TCP_CONNTRACK_NONE
#define sES TCP_CONNTRACK_ESTABLISHED #define sES TCP_CONNTRACK_ESTABLISHED
#define sSS TCP_CONNTRACK_SYN_SENT #define sSS TCP_CONNTRACK_SYN_SENT
...@@ -204,7 +212,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, ...@@ -204,7 +212,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
set_bit(IPS_ASSURED_BIT, &conntrack->status); set_bit(IPS_ASSURED_BIT, &conntrack->status);
WRITE_UNLOCK(&tcp_lock); WRITE_UNLOCK(&tcp_lock);
ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]); ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
} }
return NF_ACCEPT; return NF_ACCEPT;
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#define UDP_TIMEOUT (30*HZ) unsigned long ip_ct_udp_timeout = 30*HZ;
#define UDP_STREAM_TIMEOUT (180*HZ) unsigned long ip_ct_udp_timeout_stream = 180*HZ;
static int udp_pkt_to_tuple(const struct sk_buff *skb, static int udp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
...@@ -57,11 +57,11 @@ static int udp_packet(struct ip_conntrack *conntrack, ...@@ -57,11 +57,11 @@ static int udp_packet(struct ip_conntrack *conntrack,
/* If we've seen traffic both ways, this is some kind of UDP /* If we've seen traffic both ways, this is some kind of UDP
stream. Extend timeout. */ stream. Extend timeout. */
if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT); ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
/* Also, more likely to be important, and not a probe */ /* Also, more likely to be important, and not a probe */
set_bit(IPS_ASSURED_BIT, &conntrack->status); set_bit(IPS_ASSURED_BIT, &conntrack->status);
} else } else
ip_ct_refresh(conntrack, UDP_TIMEOUT); ip_ct_refresh(conntrack, ip_ct_udp_timeout);
return NF_ACCEPT; return NF_ACCEPT;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
Public Licence. */ Public Licence. */
#include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
...@@ -14,6 +15,9 @@ ...@@ -14,6 +15,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
#include <net/checksum.h> #include <net/checksum.h>
#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
...@@ -256,6 +260,98 @@ static struct nf_hook_ops ip_conntrack_local_in_ops = { ...@@ -256,6 +260,98 @@ static struct nf_hook_ops ip_conntrack_local_in_ops = {
.priority = NF_IP_PRI_LAST-1, .priority = NF_IP_PRI_LAST-1,
}; };
/* Sysctl support */
#ifdef CONFIG_SYSCTL
/* From ip_conntrack_core.c */
extern int ip_conntrack_max;
/* From ip_conntrack_proto_tcp.c */
extern unsigned long ip_ct_tcp_timeout_syn_sent;
extern unsigned long ip_ct_tcp_timeout_syn_recv;
extern unsigned long ip_ct_tcp_timeout_established;
extern unsigned long ip_ct_tcp_timeout_fin_wait;
extern unsigned long ip_ct_tcp_timeout_close_wait;
extern unsigned long ip_ct_tcp_timeout_last_ack;
extern unsigned long ip_ct_tcp_timeout_time_wait;
extern unsigned long ip_ct_tcp_timeout_close;
/* From ip_conntrack_proto_udp.c */
extern unsigned long ip_ct_udp_timeout;
extern unsigned long ip_ct_udp_timeout_stream;
/* From ip_conntrack_proto_icmp.c */
extern unsigned long ip_ct_icmp_timeout;
/* From ip_conntrack_proto_icmp.c */
extern unsigned long ip_ct_generic_timeout;
static struct ctl_table_header *ip_ct_sysctl_header;
static ctl_table ip_ct_sysctl_table[] = {
{NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max",
&ip_conntrack_max, sizeof(int), 0644, NULL,
&proc_dointvec},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, "ip_conntrack_tcp_timeout_syn_sent",
&ip_ct_tcp_timeout_syn_sent, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, "ip_conntrack_tcp_timeout_syn_recv",
&ip_ct_tcp_timeout_syn_recv, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, "ip_conntrack_tcp_timeout_established",
&ip_ct_tcp_timeout_established, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, "ip_conntrack_tcp_timeout_fin_wait",
&ip_ct_tcp_timeout_fin_wait, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, "ip_conntrack_tcp_timeout_close_wait",
&ip_ct_tcp_timeout_close_wait, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, "ip_conntrack_tcp_timeout_last_ack",
&ip_ct_tcp_timeout_last_ack, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, "ip_conntrack_tcp_timeout_time_wait",
&ip_ct_tcp_timeout_time_wait, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, "ip_conntrack_tcp_timeout_close",
&ip_ct_tcp_timeout_close, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, "ip_conntrack_udp_timeout",
&ip_ct_udp_timeout, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, "ip_conntrack_udp_timeout_stream",
&ip_ct_udp_timeout_stream, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, "ip_conntrack_icmp_timeout",
&ip_ct_icmp_timeout, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, "ip_conntrack_generic_timeout",
&ip_ct_generic_timeout, sizeof(unsigned int), 0644, NULL,
&proc_dointvec_jiffies},
{0}
};
#define NET_IP_CONNTRACK_MAX 2089
static ctl_table ip_ct_netfilter_table[] = {
{NET_IPV4_NETFILTER, "netfilter", NULL, 0, 0555, ip_ct_sysctl_table, 0, 0, 0, 0, 0},
{NET_IP_CONNTRACK_MAX, "ip_conntrack_max",
&ip_conntrack_max, sizeof(int), 0644, NULL,
&proc_dointvec},
{0}
};
static ctl_table ip_ct_ipv4_table[] = {
{NET_IPV4, "ipv4", NULL, 0, 0555, ip_ct_netfilter_table, 0, 0, 0, 0, 0},
{0}
};
static ctl_table ip_ct_net_table[] = {
{CTL_NET, "net", NULL, 0, 0555, ip_ct_ipv4_table, 0, 0, 0, 0, 0},
{0}
};
#endif
static int init_or_cleanup(int init) static int init_or_cleanup(int init)
{ {
struct proc_dir_entry *proc; struct proc_dir_entry *proc;
...@@ -291,10 +387,20 @@ static int init_or_cleanup(int init) ...@@ -291,10 +387,20 @@ static int init_or_cleanup(int init)
printk("ip_conntrack: can't register local in hook.\n"); printk("ip_conntrack: can't register local in hook.\n");
goto cleanup_inoutandlocalops; goto cleanup_inoutandlocalops;
} }
#ifdef CONFIG_SYSCTL
ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
if (ip_ct_sysctl_header == NULL) {
printk("ip_conntrack: can't register to sysctl.\n");
goto cleanup;
}
#endif
return ret; return ret;
cleanup: cleanup:
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(ip_ct_sysctl_header);
#endif
nf_unregister_hook(&ip_conntrack_local_in_ops); nf_unregister_hook(&ip_conntrack_local_in_ops);
cleanup_inoutandlocalops: cleanup_inoutandlocalops:
nf_unregister_hook(&ip_conntrack_out_ops); nf_unregister_hook(&ip_conntrack_out_ops);
......
...@@ -516,12 +516,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, ...@@ -516,12 +516,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack,
struct ip_conntrack_tuple new_tuple, inv_tuple, reply; struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
struct ip_conntrack_tuple orig_tp; struct ip_conntrack_tuple orig_tp;
struct ip_nat_info *info = &conntrack->nat.info; struct ip_nat_info *info = &conntrack->nat.info;
int in_hashes = info->initialized;
MUST_BE_WRITE_LOCKED(&ip_nat_lock); MUST_BE_WRITE_LOCKED(&ip_nat_lock);
IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
|| hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_POST_ROUTING
|| hooknum == NF_IP_LOCAL_OUT); || hooknum == NF_IP_LOCAL_OUT);
IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS); IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
/* What we've got will look like inverse of reply. Normally /* What we've got will look like inverse of reply. Normally
this is what is in the conntrack, except for prior this is what is in the conntrack, except for prior
...@@ -638,6 +640,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, ...@@ -638,6 +640,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack,
/* It's done. */ /* It's done. */
info->initialized |= (1 << HOOK2MANIP(hooknum)); info->initialized |= (1 << HOOK2MANIP(hooknum));
if (in_hashes) {
IP_NF_ASSERT(info->bysource.conntrack);
replace_in_hashes(conntrack, info);
} else {
place_in_hashes(conntrack, info);
}
return NF_ACCEPT; return NF_ACCEPT;
} }
...@@ -761,11 +771,6 @@ do_bindings(struct ip_conntrack *ct, ...@@ -761,11 +771,6 @@ do_bindings(struct ip_conntrack *ct,
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
int proto = (*pskb)->nh.iph->protocol; int proto = (*pskb)->nh.iph->protocol;
/* Skip everything and don't call helpers if there are no
* manips for this connection */
if (info->num_manips == 0)
return NF_ACCEPT;
/* Need nat lock to protect against modification, but neither /* Need nat lock to protect against modification, but neither
conntrack (referenced) and helper (deleted with conntrack (referenced) and helper (deleted with
synchronize_bh()) can vanish. */ synchronize_bh()) can vanish. */
......
...@@ -122,7 +122,6 @@ static void mangle_contents(struct sk_buff *skb, ...@@ -122,7 +122,6 @@ static void mangle_contents(struct sk_buff *skb,
/* fix IP hdr checksum information */ /* fix IP hdr checksum information */
skb->nh.iph->tot_len = htons(skb->len); skb->nh.iph->tot_len = htons(skb->len);
ip_send_check(skb->nh.iph); ip_send_check(skb->nh.iph);
skb->csum = csum_partial(data, skb->len - dataoff, 0);
} }
/* Unusual, but possible case. */ /* Unusual, but possible case. */
...@@ -167,6 +166,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, ...@@ -167,6 +166,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
{ {
struct iphdr *iph; struct iphdr *iph;
struct tcphdr *tcph; struct tcphdr *tcph;
int datalen;
if (!skb_ip_make_writable(pskb, (*pskb)->len)) if (!skb_ip_make_writable(pskb, (*pskb)->len))
return 0; return 0;
...@@ -184,11 +184,11 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, ...@@ -184,11 +184,11 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
match_offset, match_len, rep_buffer, rep_len); match_offset, match_len, rep_buffer, rep_len);
datalen = (*pskb)->len - iph->ihl*4;
tcph->check = 0; tcph->check = 0;
tcph->check = tcp_v4_check(tcph, (*pskb)->len - iph->ihl*4, tcph->check = tcp_v4_check(tcph, datalen, iph->saddr, iph->daddr,
iph->saddr, iph->daddr, csum_partial((char *)tcph, datalen, 0));
csum_partial((char *)tcph, tcph->doff*4,
(*pskb)->csum));
adjust_tcp_sequence(ntohl(tcph->seq), adjust_tcp_sequence(ntohl(tcph->seq),
(int)rep_len - (int)match_len, (int)rep_len - (int)match_len,
ct, ctinfo); ct, ctinfo);
...@@ -216,7 +216,12 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, ...@@ -216,7 +216,12 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,
{ {
struct iphdr *iph; struct iphdr *iph;
struct udphdr *udph; struct udphdr *udph;
int need_csum = ((*pskb)->csum != 0);
/* 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_ip_make_writable(pskb, (*pskb)->len)) if (!skb_ip_make_writable(pskb, (*pskb)->len))
return 0; return 0;
...@@ -235,17 +240,15 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, ...@@ -235,17 +240,15 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,
udph->len = htons((*pskb)->len - iph->ihl*4); udph->len = htons((*pskb)->len - iph->ihl*4);
/* fix udp checksum if udp checksum was previously calculated */ /* fix udp checksum if udp checksum was previously calculated */
if (need_csum) { if (udph->check) {
int datalen = (*pskb)->len - iph->ihl * 4;
udph->check = 0; udph->check = 0;
udph->check udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
= csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP,
(*pskb)->len - iph->ihl*4, csum_partial((char *)udph,
IPPROTO_UDP, datalen, 0));
csum_partial((char *)udph, }
sizeof(struct udphdr),
(*pskb)->csum));
} else
(*pskb)->csum = 0;
return 1; return 1;
} }
......
...@@ -233,7 +233,7 @@ static int ipt_dnat_checkentry(const char *tablename, ...@@ -233,7 +233,7 @@ static int ipt_dnat_checkentry(const char *tablename,
return 1; return 1;
} }
static inline unsigned int inline unsigned int
alloc_null_binding(struct ip_conntrack *conntrack, alloc_null_binding(struct ip_conntrack *conntrack,
struct ip_nat_info *info, struct ip_nat_info *info,
unsigned int hooknum) unsigned int hooknum)
......
...@@ -119,7 +119,6 @@ ip_nat_fn(unsigned int hooknum, ...@@ -119,7 +119,6 @@ ip_nat_fn(unsigned int hooknum,
/* Seen it before? This can happen for loopback, retrans, /* Seen it before? This can happen for loopback, retrans,
or local packets.. */ or local packets.. */
if (!(info->initialized & (1 << maniptype))) { if (!(info->initialized & (1 << maniptype))) {
int in_hashes = info->initialized;
unsigned int ret; unsigned int ret;
if (ct->master if (ct->master
...@@ -130,9 +129,10 @@ ip_nat_fn(unsigned int hooknum, ...@@ -130,9 +129,10 @@ ip_nat_fn(unsigned int hooknum,
} else { } else {
#ifdef CONFIG_IP_NF_NAT_LOCAL #ifdef CONFIG_IP_NF_NAT_LOCAL
/* LOCAL_IN hook doesn't have a chain! */ /* LOCAL_IN hook doesn't have a chain! */
if (hooknum == NF_IP_LOCAL_IN) { if (hooknum == NF_IP_LOCAL_IN)
ret = NF_ACCEPT; ret = alloc_null_binding(ct, info,
} else hooknum);
else
#endif #endif
ret = ip_nat_rule_find(pskb, hooknum, in, out, ret = ip_nat_rule_find(pskb, hooknum, in, out,
ct, info); ct, info);
...@@ -142,13 +142,6 @@ ip_nat_fn(unsigned int hooknum, ...@@ -142,13 +142,6 @@ ip_nat_fn(unsigned int hooknum,
WRITE_UNLOCK(&ip_nat_lock); WRITE_UNLOCK(&ip_nat_lock);
return ret; return ret;
} }
if (in_hashes) {
IP_NF_ASSERT(info->bysource.conntrack);
replace_in_hashes(ct, info);
} else {
place_in_hashes(ct, info);
}
} else } else
DEBUGP("Already setup manip %s for ct %p\n", DEBUGP("Already setup manip %s for ct %p\n",
maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
...@@ -199,6 +192,7 @@ ip_nat_out(unsigned int hooknum, ...@@ -199,6 +192,7 @@ ip_nat_out(unsigned int hooknum,
return ip_nat_fn(hooknum, pskb, in, out, okfn); return ip_nat_fn(hooknum, pskb, in, out, okfn);
} }
#ifdef CONFIG_IP_NF_NAT_LOCAL
static unsigned int static unsigned int
ip_nat_local_fn(unsigned int hooknum, ip_nat_local_fn(unsigned int hooknum,
struct sk_buff **pskb, struct sk_buff **pskb,
...@@ -224,6 +218,7 @@ ip_nat_local_fn(unsigned int hooknum, ...@@ -224,6 +218,7 @@ ip_nat_local_fn(unsigned int hooknum,
return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
return ret; return ret;
} }
#endif
/* We must be after connection tracking and before packet filtering. */ /* We must be after connection tracking and before packet filtering. */
...@@ -245,6 +240,7 @@ static struct nf_hook_ops ip_nat_out_ops = { ...@@ -245,6 +240,7 @@ static struct nf_hook_ops ip_nat_out_ops = {
.priority = NF_IP_PRI_NAT_SRC, .priority = NF_IP_PRI_NAT_SRC,
}; };
#ifdef CONFIG_IP_NF_NAT_LOCAL
/* Before packet filtering, change destination */ /* Before packet filtering, change destination */
static struct nf_hook_ops ip_nat_local_out_ops = { static struct nf_hook_ops ip_nat_local_out_ops = {
.hook = ip_nat_local_fn, .hook = ip_nat_local_fn,
...@@ -254,7 +250,7 @@ static struct nf_hook_ops ip_nat_local_out_ops = { ...@@ -254,7 +250,7 @@ static struct nf_hook_ops ip_nat_local_out_ops = {
.priority = NF_IP_PRI_NAT_DST, .priority = NF_IP_PRI_NAT_DST,
}; };
#ifdef CONFIG_IP_NF_NAT_LOCAL /* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */
static struct nf_hook_ops ip_nat_local_in_ops = { static struct nf_hook_ops ip_nat_local_in_ops = {
.hook = ip_nat_fn, .hook = ip_nat_fn,
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -324,12 +320,12 @@ static int init_or_cleanup(int init) ...@@ -324,12 +320,12 @@ static int init_or_cleanup(int init)
printk("ip_nat_init: can't register out hook.\n"); printk("ip_nat_init: can't register out hook.\n");
goto cleanup_inops; goto cleanup_inops;
} }
#ifdef CONFIG_IP_NF_NAT_LOCAL
ret = nf_register_hook(&ip_nat_local_out_ops); ret = nf_register_hook(&ip_nat_local_out_ops);
if (ret < 0) { if (ret < 0) {
printk("ip_nat_init: can't register local out hook.\n"); printk("ip_nat_init: can't register local out hook.\n");
goto cleanup_outops; goto cleanup_outops;
} }
#ifdef CONFIG_IP_NF_NAT_LOCAL
ret = nf_register_hook(&ip_nat_local_in_ops); ret = nf_register_hook(&ip_nat_local_in_ops);
if (ret < 0) { if (ret < 0) {
printk("ip_nat_init: can't register local in hook.\n"); printk("ip_nat_init: can't register local in hook.\n");
...@@ -342,9 +338,9 @@ static int init_or_cleanup(int init) ...@@ -342,9 +338,9 @@ static int init_or_cleanup(int init)
#ifdef CONFIG_IP_NF_NAT_LOCAL #ifdef CONFIG_IP_NF_NAT_LOCAL
nf_unregister_hook(&ip_nat_local_in_ops); nf_unregister_hook(&ip_nat_local_in_ops);
cleanup_localoutops: cleanup_localoutops:
#endif
nf_unregister_hook(&ip_nat_local_out_ops); nf_unregister_hook(&ip_nat_local_out_ops);
cleanup_outops: cleanup_outops:
#endif
nf_unregister_hook(&ip_nat_out_ops); nf_unregister_hook(&ip_nat_out_ops);
cleanup_inops: cleanup_inops:
nf_unregister_hook(&ip_nat_in_ops); nf_unregister_hook(&ip_nat_in_ops);
......
...@@ -40,16 +40,17 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct) ...@@ -40,16 +40,17 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
} }
} }
static inline struct rtable *route_reverse(struct sk_buff *skb, int local) static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
{ {
struct iphdr *iph = skb->nh.iph; struct iphdr *iph = skb->nh.iph;
struct dst_entry *odst; struct dst_entry *odst;
struct flowi fl = {}; struct flowi fl = {};
struct rtable *rt; struct rtable *rt;
if (local) { if (hook != NF_IP_FORWARD) {
fl.nl_u.ip4_u.daddr = iph->saddr; fl.nl_u.ip4_u.daddr = iph->saddr;
fl.nl_u.ip4_u.saddr = iph->daddr; if (hook == NF_IP_LOCAL_IN)
fl.nl_u.ip4_u.saddr = iph->daddr;
fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
if (ip_route_output_key(&rt, &fl) != 0) if (ip_route_output_key(&rt, &fl) != 0)
...@@ -81,7 +82,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, int local) ...@@ -81,7 +82,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, int local)
} }
/* Send RST reply */ /* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int local) static void send_reset(struct sk_buff *oldskb, int hook)
{ {
struct sk_buff *nskb; struct sk_buff *nskb;
struct tcphdr otcph, *tcph; struct tcphdr otcph, *tcph;
...@@ -104,7 +105,7 @@ static void send_reset(struct sk_buff *oldskb, int local) ...@@ -104,7 +105,7 @@ static void send_reset(struct sk_buff *oldskb, int local)
return; return;
/* FIXME: Check checksum --RR */ /* FIXME: Check checksum --RR */
if ((rt = route_reverse(oldskb, local)) == NULL) if ((rt = route_reverse(oldskb, hook)) == NULL)
return; return;
hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
...@@ -390,7 +391,7 @@ static unsigned int reject(struct sk_buff **pskb, ...@@ -390,7 +391,7 @@ static unsigned int reject(struct sk_buff **pskb,
send_unreach(*pskb, ICMP_PKT_FILTERED); send_unreach(*pskb, ICMP_PKT_FILTERED);
break; break;
case IPT_TCP_RESET: case IPT_TCP_RESET:
send_reset(*pskb, hooknum == NF_IP_LOCAL_IN); send_reset(*pskb, hooknum);
case IPT_ICMP_ECHOREPLY: case IPT_ICMP_ECHOREPLY:
/* Doesn't happen. */ /* Doesn't happen. */
break; break;
......
...@@ -126,18 +126,11 @@ ipv6header_checkentry(const char *tablename, ...@@ -126,18 +126,11 @@ ipv6header_checkentry(const char *tablename,
return 1; return 1;
} }
static void
ipv6header_destroy(void *matchinfo,
unsigned int matchinfosize)
{
return;
}
static struct ip6t_match ip6t_ipv6header_match = { static struct ip6t_match ip6t_ipv6header_match = {
.name = "ipv6header", .name = "ipv6header",
.match = &ipv6header_match, .match = &ipv6header_match,
.checkentry = &ipv6header_checkentry, .checkentry = &ipv6header_checkentry,
.destroy = &ipv6header_destroy, .destroy = NULL,
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
......
...@@ -141,9 +141,9 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, ...@@ -141,9 +141,9 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
* socket values. * socket values.
*/ */
asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt; asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt;
asoc->rto_initial = sp->rtoinfo.srto_initial * HZ / 1000; asoc->rto_initial = MSECS_TO_JIFFIES(sp->rtoinfo.srto_initial);
asoc->rto_max = sp->rtoinfo.srto_max * HZ / 1000; asoc->rto_max = MSECS_TO_JIFFIES(sp->rtoinfo.srto_max);
asoc->rto_min = sp->rtoinfo.srto_min * HZ / 1000; asoc->rto_min = MSECS_TO_JIFFIES(sp->rtoinfo.srto_min);
asoc->overall_error_count = 0; asoc->overall_error_count = 0;
...@@ -168,7 +168,8 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, ...@@ -168,7 +168,8 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams;
asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; asoc->max_init_attempts = sp->initmsg.sinit_max_attempts;
asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ / 1000; asoc->max_init_timeo =
MSECS_TO_JIFFIES(sp->initmsg.sinit_max_init_timeo);
/* Allocate storage for the ssnmap after the inbound and outbound /* Allocate storage for the ssnmap after the inbound and outbound
* streams have been negotiated during Init. * streams have been negotiated during Init.
...@@ -246,6 +247,11 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, ...@@ -246,6 +247,11 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
*/ */
asoc->peer.sack_needed = 1; asoc->peer.sack_needed = 1;
/* Assume that the peer recongizes ASCONF until reported otherwise
* via an ERROR chunk.
*/
asoc->peer.asconf_capable = 1;
/* Create an input queue. */ /* Create an input queue. */
sctp_inq_init(&asoc->base.inqueue); sctp_inq_init(&asoc->base.inqueue);
sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_inq_set_th_handler(&asoc->base.inqueue,
...@@ -495,7 +501,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -495,7 +501,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* Initialize the peer's heartbeat interval based on the /* Initialize the peer's heartbeat interval based on the
* sock configured value. * sock configured value.
*/ */
peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; peer->hb_interval = MSECS_TO_JIFFIES(sp->paddrparam.spp_hbinterval);
/* Set the path max_retrans. */ /* Set the path max_retrans. */
peer->max_retrans = asoc->max_retrans; peer->max_retrans = asoc->max_retrans;
......
...@@ -324,6 +324,43 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp, ...@@ -324,6 +324,43 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
return 0; return 0;
} }
/* Find the first address in the bind address list that is not present in
* the addrs packed array.
*/
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
const union sctp_addr *addrs,
int addrcnt,
struct sctp_opt *opt)
{
struct sctp_sockaddr_entry *laddr;
union sctp_addr *addr;
void *addr_buf;
struct sctp_af *af;
struct list_head *pos;
int i;
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
addr_buf = (union sctp_addr *)addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(addr->v4.sin_family);
if (!af)
return NULL;
if (opt->pf->cmp_addr(&laddr->a, addr, opt))
break;
addr_buf += af->sockaddr_len;
}
if (i == addrcnt)
return &laddr->a;
}
return NULL;
}
/* Copy out addresses from the global local address list. */ /* Copy out addresses from the global local address list. */
static int sctp_copy_one_addr(struct sctp_bind_addr *dest, static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
union sctp_addr *addr, union sctp_addr *addr,
......
...@@ -129,7 +129,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ...@@ -129,7 +129,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
SCTP_DEFAULT_TIMEOUT_T1_INIT; SCTP_DEFAULT_TIMEOUT_T1_INIT;
ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
sp->rtoinfo.srto_initial * HZ / 1000; MSECS_TO_JIFFIES(sp->rtoinfo.srto_initial);
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0;
...@@ -138,7 +138,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ...@@ -138,7 +138,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
* recommended value of 5 times 'RTO.Max'. * recommended value of 5 times 'RTO.Max'.
*/ */
ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
= 5 * (sp->rtoinfo.srto_max * HZ / 1000); = 5 * MSECS_TO_JIFFIES(sp->rtoinfo.srto_max);
ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
SCTP_DEFAULT_TIMEOUT_HEARTBEAT; SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (C) IBM Corp. 2001, 2003 * (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 Intel Corp. * Copyright (c) 2001-2002 Intel Corp.
...@@ -1288,7 +1288,7 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, ...@@ -1288,7 +1288,7 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
/* Set an expiration time for the cookie. */ /* Set an expiration time for the cookie. */
do_gettimeofday(&cookie->c.expiration); do_gettimeofday(&cookie->c.expiration);
tv_add(&asoc->cookie_life, &cookie->c.expiration); TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration);
/* Copy the peer's init packet. */ /* Copy the peer's init packet. */
memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr,
...@@ -2021,11 +2021,11 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, ...@@ -2021,11 +2021,11 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
sctp_addiphdr_t asconf; sctp_addiphdr_t asconf;
struct sctp_chunk *retval; struct sctp_chunk *retval;
int length = sizeof(asconf) + vparam_len; int length = sizeof(asconf) + vparam_len;
union sctp_params addrparam; union sctp_addr_param addrparam;
int addrlen; int addrlen;
struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family); struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
addrlen = af->to_addr_param(addr, (union sctp_addr_param *)&addrparam); addrlen = af->to_addr_param(addr, &addrparam);
if (!addrlen) if (!addrlen)
return NULL; return NULL;
length += addrlen; length += addrlen;
...@@ -2045,6 +2045,83 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, ...@@ -2045,6 +2045,83 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
return retval; return retval;
} }
/* ADDIP
* 3.2.1 Add IP Address
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type = 0xC001 | Length = Variable |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ASCONF-Request Correlation ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Address Parameter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 3.2.2 Delete IP Address
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type = 0xC002 | Length = Variable |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ASCONF-Request Correlation ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Address Parameter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
union sctp_addr *laddr,
struct sockaddr *addrs,
int addrcnt,
int flags)
{
sctp_addip_param_t param;
struct sctp_chunk *retval;
union sctp_addr_param addr_param;
union sctp_addr *addr;
void *addr_buf;
struct sctp_af *af;
int paramlen = sizeof(param);
int addr_param_len = 0;
int totallen = 0;
int i;
/* Get total length of all the address parameters. */
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(addr->v4.sin_family);
addr_param_len = af->to_addr_param(addr, &addr_param);
totallen += paramlen;
totallen += addr_param_len;
addr_buf += af->sockaddr_len;
}
/* Create an asconf chunk with the required length. */
retval = sctp_make_asconf(asoc, laddr, totallen);
if (!retval)
return NULL;
/* Add the address parameters to the asconf chunk. */
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(addr->v4.sin_family);
addr_param_len = af->to_addr_param(addr, &addr_param);
param.param_hdr.type = flags;
param.param_hdr.length = htons(paramlen + addr_param_len);
param.crr_id = htonl(i);
sctp_addto_chunk(retval, paramlen, &param);
sctp_addto_chunk(retval, addr_param_len, &addr_param);
addr_buf += af->sockaddr_len;
}
return retval;
}
/* ADDIP /* ADDIP
* 3.2.4 Set Primary IP Address * 3.2.4 Set Primary IP Address
* 0 1 2 3 * 0 1 2 3
...@@ -2065,11 +2142,11 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, ...@@ -2065,11 +2142,11 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
sctp_addip_param_t param; sctp_addip_param_t param;
struct sctp_chunk *retval; struct sctp_chunk *retval;
int len = sizeof(param); int len = sizeof(param);
union sctp_params addrparam; union sctp_addr_param addrparam;
int addrlen; int addrlen;
struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family); struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
addrlen = af->to_addr_param(addr, (union sctp_addr_param *)&addrparam); addrlen = af->to_addr_param(addr, &addrparam);
if (!addrlen) if (!addrlen)
return NULL; return NULL;
len += addrlen; len += addrlen;
...@@ -2089,11 +2166,7 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, ...@@ -2089,11 +2166,7 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
return retval; return retval;
} }
/* /* ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK)
* Unpack the parameters in an ASCONF chunk into an association and
* generate ASCONF-ACK chunk.
*
* ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK)
* 0 1 2 3 * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...@@ -2110,8 +2183,28 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, ...@@ -2110,8 +2183,28 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
* | ASCONF Parameter Response#N | * | ASCONF Parameter Response#N |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* *
* All the parameter respoinces will be added in this function. * Create an ASCONF_ACK chunk with enough space for the parameter responses.
*/ */
struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc,
int serial, int vparam_len)
{
sctp_addiphdr_t asconf;
struct sctp_chunk *retval;
int length = sizeof(asconf) + vparam_len;
/* Create the chunk. */
retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF_ACK, 0, length);
if (!retval)
return NULL;
asconf.serial = serial;
retval->subh.addip_hdr =
sctp_addto_chunk(retval, sizeof(asconf), &asconf);
return retval;
}
struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf, struct sctp_chunk *asconf,
int vparam_len) int vparam_len)
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999 Cisco, Inc. * Copyright (c) 1999 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -690,6 +690,44 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds, ...@@ -690,6 +690,44 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,
chunk->transport = t; chunk->transport = t;
} }
/* Process an incoming Operation Error Chunk. */
static void sctp_cmd_process_operr(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc,
struct sctp_chunk *chunk)
{
struct sctp_operr_chunk *operr_chunk;
struct sctp_errhdr *err_hdr;
operr_chunk = (struct sctp_operr_chunk *)chunk->chunk_hdr;
err_hdr = &operr_chunk->err_hdr;
switch (err_hdr->cause) {
case SCTP_ERROR_UNKNOWN_CHUNK:
{
struct sctp_chunkhdr *unk_chunk_hdr;
unk_chunk_hdr = (struct sctp_chunkhdr *)err_hdr->variable;
switch (unk_chunk_hdr->type) {
/* ADDIP 4.1 A9) If the peer responds to an ASCONF with an
* ERROR chunk reporting that it did not recognized the ASCONF
* chunk type, the sender of the ASCONF MUST NOT send any
* further ASCONF chunks and MUST stop its T-4 timer.
*/
case SCTP_CID_ASCONF:
asoc->peer.asconf_capable = 0;
sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
break;
default:
break;
}
break;
}
default:
break;
}
}
/* These three macros allow us to pull the debugging code out of the /* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real * main flow of sctp_do_sm() to keep attention focused on the real
* functionality there. * functionality there.
...@@ -1205,6 +1243,9 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -1205,6 +1243,9 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_cmd_setup_t4(commands, asoc, cmd->obj.ptr); sctp_cmd_setup_t4(commands, asoc, cmd->obj.ptr);
break; break;
case SCTP_CMD_PROCESS_OPERR:
sctp_cmd_process_operr(commands, asoc, chunk);
break;
default: default:
printk(KERN_WARNING "Impossible command: %u, %p\n", printk(KERN_WARNING "Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr); cmd->verb, cmd->obj.ptr);
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001-2002 Intel Corp. * Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2002 Nokia Corp. * Copyright (c) 2002 Nokia Corp.
* *
...@@ -2864,6 +2864,9 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, ...@@ -2864,6 +2864,9 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
sctp_ulpevent_free(ev); sctp_ulpevent_free(ev);
goto nomem; goto nomem;
} }
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
SCTP_CHUNK(chunk));
} }
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
......
...@@ -97,6 +97,8 @@ static void sctp_wait_for_close(struct sock *sk, long timeo); ...@@ -97,6 +97,8 @@ static void sctp_wait_for_close(struct sock *sk, long timeo);
static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
static int sctp_bindx_add(struct sock *, struct sockaddr *, int); static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int);
static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int);
static int sctp_do_bind(struct sock *, union sctp_addr *, int); static int sctp_do_bind(struct sock *, union sctp_addr *, int);
static int sctp_autobind(struct sock *sk); static int sctp_autobind(struct sock *sk);
static void sctp_sock_migrate(struct sock *, struct sock *, static void sctp_sock_migrate(struct sock *, struct sock *,
...@@ -349,6 +351,106 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) ...@@ -349,6 +351,106 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt)
return retval; return retval;
} }
/* Send an ASCONF chunk with Add IP address parameters to all the peers of the
* associations that are part of the endpoint indicating that a list of local
* addresses are added to the endpoint.
*
* If any of the addresses is already in the bind address list of the
* association, we do not send the chunk for that association. But it will not
* affect other associations.
*
* Only sctp_setsockopt_bindx() is supposed to call this function.
*/
static int sctp_send_asconf_add_ip(struct sock *sk,
struct sockaddr *addrs,
int addrcnt)
{
struct sctp_opt *sp;
struct sctp_endpoint *ep;
struct sctp_association *asoc;
struct sctp_bind_addr *bp;
struct sctp_chunk *chunk;
struct sctp_sockaddr_entry *laddr;
union sctp_addr *addr;
void *addr_buf;
struct sctp_af *af;
struct list_head *pos;
struct list_head *p;
int i;
int retval = 0;
sp = sctp_sk(sk);
ep = sp->ep;
SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
__FUNCTION__, sk, addrs, addrcnt);
list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs);
if (!sctp_state(asoc, ESTABLISHED))
continue;
if (!asoc->peer.asconf_capable)
continue;
/* Check if any address in the packed array of addresses is
* in the bind address list of the association. If so,
* do not send the asconf chunk to its peer, but continue with
* other associations.
*/
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(addr->v4.sin_family);
if (!af) {
retval = -EINVAL;
goto out;
}
if (sctp_assoc_lookup_laddr(asoc, addr))
break;
addr_buf += af->sockaddr_len;
}
if (i < addrcnt)
continue;
/* Use the first address in bind addr list of association as
* Address Parameter of ASCONF CHUNK.
*/
sctp_read_lock(&asoc->base.addr_lock);
bp = &asoc->base.bind_addr;
p = bp->address_list.next;
laddr = list_entry(p, struct sctp_sockaddr_entry, list);
sctp_read_unlock(&asoc->base.addr_lock);
chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
addrcnt, SCTP_PARAM_ADD_IP);
if (!chunk) {
retval = -ENOMEM;
goto out;
}
retval = sctp_primitive_ASCONF(asoc, chunk);
if (retval) {
sctp_chunk_free(chunk);
goto out;
}
/* FIXME: After sending the add address ASCONF chunk, we
* cannot append the address to the association's binding
* address list, because the new address may be used as the
* source of a message sent to the peer before the ASCONF
* chunk is received by the peer. So we should wait until
* ASCONF_ACK is received.
*/
}
out:
return retval;
}
/* Remove a list of addresses from bind addresses list. Do not remove the /* Remove a list of addresses from bind addresses list. Do not remove the
* last address. * last address.
* *
...@@ -436,6 +538,106 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) ...@@ -436,6 +538,106 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
return retval; return retval;
} }
/* Send an ASCONF chunk with Delete IP address parameters to all the peers of
* the associations that are part of the endpoint indicating that a list of
* local addresses are removed from the endpoint.
*
* If any of the addresses is already in the bind address list of the
* association, we do not send the chunk for that association. But it will not
* affect other associations.
*
* Only sctp_setsockopt_bindx() is supposed to call this function.
*/
static int sctp_send_asconf_del_ip(struct sock *sk,
struct sockaddr *addrs,
int addrcnt)
{
struct sctp_opt *sp;
struct sctp_endpoint *ep;
struct sctp_association *asoc;
struct sctp_bind_addr *bp;
struct sctp_chunk *chunk;
union sctp_addr *laddr;
void *addr_buf;
struct sctp_af *af;
struct list_head *pos;
int i;
int retval = 0;
sp = sctp_sk(sk);
ep = sp->ep;
SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
__FUNCTION__, sk, addrs, addrcnt);
list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs);
if (!sctp_state(asoc, ESTABLISHED))
continue;
if (!asoc->peer.asconf_capable)
continue;
/* Check if any address in the packed array of addresses is
* not present in the bind address list of the association.
* If so, do not send the asconf chunk to its peer, but
* continue with other associations.
*/
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
laddr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(laddr->v4.sin_family);
if (!af) {
retval = -EINVAL;
goto out;
}
if (!sctp_assoc_lookup_laddr(asoc, laddr))
break;
addr_buf += af->sockaddr_len;
}
if (i < addrcnt)
continue;
/* Find one address in the association's bind address list
* that is not in the packed array of addresses. This is to
* make sure that we do not delete all the addresses in the
* association.
*/
sctp_read_lock(&asoc->base.addr_lock);
bp = &asoc->base.bind_addr;
laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
addrcnt, sp);
sctp_read_unlock(&asoc->base.addr_lock);
if (!laddr)
continue;
chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt,
SCTP_PARAM_DEL_IP);
if (!chunk) {
retval = -ENOMEM;
goto out;
}
retval = sctp_primitive_ASCONF(asoc, chunk);
if (retval) {
sctp_chunk_free(chunk);
goto out;
}
/* FIXME: After sending the delete address ASCONF chunk, we
* cannot remove the addresses from the association's bind
* address list, because there maybe some packet send to
* the delete addresses, so we should wait until ASCONF_ACK
* packet is received.
*/
}
out:
return retval;
}
/* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
* *
* API 8.1 * API 8.1
...@@ -564,10 +766,16 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs, ...@@ -564,10 +766,16 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs,
switch (op) { switch (op) {
case SCTP_BINDX_ADD_ADDR: case SCTP_BINDX_ADD_ADDR:
err = sctp_bindx_add(sk, kaddrs, addrcnt); err = sctp_bindx_add(sk, kaddrs, addrcnt);
if (err)
goto out;
err = sctp_send_asconf_add_ip(sk, kaddrs, addrcnt);
break; break;
case SCTP_BINDX_REM_ADDR: case SCTP_BINDX_REM_ADDR:
err = sctp_bindx_rem(sk, kaddrs, addrcnt); err = sctp_bindx_rem(sk, kaddrs, addrcnt);
if (err)
goto out;
err = sctp_send_asconf_del_ip(sk, kaddrs, addrcnt);
break; break;
default: default:
...@@ -575,6 +783,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs, ...@@ -575,6 +783,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs,
break; break;
}; };
out:
kfree(kaddrs); kfree(kaddrs);
return err; return err;
...@@ -962,8 +1171,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -962,8 +1171,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
= sinit->sinit_max_attempts; = sinit->sinit_max_attempts;
} }
if (sinit->sinit_max_init_timeo) { if (sinit->sinit_max_init_timeo) {
asoc->max_init_timeo asoc->max_init_timeo =
= sinit->sinit_max_init_timeo * HZ; MSECS_TO_JIFFIES(sinit->sinit_max_init_timeo);
} }
} }
...@@ -1401,7 +1610,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -1401,7 +1610,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
*/ */
if (params.spp_hbinterval) { if (params.spp_hbinterval) {
trans->hb_allowed = 1; trans->hb_allowed = 1;
trans->hb_interval = params.spp_hbinterval * HZ / 1000; trans->hb_interval =
MSECS_TO_JIFFIES(params.spp_hbinterval);
} else } else
trans->hb_allowed = 0; trans->hb_allowed = 0;
} }
...@@ -1560,11 +1770,12 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) { ...@@ -1560,11 +1770,12 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) {
if (asoc) { if (asoc) {
if (rtoinfo.srto_initial != 0) if (rtoinfo.srto_initial != 0)
asoc->rto_initial = rtoinfo.srto_initial * HZ / 1000; asoc->rto_initial =
MSECS_TO_JIFFIES(rtoinfo.srto_initial);
if (rtoinfo.srto_max != 0) if (rtoinfo.srto_max != 0)
asoc->rto_max = rtoinfo.srto_max * HZ / 1000; asoc->rto_max = MSECS_TO_JIFFIES(rtoinfo.srto_max);
if (rtoinfo.srto_min != 0) if (rtoinfo.srto_min != 0)
asoc->rto_min = rtoinfo.srto_min * HZ / 1000; asoc->rto_min = MSECS_TO_JIFFIES(rtoinfo.srto_min);
} else { } else {
/* If there is no association or the association-id = 0 /* If there is no association or the association-id = 0
* set the values to the endpoint. * set the values to the endpoint.
...@@ -2088,14 +2299,14 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2088,14 +2299,14 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; sp->initmsg.sinit_num_ostreams = sctp_max_outstreams;
sp->initmsg.sinit_max_instreams = sctp_max_instreams; sp->initmsg.sinit_max_instreams = sctp_max_instreams;
sp->initmsg.sinit_max_attempts = sctp_max_retrans_init; sp->initmsg.sinit_max_attempts = sctp_max_retrans_init;
sp->initmsg.sinit_max_init_timeo = (sctp_rto_max / HZ) * 1000; sp->initmsg.sinit_max_init_timeo = JIFFIES_TO_MSECS(sctp_rto_max);
/* Initialize default RTO related parameters. These parameters can /* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option. * be modified for with the SCTP_RTOINFO socket option.
*/ */
sp->rtoinfo.srto_initial = (sctp_rto_initial / HZ) * 1000; sp->rtoinfo.srto_initial = JIFFIES_TO_MSECS(sctp_rto_initial);
sp->rtoinfo.srto_max = (sctp_rto_max / HZ) * 1000; sp->rtoinfo.srto_max = JIFFIES_TO_MSECS(sctp_rto_max);
sp->rtoinfo.srto_min = (sctp_rto_min / HZ) * 1000; sp->rtoinfo.srto_min = JIFFIES_TO_MSECS(sctp_rto_min);
/* Initialize default association related parameters. These parameters /* Initialize default association related parameters. These parameters
* can be modified with the SCTP_ASSOCINFO socket option. * can be modified with the SCTP_ASSOCINFO socket option.
...@@ -2104,8 +2315,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2104,8 +2315,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->assocparams.sasoc_number_peer_destinations = 0; sp->assocparams.sasoc_number_peer_destinations = 0;
sp->assocparams.sasoc_peer_rwnd = 0; sp->assocparams.sasoc_peer_rwnd = 0;
sp->assocparams.sasoc_local_rwnd = 0; sp->assocparams.sasoc_local_rwnd = 0;
sp->assocparams.sasoc_cookie_life = (sctp_valid_cookie_life / HZ) sp->assocparams.sasoc_cookie_life =
* 1000; JIFFIES_TO_MSECS(sctp_valid_cookie_life);
/* Initialize default event subscriptions. By default, all the /* Initialize default event subscriptions. By default, all the
* options are off. * options are off.
...@@ -2115,7 +2326,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2115,7 +2326,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Default Peer Address Parameters. These defaults can /* Default Peer Address Parameters. These defaults can
* be modified via SCTP_PEER_ADDR_PARAMS * be modified via SCTP_PEER_ADDR_PARAMS
*/ */
sp->paddrparam.spp_hbinterval = (sctp_hb_interval / HZ) * 1000; sp->paddrparam.spp_hbinterval = JIFFIES_TO_MSECS(sctp_hb_interval);
sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path; sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path;
/* If enabled no SCTP message fragmentation will be performed. /* If enabled no SCTP message fragmentation will be performed.
...@@ -2265,7 +2476,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -2265,7 +2476,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_state = transport->active;
status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_cwnd = transport->cwnd;
status.sstat_primary.spinfo_srtt = transport->srtt; status.sstat_primary.spinfo_srtt = transport->srtt;
status.sstat_primary.spinfo_rto = (transport->rto / HZ) * 1000; status.sstat_primary.spinfo_rto = JIFFIES_TO_MSECS(transport->rto);
status.sstat_primary.spinfo_mtu = transport->pmtu; status.sstat_primary.spinfo_mtu = transport->pmtu;
if (put_user(len, optlen)) { if (put_user(len, optlen)) {
...@@ -2320,7 +2531,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, ...@@ -2320,7 +2531,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
pinfo.spinfo_state = transport->active; pinfo.spinfo_state = transport->active;
pinfo.spinfo_cwnd = transport->cwnd; pinfo.spinfo_cwnd = transport->cwnd;
pinfo.spinfo_srtt = transport->srtt; pinfo.spinfo_srtt = transport->srtt;
pinfo.spinfo_rto = (transport->rto / HZ) * 1000; pinfo.spinfo_rto = JIFFIES_TO_MSECS(transport->rto);
pinfo.spinfo_mtu = transport->pmtu; pinfo.spinfo_mtu = transport->pmtu;
if (put_user(len, optlen)) { if (put_user(len, optlen)) {
...@@ -2524,7 +2735,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, ...@@ -2524,7 +2735,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
if (!trans->hb_allowed) if (!trans->hb_allowed)
params.spp_hbinterval = 0; params.spp_hbinterval = 0;
else else
params.spp_hbinterval = trans->hb_interval * 1000 / HZ; params.spp_hbinterval = JIFFIES_TO_MSECS(trans->hb_interval);
/* spp_pathmaxrxt contains the maximum number of retransmissions /* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable. * before this address shall be considered unreachable.
...@@ -2582,10 +2793,8 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, ...@@ -2582,10 +2793,8 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
list_for_each(pos, &asoc->peer.transport_addr_list) { list_for_each(pos, &asoc->peer.transport_addr_list) {
cnt ++; cnt ++;
} }
if (copy_to_user(optval, &cnt, sizeof(int)))
return -EFAULT;
return 0; return cnt;
} }
static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
...@@ -2666,10 +2875,8 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, ...@@ -2666,10 +2875,8 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
cnt ++; cnt ++;
} }
if (copy_to_user(optval, &cnt, sizeof(int)))
return -EFAULT;
return 0; return cnt;
} }
static int sctp_getsockopt_local_addrs(struct sock *sk, int len, static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
...@@ -2879,9 +3086,9 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval, ...@@ -2879,9 +3086,9 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval,
/* Values corresponding to the specific association. */ /* Values corresponding to the specific association. */
if (asoc) { if (asoc) {
rtoinfo.srto_initial = (asoc->rto_initial / HZ) * 1000; rtoinfo.srto_initial = JIFFIES_TO_MSECS(asoc->rto_initial);
rtoinfo.srto_max = (asoc->rto_max / HZ) * 1000; rtoinfo.srto_max = JIFFIES_TO_MSECS(asoc->rto_max);
rtoinfo.srto_min = (asoc->rto_min / HZ) * 1000; rtoinfo.srto_min = JIFFIES_TO_MSECS(asoc->rto_min);
} else { } else {
/* Values corresponding to the endpoint. */ /* Values corresponding to the endpoint. */
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#include <linux/sysctl.h> #include <linux/sysctl.h>
static ctl_handler sctp_sysctl_jiffies_ms; static ctl_handler sctp_sysctl_jiffies_ms;
static long rto_timer_min = 0; static long rto_timer_min = 1;
static long rto_timer_max = 86400000; /* One day */ static long rto_timer_max = 86400000; /* One day */
static ctl_table sctp_table[] = { static ctl_table sctp_table[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment